diff --git a/internal/sponsors/handler.go b/internal/sponsors/handler.go index 034438c..82a184b 100644 --- a/internal/sponsors/handler.go +++ b/internal/sponsors/handler.go @@ -1,6 +1,7 @@ package sponsors import ( + "errors" "fmt" ) @@ -57,6 +58,10 @@ func (h *Handler) Load(dataSource string) error { // TODO: configure the dynamic header mapper for _, entry := range processedData { + if len(entry["Organisation Name"]) <= 0 || len(entry["Route"]) <= 0 { + return errors.New("incompatible data, expecting headers `Organisation Name` and `Route`") + } + h.Organisations.AddOrUpdateVisaType(entry["Organisation Name"], entry["Route"]) } } diff --git a/internal/sponsors/handler_test.go b/internal/sponsors/handler_test.go index fc16f0d..e567641 100644 --- a/internal/sponsors/handler_test.go +++ b/internal/sponsors/handler_test.go @@ -121,3 +121,161 @@ func TestNewHandler(t *testing.T) { }) } } + +func TestHandler_Load(t *testing.T) { + tests := []struct { + name string + datasource string + fetcherSetup func(client *mocks.Fetcher) + processorSetup func(client *mocks.Processor) + wantEmptyOrgs bool + wantErr bool + }{ + { + name: "Successfully load data using default datasource", + datasource: "", + fetcherSetup: func(client *mocks.Fetcher) { + client.On("FetchDataSource").Once().Return( + "datasource", + nil, + ) + client.On("FetchData", mock.Anything).Once().Return( + []byte(`"Organisation Name", "Town/City", "County", "Type & Rating", "Route" +"Awesome company", "London", "United Kingdom", "Worker (A rating)", "Skilled Worker" +`), + nil, + ) + }, + processorSetup: func(client *mocks.Processor) { + client.On("ProcessRawData", mock.Anything).Once().Return( + []map[string]string{ + { + "Organisation Name": "Awesome company", + "Route": "Skilled Worker", + }, + }, + nil, + ) + }, + wantErr: false, + }, + { + name: "Successfully load data using custom datasource", + datasource: "custom_datasource", + fetcherSetup: func(client *mocks.Fetcher) { + client.On("FetchData", mock.Anything).Once().Return( + []byte(`"Organisation Name", "Town/City", "County", "Type & Rating", "Route" +"Awesome company", "London", "United Kingdom", "Worker (A rating)", "Skilled Worker" +`), + nil, + ) + }, + processorSetup: func(client *mocks.Processor) { + client.On("ProcessRawData", mock.Anything).Once().Return( + []map[string]string{ + { + "Organisation Name": "Awesome company", + "Route": "Skilled Worker", + }, + }, + nil, + ) + }, + wantErr: false, + }, + { + name: "Successfully load data using custom datasource, but it's empty", + datasource: "custom_datasource", + fetcherSetup: func(client *mocks.Fetcher) { + client.On("FetchData", mock.Anything).Once().Return( + []byte(``), + nil, + ) + }, + processorSetup: func(client *mocks.Processor) { + client.On("ProcessRawData", mock.Anything).Once().Return( + []map[string]string{}, + nil, + ) + }, + wantEmptyOrgs: true, + wantErr: false, + }, + { + name: "Failed to load due to failure to fetch datasource", + fetcherSetup: func(client *mocks.Fetcher) { + client.On("FetchDataSource").Once().Return( + "", + errors.New("failed to fetch datasource"), + ) + }, + wantErr: true, + }, + { + name: "Failed to load due to failure to fetch data from datasource", + datasource: "custom_datasource", + fetcherSetup: func(client *mocks.Fetcher) { + client.On("FetchData", mock.Anything).Once().Return( + []byte(""), + errors.New("failed to fetch datasource"), + ) + }, + wantErr: true, + }, + { + name: "Failed to process data due to incompatibility", + datasource: "custom_datasource", + fetcherSetup: func(client *mocks.Fetcher) { + client.On("FetchData", mock.Anything).Once().Return( + []byte(""), + nil, + ) + }, + processorSetup: func(client *mocks.Processor) { + client.On("ProcessRawData", mock.Anything).Once().Return( + []map[string]string{ + { + "OrganisationName": "Awesome company", + "Route": "Skilled Worker", + }, + }, + nil, + ) + }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fetcherMock := &mocks.Fetcher{} + if tt.fetcherSetup != nil { + tt.fetcherSetup(fetcherMock) + } + + processorMock := &mocks.Processor{} + if tt.processorSetup != nil { + tt.processorSetup(processorMock) + } + + handler, err := sponsors.NewHandler(fetcherMock, processorMock, false) + require.NoError(t, err) + + err = handler.Load(tt.datasource) + if tt.wantErr { + require.Error(t, err) + require.Empty(t, handler.Organisations.List()) + } else { + require.NoError(t, err) + + if tt.wantEmptyOrgs { + require.Empty(t, handler.Organisations.List()) + } + } + + mock.AssertExpectationsForObjects(t, fetcherMock) + mock.AssertExpectationsForObjects(t, processorMock) + }) + } + +}