package weather import ( "context" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" ) func TestOpenMeteoProvider(t *testing.T) { var geoReqCount, weatherReqCount int mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/v1/search" { geoReqCount++ json.NewEncoder(w).Encode(geoResponse{ Results: []geoResult{{ Name: "Moscow", Latitude: 55.7558, Longitude: 37.6173, Country: "Russia", }}, }) return } if r.URL.Path == "/v1/forecast" { weatherReqCount++ json.NewEncoder(w).Encode(forecastResponse{ CurrentWeather: currentWeather{ Temperature: 22.5, WMO: 0, WindSpeed: 3.2, }, }) return } w.WriteHeader(http.StatusNotFound) })) defer mock.Close() p := NewOpenMeteoProvider() transport := &mockTransport{ geoURL: mock.URL + "/v1/search", forecastURL: mock.URL + "/v1/forecast", } p.SetClient(&http.Client{Transport: transport}) w, err := p.CurrentWeather(context.Background(), "Moscow") if err != nil { t.Fatalf("CurrentWeather: %v", err) } if w.Location != "Moscow" { t.Errorf("location = %q, want Moscow", w.Location) } if w.Temperature != 22.5 { t.Errorf("temperature = %f, want 22.5", w.Temperature) } if w.Condition != "ясно" { t.Errorf("condition = %q, want ясно", w.Condition) } } type mockTransport struct { geoURL string forecastURL string } func (t *mockTransport) RoundTrip(r *http.Request) (*http.Response, error) { var targetURL string if r.URL.Host == "geocoding-api.open-meteo.com" { targetURL = t.geoURL + "?" + r.URL.RawQuery } else if r.URL.Host == "api.open-meteo.com" { targetURL = t.forecastURL + "?" + r.URL.RawQuery } else { return nil, fmt.Errorf("unexpected host: %s", r.URL.Host) } req, _ := http.NewRequestWithContext(r.Context(), r.Method, targetURL, nil) return http.DefaultTransport.RoundTrip(req) } func TestStubProvider(t *testing.T) { p := NewStubProvider() _, err := p.CurrentWeather(context.Background(), "Moscow") if err != ErrNotConfigured { t.Fatalf("StubProvider: want ErrNotConfigured, got %v", err) } }