github.com/m3db/m3@v1.5.0/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  }