package topic import ( "context" "errors" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "edge-infra.dev/pkg/lib/fog" "edge-infra.dev/pkg/sds/interlock/websocket" ) type testState struct { Name string } type mockEventHandler struct { called int } func (m *mockEventHandler) Send(_ websocket.Event) { m.called++ } func TestUpdateState(t *testing.T) { testCases := map[string]struct { uf UpdateFunc updatedName string handlerCalls int }{ "update": { updatedName: "new-name", handlerCalls: 1, }, "noupdate": { updatedName: "old-name", handlerCalls: 0, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { mockEventHandler := &mockEventHandler{0} testTopic := NewTopic( "test-topic", &testState{ Name: "old-name", }, nil, mockEventHandler, ) err := testTopic.UpdateState(func(obj interface{}) error { state := obj.(*testState) state.Name = tc.updatedName return nil }) require.NoError(t, err) state, ok := testTopic.state.data.(*testState) require.True(t, ok) // test that the event has been sent/not sent assert.Equal(t, tc.handlerCalls, mockEventHandler.called) // test that the state has been updated assert.Equal(t, tc.updatedName, state.Name) }) } } type AllTypes struct { Bool bool String string Int int Slice []AllTypes Map map[string]AllTypes AllTypesP *AllTypes } func TestDeepCopyData(t *testing.T) { innerAllTypes := AllTypes{ Bool: true, String: "string", Int: 1, Slice: make([]AllTypes, 0), Map: make(map[string]AllTypes), AllTypesP: nil, } allTypes := AllTypes{ Bool: false, String: "string", Int: 1, Slice: []AllTypes{innerAllTypes}, Map: map[string]AllTypes{"one": innerAllTypes}, AllTypesP: &innerAllTypes, } allTypesState := &State{ data: allTypes, } got := allTypesState.DeepCopyData() assert.Equal(t, allTypes, got) } type mockFieldError struct { validator.FieldError } func (fe *mockFieldError) Tag() string { return "fe.tag" } func (fe *mockFieldError) Field() string { return "fe.field" } func (fe *mockFieldError) Error() string { return "error" } func TestHandleBindingError(t *testing.T) { myerrors := []validator.FieldError{&mockFieldError{}} validationError := validator.ValidationErrors(myerrors) sliceValidationError := binding.SliceValidationError{} standardError := errors.New("new test error") testCases := map[string]struct { inputError error errorCode int }{ "ValidationError": { validationError, 400, }, "SliceValidationError": { sliceValidationError, 400, }, "NotValidationError": { standardError, 500, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = &http.Request{ Header: make(http.Header), Method: "GET", } log := fog.New() ctx := context.Background() c.Request = c.Request.WithContext(fog.IntoContext(ctx, log)) HandleBindingError(c, tc.inputError) assert.Equal(t, tc.errorCode, w.Code) }) } }