github.com/hamba/avro@v1.8.0/schema_compatibility_test.go (about)

     1  package avro_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/hamba/avro"
     7  	"github.com/stretchr/testify/assert"
     8  )
     9  
    10  func TestNewSchemaCompatibility(t *testing.T) {
    11  	sc := avro.NewSchemaCompatibility()
    12  
    13  	assert.IsType(t, &avro.SchemaCompatibility{}, sc)
    14  }
    15  
    16  func TestSchemaCompatibility_Compatible(t *testing.T) {
    17  	tests := []struct {
    18  		name    string
    19  		reader  string
    20  		writer  string
    21  		wantErr bool
    22  	}{
    23  		{
    24  			name:    "Primitive Matching",
    25  			reader:  `"int"`,
    26  			writer:  `"int"`,
    27  			wantErr: false,
    28  		},
    29  		{
    30  			name:    "Int Promote Long",
    31  			reader:  `"long"`,
    32  			writer:  `"int"`,
    33  			wantErr: false,
    34  		},
    35  		{
    36  			name:    "Int Promote Float",
    37  			reader:  `"float"`,
    38  			writer:  `"int"`,
    39  			wantErr: false,
    40  		},
    41  		{
    42  			name:    "Int Promote Double",
    43  			reader:  `"double"`,
    44  			writer:  `"int"`,
    45  			wantErr: false,
    46  		},
    47  		{
    48  			name:    "Long Promote Float",
    49  			reader:  `"float"`,
    50  			writer:  `"long"`,
    51  			wantErr: false,
    52  		},
    53  		{
    54  			name:    "Long Promote Double",
    55  			reader:  `"double"`,
    56  			writer:  `"long"`,
    57  			wantErr: false,
    58  		},
    59  		{
    60  			name:    "Float Promote Double",
    61  			reader:  `"double"`,
    62  			writer:  `"float"`,
    63  			wantErr: false,
    64  		},
    65  		{
    66  			name:    "String Promote Bytes",
    67  			reader:  `"bytes"`,
    68  			writer:  `"string"`,
    69  			wantErr: false,
    70  		},
    71  		{
    72  			name:    "Bytes Promote String",
    73  			reader:  `"string"`,
    74  			writer:  `"bytes"`,
    75  			wantErr: false,
    76  		},
    77  		{
    78  			name:    "Union Match",
    79  			reader:  `["int", "long", "string"]`,
    80  			writer:  `["string", "int", "long"]`,
    81  			wantErr: false,
    82  		},
    83  		{
    84  			name:    "Union Reader Missing Schema",
    85  			reader:  `["int", "string"]`,
    86  			writer:  `["string", "int", "long"]`,
    87  			wantErr: true,
    88  		},
    89  		{
    90  			name:    "Union Writer Missing Schema",
    91  			reader:  `["int", "long", "string"]`,
    92  			writer:  `["string", "int"]`,
    93  			wantErr: false,
    94  		},
    95  		{
    96  			name:    "Union Writer Not Union",
    97  			reader:  `["int", "long", "string"]`,
    98  			writer:  `"int"`,
    99  			wantErr: false,
   100  		},
   101  		{
   102  			name:    "Union Writer Not Union With Error",
   103  			reader:  `["string"]`,
   104  			writer:  `"int"`,
   105  			wantErr: true,
   106  		},
   107  		{
   108  			name:    "Union Reader Not Union",
   109  			reader:  `"int"`,
   110  			writer:  `["int"]`,
   111  			wantErr: false,
   112  		},
   113  		{
   114  			name:    "Union Reader Not Union With Error",
   115  			reader:  `"int"`,
   116  			writer:  `["string", "int", "long"]`,
   117  			wantErr: true,
   118  		},
   119  		{
   120  			name:    "Array Match",
   121  			reader:  `{"type":"array", "items": "int"}`,
   122  			writer:  `{"type":"array", "items": "int"}`,
   123  			wantErr: false,
   124  		},
   125  		{
   126  			name:    "Array Items Mismatch",
   127  			reader:  `{"type":"array", "items": "int"}`,
   128  			writer:  `{"type":"array", "items": "string"}`,
   129  			wantErr: true,
   130  		},
   131  		{
   132  			name:    "Map Match",
   133  			reader:  `{"type":"map", "values": "int"}`,
   134  			writer:  `{"type":"map", "values": "int"}`,
   135  			wantErr: false,
   136  		},
   137  		{
   138  			name:    "Map Items Mismatch",
   139  			reader:  `{"type":"map", "values": "int"}`,
   140  			writer:  `{"type":"map", "values": "string"}`,
   141  			wantErr: true,
   142  		},
   143  		{
   144  			name:    "Fixed Match",
   145  			reader:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 12}`,
   146  			writer:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 12}`,
   147  			wantErr: false,
   148  		},
   149  		{
   150  			name:    "Fixed Name Mismatch",
   151  			reader:  `{"type":"fixed", "name":"test1", "namespace": "org.hamba.avro", "size": 12}`,
   152  			writer:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 12}`,
   153  			wantErr: true,
   154  		},
   155  		{
   156  			name:    "Fixed Size Mismatch",
   157  			reader:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 13}`,
   158  			writer:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 12}`,
   159  			wantErr: true,
   160  		},
   161  		{
   162  			name:    "Enum Match",
   163  			reader:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST1", "TEST2"]}`,
   164  			writer:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST1", "TEST2"]}`,
   165  			wantErr: false,
   166  		},
   167  		{
   168  			name:    "Enum Name Mismatch",
   169  			reader:  `{"type":"enum", "name":"test1", "namespace": "org.hamba.avro", "symbols":["TEST1", "TEST2"]}`,
   170  			writer:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST1", "TEST2"]}`,
   171  			wantErr: true,
   172  		},
   173  		{
   174  			name:    "Enum Reader Missing Symbol",
   175  			reader:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST1"]}`,
   176  			writer:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST1", "TEST2"]}`,
   177  			wantErr: true,
   178  		},
   179  		{
   180  			name:    "Enum Writer Missing Symbol",
   181  			reader:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST1", "TEST2"]}`,
   182  			writer:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST1"]}`,
   183  			wantErr: false,
   184  		},
   185  		{
   186  			name:    "Record Match",
   187  			reader:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "int"}, {"name": "b", "type": "string"}]}`,
   188  			writer:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "b", "type": "string"}, {"name": "a", "type": "int"}]}`,
   189  			wantErr: false,
   190  		},
   191  		{
   192  			name:    "Record Name Mismatch",
   193  			reader:  `{"type":"record", "name":"test1", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "int", "default": 1}, {"name": "b", "type": "string"}]}`,
   194  			writer:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "b", "type": "string", "default": "b"}, {"name": "a", "type": "int"}]}`,
   195  			wantErr: true,
   196  		},
   197  		{
   198  			name:    "Record Schema Mismatch",
   199  			reader:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "string"}, {"name": "b", "type": "string"}]}`,
   200  			writer:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "b", "type": "string"}, {"name": "a", "type": "int"}]}`,
   201  			wantErr: true,
   202  		},
   203  		{
   204  			name:    "Record Reader Field Missing",
   205  			reader:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "int"}]}`,
   206  			writer:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "b", "type": "string"}, {"name": "a", "type": "int"}]}`,
   207  			wantErr: false,
   208  		},
   209  		{
   210  			name:    "Record Writer Field Missing With Default",
   211  			reader:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "int"}, {"name": "b", "type": "string", "default": "test"}]}`,
   212  			writer:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "int"}]}`,
   213  			wantErr: false,
   214  		},
   215  		{
   216  			name:    "Record Writer Field Missing Without Default",
   217  			reader:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "int"}, {"name": "b", "type": "string"}]}`,
   218  			writer:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "int"}]}`,
   219  			wantErr: true,
   220  		},
   221  		{
   222  			name:    "Ref Dereference",
   223  			reader:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"record", "name":"test1", "namespace": "org.hamba.avro", "fields":[{"name": "b", "type": "int"}]}}, {"name": "b", "type": "test1"}]}`,
   224  			writer:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"record", "name":"test1", "namespace": "org.hamba.avro", "fields":[{"name": "b", "type": "int"}]}}, {"name": "b", "type": "test"}]}`,
   225  			wantErr: true,
   226  		},
   227  		{
   228  			name:    "Breaks Recursion",
   229  			reader:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "test"}]}`,
   230  			writer:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "test"}]}`,
   231  			wantErr: false,
   232  		},
   233  	}
   234  
   235  	for _, tt := range tests {
   236  		t.Run(tt.name, func(t *testing.T) {
   237  			r := avro.MustParse(tt.reader)
   238  			w := avro.MustParse(tt.writer)
   239  			sc := avro.NewSchemaCompatibility()
   240  
   241  			err := sc.Compatible(r, w)
   242  
   243  			if tt.wantErr {
   244  				assert.Error(t, err)
   245  				return
   246  			}
   247  
   248  			assert.NoError(t, err)
   249  		})
   250  	}
   251  }
   252  
   253  func TestSchemaCompatibility_CompatibleUsesCacheWithNoError(t *testing.T) {
   254  	reader := `"int"`
   255  	writer := `"int"`
   256  
   257  	r := avro.MustParse(reader)
   258  	w := avro.MustParse(writer)
   259  	sc := avro.NewSchemaCompatibility()
   260  
   261  	_ = sc.Compatible(r, w)
   262  
   263  	err := sc.Compatible(r, w)
   264  
   265  	assert.NoError(t, err)
   266  }
   267  
   268  func TestSchemaCompatibility_CompatibleUsesCacheWithError(t *testing.T) {
   269  	reader := `"int"`
   270  	writer := `"string"`
   271  
   272  	r := avro.MustParse(reader)
   273  	w := avro.MustParse(writer)
   274  	sc := avro.NewSchemaCompatibility()
   275  
   276  	_ = sc.Compatible(r, w)
   277  
   278  	err := sc.Compatible(r, w)
   279  
   280  	assert.Error(t, err)
   281  }