package cms import ( "encoding/json" "io" "net/http" "net/http/httptest" "reflect" "strings" "testing" "gitea.futuresens.co.uk/futuresens/cmstypes" ) func TestReadHotelSuccess(t *testing.T) { const hotelCode = "gb-test-hotel" expected := cmstypes.ReservationSystemRec{} server := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { t.Errorf( "expected method %s, got %s", http.MethodPost, r.Method, ) } if r.URL.Path != cmstypes.APIHotelDetails { t.Errorf( "expected path %q, got %q", cmstypes.APIHotelDetails, r.URL.Path, ) } if contentType := r.Header.Get("Content-Type"); contentType != "application/json" { t.Errorf( "expected Content-Type application/json, got %q", contentType, ) } if accept := r.Header.Get("Accept"); accept != "application/json" { t.Errorf( "expected Accept application/json, got %q", accept, ) } var request cmstypes.RequestRec if err := json.NewDecoder(r.Body).Decode(&request); err != nil { t.Errorf("decode request: %v", err) http.Error(w, "invalid request", http.StatusBadRequest) return } if request.Auth.ID != hotelCode { t.Errorf( "expected auth ID %q, got %q", hotelCode, request.Auth.ID, ) } if request.Auth.Hotel != hotelCode { t.Errorf( "expected auth hotel %q, got %q", hotelCode, request.Auth.Hotel, ) } if request.Auth.APIKey != cmstypes.APIKey { t.Errorf( "expected API key %q, got %q", cmstypes.APIKey, request.Auth.APIKey, ) } if request.Data != hotelCode { t.Errorf( "expected request data %q, got %q", hotelCode, request.Data, ) } response := cmstypes.HotelResponseRec{} response.Status.Code = cmstypes.StatusSuccessCode response.TheHotel.Updated = 1 response.TheHotel.ReservationSystem = expected w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(response); err != nil { t.Errorf("encode response: %v", err) } }, )) defer server.Close() got, err := ReadHotel(hotelCode, server.URL) if err != nil { t.Fatalf("ReadHotel returned an unexpected error: %v", err) } if !reflect.DeepEqual(got, expected) { t.Errorf( "unexpected reservation system:\ngot: %+v\nwant: %+v", got, expected, ) } } func TestReadHotelValidation(t *testing.T) { tests := []struct { name string hotelCode string cmsBaseURL string wantMessage string }{ { name: "empty hotel code", hotelCode: "", cmsBaseURL: "http://example.com", wantMessage: "hotel code is empty", }, { name: "empty CMS base URL", hotelCode: "gb-test-hotel", cmsBaseURL: "", wantMessage: "CMS base URL is empty", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { _, err := ReadHotel(test.hotelCode, test.cmsBaseURL) if err == nil { t.Fatal("expected an error, got nil") } if err.Error() != test.wantMessage { t.Errorf( "expected error %q, got %q", test.wantMessage, err.Error(), ) } }) } } func TestReadHotelNotUpdated(t *testing.T) { server := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, _ *http.Request) { response := cmstypes.HotelResponseRec{} response.Status.Code = cmstypes.StatusSuccessCode response.TheHotel.Updated = -1 w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(response); err != nil { t.Errorf("encode response: %v", err) } }, )) defer server.Close() _, err := ReadHotel("gb-test-hotel", server.URL) if err == nil { t.Fatal("expected an error, got nil") } const expected = "hotel record not updated since last read" if err.Error() != expected { t.Errorf("expected error %q, got %q", expected, err.Error()) } } func TestReadHotelHTTPError(t *testing.T) { server := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusInternalServerError) if _, err := io.WriteString(w, "CMS unavailable"); err != nil { t.Errorf("write response: %v", err) } }, )) defer server.Close() _, err := ReadHotel("gb-test-hotel", server.URL) if err == nil { t.Fatal("expected an error, got nil") } if !strings.Contains(err.Error(), "HTTP 500 Internal Server Error") { t.Errorf("unexpected error: %v", err) } if !strings.Contains(err.Error(), "CMS unavailable") { t.Errorf("expected response body in error, got: %v", err) } } func TestReadHotelInvalidJSON(t *testing.T) { server := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json") if _, err := io.WriteString(w, `{invalid JSON`); err != nil { t.Errorf("write response: %v", err) } }, )) defer server.Close() _, err := ReadHotel("gb-test-hotel", server.URL) if err == nil { t.Fatal("expected an error, got nil") } if !strings.Contains(err.Error(), "unmarshal CMS hotel response") { t.Errorf("unexpected error: %v", err) } }