package http import ( "bytes" "context" "errors" "net/http" "net/http/httptest" "testing" "git.defalsify.org/vise.git/engine" "git.grassecon.net/urdt/ussd/internal/handlers" "git.grassecon.net/urdt/ussd/internal/testutil/mocks/httpmocks" ) // invalidRequestType is a custom type to test invalid request scenarios type invalidRequestType struct{} // errorReader is a helper type that always returns an error when Read is called type errorReader struct{} func (e *errorReader) Read(p []byte) (n int, err error) { return 0, errors.New("read error") } func TestSessionHandler_ServeHTTP(t *testing.T) { tests := []struct { name string sessionID string input []byte parserErr error processErr error outputErr error resetErr error expectedStatus int }{ { name: "Success", sessionID: "123", input: []byte("test input"), expectedStatus: http.StatusOK, }, { name: "Missing Session ID", sessionID: "", parserErr: handlers.ErrSessionMissing, expectedStatus: http.StatusBadRequest, }, { name: "Process Error", sessionID: "123", input: []byte("test input"), processErr: handlers.ErrStorage, expectedStatus: http.StatusInternalServerError, }, { name: "Output Error", sessionID: "123", input: []byte("test input"), outputErr: errors.New("output error"), expectedStatus: http.StatusOK, }, { name: "Reset Error", sessionID: "123", input: []byte("test input"), resetErr: errors.New("reset error"), expectedStatus: http.StatusOK, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockRequestParser := &httpmocks.MockRequestParser{ GetSessionIdFunc: func(any) (string, error) { return tt.sessionID, tt.parserErr }, GetInputFunc: func(any) ([]byte, error) { return tt.input, nil }, } mockRequestHandler := &httpmocks.MockRequestHandler{ ProcessFunc: func(rs handlers.RequestSession) (handlers.RequestSession, error) { return rs, tt.processErr }, OutputFunc: func(rs handlers.RequestSession) (handlers.RequestSession, error) { return rs, tt.outputErr }, ResetFunc: func(rs handlers.RequestSession) (handlers.RequestSession, error) { return rs, tt.resetErr }, GetRequestParserFunc: func() handlers.RequestParser { return mockRequestParser }, GetConfigFunc: func() engine.Config { return engine.Config{} }, } sessionHandler := ToSessionHandler(mockRequestHandler) req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(tt.input)) req.Header.Set("X-Vise-Session", tt.sessionID) rr := httptest.NewRecorder() sessionHandler.ServeHTTP(rr, req) if status := rr.Code; status != tt.expectedStatus { t.Errorf("handler returned wrong status code: got %v want %v", status, tt.expectedStatus) } }) } } func TestSessionHandler_WriteError(t *testing.T) { handler := &SessionHandler{} mockWriter := &httpmocks.MockWriter{} err := errors.New("test error") handler.WriteError(mockWriter, http.StatusBadRequest, err) if mockWriter.WrittenString != "" { t.Errorf("Expected empty body, got %s", mockWriter.WrittenString) } } func TestDefaultRequestParser_GetSessionId(t *testing.T) { tests := []struct { name string request any expectedID string expectedError error }{ { name: "Valid Session ID", request: func() *http.Request { req := httptest.NewRequest(http.MethodPost, "/", nil) req.Header.Set("X-Vise-Session", "123456") return req }(), expectedID: "123456", expectedError: nil, }, { name: "Missing Session ID", request: httptest.NewRequest(http.MethodPost, "/", nil), expectedID: "", expectedError: handlers.ErrSessionMissing, }, { name: "Invalid Request Type", request: invalidRequestType{}, expectedID: "", expectedError: handlers.ErrInvalidRequest, }, } parser := &DefaultRequestParser{} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { id, err := parser.GetSessionId(context.Background(),tt.request) if id != tt.expectedID { t.Errorf("Expected session ID %s, got %s", tt.expectedID, id) } if err != tt.expectedError { t.Errorf("Expected error %v, got %v", tt.expectedError, err) } }) } } func TestDefaultRequestParser_GetInput(t *testing.T) { tests := []struct { name string request any expectedInput []byte expectedError error }{ { name: "Valid Input", request: func() *http.Request { return httptest.NewRequest(http.MethodPost, "/", bytes.NewBufferString("test input")) }(), expectedInput: []byte("test input"), expectedError: nil, }, { name: "Empty Input", request: httptest.NewRequest(http.MethodPost, "/", nil), expectedInput: []byte{}, expectedError: nil, }, { name: "Invalid Request Type", request: invalidRequestType{}, expectedInput: nil, expectedError: handlers.ErrInvalidRequest, }, { name: "Read Error", request: func() *http.Request { return httptest.NewRequest(http.MethodPost, "/", &errorReader{}) }(), expectedInput: nil, expectedError: errors.New("read error"), }, } parser := &DefaultRequestParser{} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { input, err := parser.GetInput(tt.request) if !bytes.Equal(input, tt.expectedInput) { t.Errorf("Expected input %s, got %s", tt.expectedInput, input) } if err != tt.expectedError && (err == nil || err.Error() != tt.expectedError.Error()) { t.Errorf("Expected error %v, got %v", tt.expectedError, err) } }) } }