diff --git a/pkg/client/factory_test.go b/pkg/client/factory_test.go index 7a53e1d2c..b6dc7d068 100644 --- a/pkg/client/factory_test.go +++ b/pkg/client/factory_test.go @@ -136,7 +136,7 @@ func TestClientWithCustomCtx(t *testing.T) { } func TestStaticClient(t *testing.T) { - factory := OptimizelyFactory{Datafile: []byte(`{"revision": "42"}`)} + factory := OptimizelyFactory{Datafile: []byte(`{"revision": "42", "version": "4"}`)} optlyClient, err := factory.StaticClient() assert.NoError(t, err) diff --git a/pkg/config/datafileprojectconfig/config.go b/pkg/config/datafileprojectconfig/config.go index 189b07814..4a787f5d3 100644 --- a/pkg/config/datafileprojectconfig/config.go +++ b/pkg/config/datafileprojectconfig/config.go @@ -18,6 +18,7 @@ package datafileprojectconfig import ( + "errors" "fmt" "github.com/optimizely/go-sdk/pkg/config/datafileprojectconfig/mappers" @@ -27,6 +28,10 @@ import ( var logger = logging.GetLogger("DatafileProjectConfig") +var datafileVersions = map[string]struct{}{ + "4": {}, +} + // DatafileProjectConfig is a project config backed by a datafile type DatafileProjectConfig struct { accountID string @@ -173,7 +178,13 @@ func (c DatafileProjectConfig) GetGroupByID(groupID string) (entities.Group, err func NewDatafileProjectConfig(jsonDatafile []byte) (*DatafileProjectConfig, error) { datafile, err := Parse(jsonDatafile) if err != nil { - logger.Error("Error parsing datafile.", err) + logger.Error("Error parsing datafile", err) + return nil, err + } + + if _, ok := datafileVersions[datafile.Version]; !ok { + err = errors.New("unsupported datafile version") + logger.Error(fmt.Sprintf("Version %s of datafile not supported", datafile.Version), err) return nil, err } diff --git a/pkg/config/datafileprojectconfig/config_test.go b/pkg/config/datafileprojectconfig/config_test.go index c788e23d0..6b0a5f83e 100644 --- a/pkg/config/datafileprojectconfig/config_test.go +++ b/pkg/config/datafileprojectconfig/config_test.go @@ -28,13 +28,18 @@ import ( func TestNewDatafileProjectConfigNil(t *testing.T) { projectConfig, err := NewDatafileProjectConfig(nil) - assert.NotNil(t, err) + assert.Error(t, err) + assert.Nil(t, projectConfig) + + jsonDatafileStr := `{"accountID": "123", "revision": "1", "projectId": "12345", "version": "2"}` + projectConfig, err = NewDatafileProjectConfig([]byte(jsonDatafileStr)) + assert.Error(t, err) assert.Nil(t, projectConfig) } func TestNewDatafileProjectConfigNotNil(t *testing.T) { dpc := DatafileProjectConfig{accountID: "123", revision: "1", projectID: "12345"} - jsonDatafileStr := `{"accountID": "123", "revision": "1", "projectId": "12345"}` + jsonDatafileStr := `{"accountID": "123", "revision": "1", "projectId": "12345", "version": "4"}` jsonDatafile := []byte(jsonDatafileStr) projectConfig, err := NewDatafileProjectConfig(jsonDatafile) assert.Nil(t, err) diff --git a/pkg/config/polling_manager_test.go b/pkg/config/polling_manager_test.go index 8f5be8014..8f7c2e8b9 100644 --- a/pkg/config/polling_manager_test.go +++ b/pkg/config/polling_manager_test.go @@ -55,7 +55,7 @@ func assertPeriodically(t *testing.T, evaluationMethod func() bool) { func TestNewPollingProjectConfigManagerWithOptions(t *testing.T) { invalidDatafile := []byte(`INVALID`) - mockDatafile := []byte(`{"revision":"42"}`) + mockDatafile := []byte(`{"revision":"42","version": "4"}`) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(invalidDatafile, http.Header{}, http.StatusOK, nil).Times(1) @@ -80,7 +80,7 @@ func TestNewPollingProjectConfigManagerWithOptions(t *testing.T) { func TestNewAsyncPollingProjectConfigManagerWithOptions(t *testing.T) { - mockDatafile := []byte(`{"revision":"42"}`) + mockDatafile := []byte(`{"revision":"42", "version": "4"}`) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile, http.Header{}, http.StatusOK, nil) @@ -102,7 +102,7 @@ func TestNewAsyncPollingProjectConfigManagerWithOptions(t *testing.T) { func TestSyncConfigFetchesDatafileUsingRequester(t *testing.T) { - mockDatafile := []byte(`{"revision":"42"}`) + mockDatafile := []byte(`{"revision":"42","version": "4"}`) projectConfig, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile, http.Header{}, http.StatusOK, nil) @@ -148,8 +148,8 @@ func TestNewAsyncPollingProjectConfigManagerWithNullDatafile(t *testing.T) { func TestNewPollingProjectConfigManagerWithSimilarDatafileRevisions(t *testing.T) { // Test newer datafile should not replace the older one if revisions are the same - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) - mockDatafile2 := []byte(`{"revision":"42","botFiltering":false}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) + mockDatafile2 := []byte(`{"revision":"42","botFiltering":false,"version": "4"}`) projectConfig1, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile1) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile2, http.Header{}, http.StatusOK, nil) @@ -183,8 +183,8 @@ func TestNewPollingProjectConfigManagerWithSimilarDatafileRevisions(t *testing.T func TestNewAsyncPollingProjectConfigManagerWithSimilarDatafileRevisions(t *testing.T) { // Test newer datafile should not replace the older one if revisions are the same - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) - mockDatafile2 := []byte(`{"revision":"42","botFiltering":false}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) + mockDatafile2 := []byte(`{"revision":"42","botFiltering":false,"version": "4"}`) projectConfig1, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile1) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile2, http.Header{}, http.StatusOK, nil) @@ -217,7 +217,7 @@ func TestNewAsyncPollingProjectConfigManagerWithSimilarDatafileRevisions(t *test } func TestNewPollingProjectConfigManagerWithLastModifiedDates(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) projectConfig1, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile1) mockRequester := new(MockRequester) modifiedDate := "Wed, 16 Oct 2019 20:16:45 GMT" @@ -244,7 +244,7 @@ func TestNewPollingProjectConfigManagerWithLastModifiedDates(t *testing.T) { } func TestNewAsyncPollingProjectConfigManagerWithLastModifiedDates(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) mockRequester := new(MockRequester) modifiedDate := "Wed, 16 Oct 2019 20:16:45 GMT" responseHeaders := http.Header{} @@ -270,8 +270,8 @@ func TestNewAsyncPollingProjectConfigManagerWithLastModifiedDates(t *testing.T) func TestNewPollingProjectConfigManagerWithDifferentDatafileRevisions(t *testing.T) { // Test newer datafile should replace the older one if revisions are different - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) - mockDatafile2 := []byte(`{"revision":"43","botFiltering":false}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) + mockDatafile2 := []byte(`{"revision":"43","botFiltering":false,"version": "4"}`) projectConfig1, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile1) projectConfig2, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile2) mockRequester := new(MockRequester) @@ -306,8 +306,8 @@ func TestNewPollingProjectConfigManagerWithDifferentDatafileRevisions(t *testing func TestNewAsyncPollingProjectConfigManagerWithDifferentDatafileRevisions(t *testing.T) { // Test newer datafile should replace the older one if revisions are different - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) - mockDatafile2 := []byte(`{"revision":"43","botFiltering":false}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) + mockDatafile2 := []byte(`{"revision":"43","botFiltering":false,"version": "4"}`) projectConfig1, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile1) projectConfig2, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile2) mockRequester := new(MockRequester) @@ -342,7 +342,7 @@ func TestNewAsyncPollingProjectConfigManagerWithDifferentDatafileRevisions(t *te func TestNewPollingProjectConfigManagerWithErrorHandling(t *testing.T) { mockDatafile1 := []byte("NOT-VALID") - mockDatafile2 := []byte(`{"revision":"43","botFiltering":false}`) + mockDatafile2 := []byte(`{"revision":"43","botFiltering":false,"version": "4"}`) projectConfig1, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile1) projectConfig2, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile2) @@ -375,7 +375,7 @@ func TestNewPollingProjectConfigManagerWithErrorHandling(t *testing.T) { func TestNewAsyncPollingProjectConfigManagerWithErrorHandling(t *testing.T) { mockDatafile1 := []byte("NOT-VALID") - mockDatafile2 := []byte(`{"revision":"43","botFiltering":false}`) + mockDatafile2 := []byte(`{"revision":"43","botFiltering":false,"version": "4"}`) projectConfig1, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile1) projectConfig2, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile2) @@ -408,8 +408,8 @@ func TestNewAsyncPollingProjectConfigManagerWithErrorHandling(t *testing.T) { } func TestNewPollingProjectConfigManagerOnDecision(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) - mockDatafile2 := []byte(`{"revision":"43","botFiltering":false}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) + mockDatafile2 := []byte(`{"revision":"43","botFiltering":false,"version": "4"}`) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile2, http.Header{}, http.StatusOK, nil) @@ -441,7 +441,7 @@ func TestNewPollingProjectConfigManagerOnDecision(t *testing.T) { } func TestNewAsyncPollingProjectConfigManagerOnDecision(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) projectConfig1, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile1) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile1, http.Header{}, http.StatusOK, nil) @@ -469,8 +469,8 @@ func TestNewAsyncPollingProjectConfigManagerOnDecision(t *testing.T) { func TestGetOptimizelyConfigForNewPollingProjectConfigManager(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) - mockDatafile2 := []byte(`{"revision":"43","botFiltering":false}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) + mockDatafile2 := []byte(`{"revision":"43","botFiltering":false,"version": "4"}`) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile2, http.Header{}, http.StatusOK, nil) @@ -493,8 +493,8 @@ func TestGetOptimizelyConfigForNewPollingProjectConfigManager(t *testing.T) { } func TestGetOptimizelyConfigForNewAsyncPollingProjectConfigManager(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`) - mockDatafile2 := []byte(`{"revision":"43","botFiltering":false}`) + mockDatafile1 := []byte(`{"revision":"42","botFiltering":true,"version": "4"}`) + mockDatafile2 := []byte(`{"revision":"43","botFiltering":false,"version": "4"}`) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile2, http.Header{}, http.StatusOK, nil) @@ -516,8 +516,8 @@ func TestGetOptimizelyConfigForNewAsyncPollingProjectConfigManager(t *testing.T) } func TestNewPollingProjectConfigManagerHardcodedDatafile(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42"}`) - mockDatafile2 := []byte(`{"revision":"43"}`) + mockDatafile1 := []byte(`{"revision":"42","version": "4"}`) + mockDatafile2 := []byte(`{"revision":"43","version": "4"}`) sdkKey := "test_sdk_key" mockRequester := new(MockRequester) @@ -533,8 +533,8 @@ func TestNewPollingProjectConfigManagerHardcodedDatafile(t *testing.T) { } func TestNewAsyncPollingProjectConfigManagerHardcodedDatafile(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42"}`) - mockDatafile2 := []byte(`{"revision":"43"}`) + mockDatafile1 := []byte(`{"revision":"42","version": "4"}`) + mockDatafile2 := []byte(`{"revision":"43","version": "4"}`) sdkKey := "test_sdk_key" mockRequester := new(MockRequester) @@ -550,7 +550,7 @@ func TestNewAsyncPollingProjectConfigManagerHardcodedDatafile(t *testing.T) { } func TestNewPollingProjectConfigManagerPullsImmediately(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42"}`) + mockDatafile1 := []byte(`{"revision":"42","version": "4"}`) sdkKey := "test_sdk_key" mockRequester := new(MockRequester) @@ -566,7 +566,7 @@ func TestNewPollingProjectConfigManagerPullsImmediately(t *testing.T) { } func TestNewAsyncPollingProjectConfigManagerDoesNotPullImmediately(t *testing.T) { - mockDatafile1 := []byte(`{"revision":"42"}`) + mockDatafile1 := []byte(`{"revision":"42","version": "4"}`) sdkKey := "test_sdk_key" mockRequester := new(MockRequester) @@ -614,7 +614,7 @@ func TestDatafileTemplate(t *testing.T) { func TestWithRequester(t *testing.T) { sdkKey := "test_sdk_key" - mockDatafile := []byte(`{"revision":"42"}`) + mockDatafile := []byte(`{"revision":"42","version": "4"}`) mockRequester := new(MockRequester) mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile, http.Header{}, http.StatusOK, nil) configManager := NewPollingProjectConfigManager(sdkKey, WithRequester(mockRequester)) diff --git a/pkg/config/static_manager_test.go b/pkg/config/static_manager_test.go index 9df73ca30..03d645378 100644 --- a/pkg/config/static_manager_test.go +++ b/pkg/config/static_manager_test.go @@ -37,9 +37,13 @@ func TestNewStaticProjectConfigManagerFromPayload(t *testing.T) { mockDatafile := []byte(`{"accountId":"42","projectId":"123""}`) configManager, err := NewStaticProjectConfigManagerFromPayload(mockDatafile) - assert.NotNil(t, err) + assert.Error(t, err) - mockDatafile = []byte(`{"accountId":"42","projectId":"123"}`) + mockDatafile = []byte(`{"accountId":"42","projectId":"123",}`) + configManager, err = NewStaticProjectConfigManagerFromPayload(mockDatafile) + assert.Error(t, err) + + mockDatafile = []byte(`{"accountId":"42","projectId":"123","version":"4"}`) configManager, err = NewStaticProjectConfigManagerFromPayload(mockDatafile) assert.Nil(t, err) @@ -51,7 +55,7 @@ func TestNewStaticProjectConfigManagerFromPayload(t *testing.T) { func TestStaticGetOptimizelyConfig(t *testing.T) { - mockDatafile := []byte(`{"accountId":"42","projectId":"123"}`) + mockDatafile := []byte(`{"accountId":"42","projectId":"123","version":"4"}`) configManager, err := NewStaticProjectConfigManagerFromPayload(mockDatafile) assert.Nil(t, err) @@ -65,12 +69,12 @@ func TestStaticGetOptimizelyConfig(t *testing.T) { func TestNewStaticProjectConfigManagerFromURL(t *testing.T) { configManager, err := NewStaticProjectConfigManagerFromURL("no_key_exists") - assert.NotNil(t, err) + assert.Error(t, err) assert.Nil(t, configManager) } func TestNewStaticProjectConfigManagerOnDecision(t *testing.T) { - mockDatafile := []byte(`{"accountId":"42","projectId":"123"}`) + mockDatafile := []byte(`{"accountId":"42","projectId":"123","version":"4"}`) configManager, err := NewStaticProjectConfigManagerFromPayload(mockDatafile) assert.Nil(t, err) @@ -79,12 +83,12 @@ func TestNewStaticProjectConfigManagerOnDecision(t *testing.T) { } id, err := configManager.OnProjectConfigUpdate(callback) - assert.NotNil(t, err) + assert.Error(t, err) assert.Equal(t, err, errors.New("method OnProjectConfigUpdate does not have any effect on StaticProjectConfigManager")) assert.Equal(t, id, 0) err = configManager.RemoveOnProjectConfigUpdate(id) - assert.NotNil(t, err) + assert.Error(t, err) assert.Equal(t, err, errors.New("method RemoveOnProjectConfigUpdate does not have any effect on StaticProjectConfigManager")) }