Add weather API bundle adapter
This commit is contained in:
@@ -6,7 +6,9 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/adapters/weatherapi"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/forecast"
|
||||
)
|
||||
|
||||
type ReportKind string
|
||||
@@ -40,6 +42,11 @@ type BatchRequest struct {
|
||||
Batch BatchKind
|
||||
}
|
||||
|
||||
type FetchBundleRequest struct {
|
||||
Config config.Config
|
||||
OutputPath string
|
||||
}
|
||||
|
||||
func Generate(ctx context.Context, req GenerateRequest) error {
|
||||
_ = ctx
|
||||
_ = req
|
||||
@@ -51,3 +58,29 @@ func RunBatch(ctx context.Context, req BatchRequest) error {
|
||||
_ = req
|
||||
return fmt.Errorf("run is not implemented")
|
||||
}
|
||||
|
||||
func FetchBundle(ctx context.Context, req FetchBundleRequest) (*forecast.Bundle, error) {
|
||||
client, err := weatherapi.New(req.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bundle, err := client.FetchBundle(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
func FetchAndSaveBundle(ctx context.Context, req FetchBundleRequest) (*forecast.Bundle, error) {
|
||||
if req.OutputPath == "" {
|
||||
return nil, fmt.Errorf("output path is required")
|
||||
}
|
||||
bundle, err := FetchBundle(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := weatherapi.SaveBundle(req.OutputPath, bundle); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
64
internal/app/app_test.go
Normal file
64
internal/app/app_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
|
||||
)
|
||||
|
||||
func TestFetchAndSaveBundle(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/observations":
|
||||
_, _ = w.Write([]byte(`{"data":{"timestamp":"2026-05-29T14:00:00Z","conditionCode":3}}`))
|
||||
case "/conditions/current":
|
||||
_, _ = w.Write([]byte(`{"data":{"conditionText":"Clear"}}`))
|
||||
case "/forecast/hourly":
|
||||
_, _ = w.Write([]byte(`{"data":{"issuedAt":"2026-05-29T10:30:00-05:00","product":"hourly","periods":[{"startTime":"2026-05-29T13:00:00-05:00","endTime":"2026-05-29T14:00:00-05:00"}]}}`))
|
||||
case "/forecast/narrative":
|
||||
_, _ = w.Write([]byte(`{"data":{"issuedAt":"2026-05-29T10:30:00-05:00","product":"narrative","periods":[]}}`))
|
||||
case "/alerts/active":
|
||||
_, _ = w.Write([]byte(`{"data":{"alerts":[]}}`))
|
||||
case "/discussion":
|
||||
_, _ = w.Write([]byte(`{"data":{"product":"discussion","issuedAt":"2026-05-29T09:25:00-05:00","keyMessages":[]}}`))
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
cfg := config.Defaults()
|
||||
cfg.WeatherAPI.BaseURL = server.URL + "/"
|
||||
path := filepath.Join(t.TempDir(), "bundle.json")
|
||||
|
||||
bundle, err := FetchAndSaveBundle(context.Background(), FetchBundleRequest{Config: cfg, OutputPath: path})
|
||||
if err != nil {
|
||||
t.Fatalf("FetchAndSaveBundle() error = %v", err)
|
||||
}
|
||||
if bundle.Hourly == nil {
|
||||
t.Fatal("Hourly = nil, want fetched bundle")
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("read saved bundle: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(data), `"product": "hourly"`) {
|
||||
t.Fatalf("saved bundle missing hourly product:\n%s", string(data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchAndSaveBundleRequiresOutputPath(t *testing.T) {
|
||||
_, err := FetchAndSaveBundle(context.Background(), FetchBundleRequest{Config: config.Defaults()})
|
||||
if err == nil {
|
||||
t.Fatal("FetchAndSaveBundle() error = nil, want output path error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "output path") {
|
||||
t.Fatalf("error = %q, want output path context", err.Error())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user