github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/namespace/schema_registry_test.go (about) 1 // Copyright (c) 2019 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package namespace 22 23 import ( 24 "sync" 25 "testing" 26 "time" 27 28 "github.com/m3db/m3/src/x/ident" 29 30 "github.com/golang/mock/gomock" 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 ) 34 35 type mockListener struct { 36 sync.RWMutex 37 value SchemaDescr 38 } 39 40 func (l *mockListener) SetSchemaHistory(value SchemaHistory) { 41 l.Lock() 42 defer l.Unlock() 43 if s, ok := value.GetLatest(); ok { 44 l.value = s 45 } 46 } 47 48 func (l *mockListener) Schema() SchemaDescr { 49 l.RLock() 50 defer l.RUnlock() 51 return l.value 52 } 53 54 func TestSchemaRegistryUpdate(t *testing.T) { 55 ctrl := gomock.NewController(t) 56 defer ctrl.Finish() 57 58 sr := NewSchemaRegistry(true, nil) 59 sh1 := NewMockSchemaHistory(ctrl) 60 nsID1 := ident.StringID("ns1") 61 inputSchema1 := NewMockSchemaDescr(ctrl) 62 inputSchema1.EXPECT().DeployId().Return("version1").AnyTimes() 63 sh1.EXPECT().GetLatest().Return(inputSchema1, true).AnyTimes() 64 sh1.EXPECT().Extends(gomock.Any()).Return(true).AnyTimes() 65 require.NoError(t, sr.SetSchemaHistory(nsID1, sh1)) 66 67 schema1, err := sr.GetLatestSchema(nsID1) 68 require.NoError(t, err) 69 require.NotNil(t, schema1) 70 require.Equal(t, "version1", schema1.DeployId()) 71 72 l := &mockListener{} 73 assert.Nil(t, l.value) 74 75 // Ensure immediately sets the value 76 closer, err := sr.RegisterListener(nsID1, l) 77 require.NoError(t, err) 78 require.Equal(t, "version1", l.Schema().DeployId()) 79 80 // Update and verify 81 sh2 := NewMockSchemaHistory(ctrl) 82 inputSchema2 := NewMockSchemaDescr(ctrl) 83 inputSchema2.EXPECT().DeployId().Return("version2").AnyTimes() 84 sh2.EXPECT().GetLatest().Return(inputSchema2, true).AnyTimes() 85 sh2.EXPECT().Extends(gomock.Any()).Return(true) 86 require.NoError(t, sr.SetSchemaHistory(nsID1, sh2)) 87 88 // Verify listener receives update 89 for func() bool { 90 return l.Schema().DeployId() != "version2" 91 }() { 92 time.Sleep(10 * time.Millisecond) 93 } 94 assert.Equal(t, "version2", l.Schema().DeployId()) 95 96 // close the listener 97 closer.Close() 98 99 // Update and verify 100 sh3 := NewMockSchemaHistory(ctrl) 101 inputSchema3 := NewMockSchemaDescr(ctrl) 102 inputSchema3.EXPECT().DeployId().Return("version3").AnyTimes() 103 sh3.EXPECT().GetLatest().Return(inputSchema3, true).AnyTimes() 104 sh3.EXPECT().Extends(gomock.Any()).Return(true) 105 require.NoError(t, sr.SetSchemaHistory(nsID1, sh3)) 106 107 // Verify closed listener does not receive the update. 108 time.Sleep(10 * time.Millisecond) 109 assert.Equal(t, "version2", l.Schema().DeployId()) 110 111 sr.Close() 112 } 113 114 func TestSchemaRegistryLoad(t *testing.T) { 115 ctrl := gomock.NewController(t) 116 defer ctrl.Finish() 117 118 sr := NewSchemaRegistry(true, nil) 119 nsID := ident.StringID("ns1") 120 require.NoError(t, LoadSchemaRegistryFromFile(sr, nsID, "first", "mainpkg/main.proto", "mainpkg.TestMessage", "testdata")) 121 122 schema1, err := sr.GetLatestSchema(nsID) 123 require.NoError(t, err) 124 require.NotNil(t, schema1) 125 require.Equal(t, "first", schema1.DeployId()) 126 } 127 128 func TestSchemaRegistryProtoDisabled(t *testing.T) { 129 ctrl := gomock.NewController(t) 130 defer ctrl.Finish() 131 132 sr := NewSchemaRegistry(false, nil) 133 nsID := ident.StringID("ns1") 134 135 schema1, err := sr.GetLatestSchema(nsID) 136 require.NoError(t, err) 137 require.Nil(t, schema1) 138 139 require.NoError(t, sr.SetSchemaHistory(nsID, nil)) 140 sl := NewMockSchemaListener(ctrl) 141 closer, err := sr.RegisterListener(nsID, sl) 142 require.NoError(t, err) 143 require.Nil(t, closer) 144 } 145 146 func TestSchemaRegistrySchemaNotSet(t *testing.T) { 147 ctrl := gomock.NewController(t) 148 defer ctrl.Finish() 149 150 sr := NewSchemaRegistry(true, nil) 151 nsID := ident.StringID("ns1") 152 153 sl := &mockListener{} 154 closer, err := sr.RegisterListener(nsID, sl) 155 require.Error(t, err) 156 require.Nil(t, closer) 157 158 sh1 := NewMockSchemaHistory(ctrl) 159 sh1.EXPECT().GetLatest().Return(nil, false) 160 require.Error(t, sr.SetSchemaHistory(nsID, sh1)) 161 162 closer, err = sr.RegisterListener(nsID, sl) 163 require.Error(t, err) 164 require.Nil(t, closer) 165 require.Nil(t, sl.Schema()) 166 167 sh2 := NewMockSchemaHistory(ctrl) 168 inputSchema1 := NewMockSchemaDescr(ctrl) 169 inputSchema1.EXPECT().DeployId().Return("version1") 170 sh2.EXPECT().GetLatest().Return(inputSchema1, true) 171 require.NoError(t, sr.SetSchemaHistory(nsID, sh2)) 172 173 sh2.EXPECT().GetLatest().Return(inputSchema1, true) 174 closer, err = sr.RegisterListener(nsID, sl) 175 require.NoError(t, err) 176 require.NotNil(t, closer) 177 require.NotNil(t, sl.Schema()) 178 require.Equal(t, "version1", sl.Schema().DeployId()) 179 180 sh3 := NewMockSchemaHistory(ctrl) 181 inputSchema2 := NewMockSchemaDescr(ctrl) 182 inputSchema2.EXPECT().DeployId().Return("version2") 183 sh3.EXPECT().GetLatest().Return(inputSchema2, true).Times(2) 184 sh3.EXPECT().Extends(gomock.Any()).Return(true) 185 require.NoError(t, sr.SetSchemaHistory(nsID, sh3)) 186 time.Sleep(10 * time.Millisecond) 187 require.NotNil(t, sl.Schema()) 188 require.Equal(t, "version2", sl.Schema().DeployId()) 189 }