diff --git a/docs/CLI.md b/docs/CLI.md index 0b8e279..07bf53f 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -297,7 +297,7 @@ View pageview statistics. - `--site DOMAIN`: Filter by site domain - `--last PERIOD`: Relative time period (24h, 7d, 30d, 1mo, 3mo, 6mo) - `--from DATE`: Start date (YYYY-MM-DD). Without --to, goes from this date to now. -- `--to DATE`: End date (YYYY-MM-DD). Without --from, goes from all time to this date. +- `--to DATE`: End date (YYYY-MM-DD). Without --from, queries all time up to this date. Requires --to alone (do not combine with --from or --last). - `--verbose`, `-v`: Show detailed view **Examples:** diff --git a/internal/api/stats_test.go b/internal/api/stats_test.go index 160ba07..d871255 100644 --- a/internal/api/stats_test.go +++ b/internal/api/stats_test.go @@ -74,26 +74,68 @@ func TestStatsFromOnly(t *testing.T) { _, ts := setupTestServer(t) token := generateTestToken(t, ts) - req, _ := http.NewRequest("GET", ts.URL+"/api/stats?from=2024-01-01", nil) + body := `{"domain":"example.com"}` + req, _ := http.NewRequest("POST", ts.URL+"/api/sites", strings.NewReader(body)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + http.DefaultClient.Do(req) + + collectBody := `{"origin":"https://example.com","path":"/","referrer":"","screen":"1920x1080"}` + req, _ = http.NewRequest("POST", ts.URL+"/collect", strings.NewReader(collectBody)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Origin", "https://example.com") + http.DefaultClient.Do(req) + + req, _ = http.NewRequest("GET", ts.URL+"/api/stats?from=2000-01-01", nil) req.Header.Set("Authorization", "Bearer "+token) resp, _ := http.DefaultClient.Do(req) if resp.StatusCode != 200 { - t.Errorf("from only: expected 200, got %d", resp.StatusCode) + t.Fatalf("from only: expected 200, got %d", resp.StatusCode) + } + + var stats []struct { + Site string `json:"site"` + Path string `json:"path"` } + json.NewDecoder(resp.Body).Decode(&stats) resp.Body.Close() + if len(stats) == 0 { + t.Error("expected data with from-only filter, got empty") + } } func TestStatsToOnly(t *testing.T) { _, ts := setupTestServer(t) token := generateTestToken(t, ts) - req, _ := http.NewRequest("GET", ts.URL+"/api/stats?to=2024-01-31", nil) + body := `{"domain":"example.com"}` + req, _ := http.NewRequest("POST", ts.URL+"/api/sites", strings.NewReader(body)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + http.DefaultClient.Do(req) + + collectBody := `{"origin":"https://example.com","path":"/","referrer":"","screen":"1920x1080"}` + req, _ = http.NewRequest("POST", ts.URL+"/collect", strings.NewReader(collectBody)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Origin", "https://example.com") + http.DefaultClient.Do(req) + + req, _ = http.NewRequest("GET", ts.URL+"/api/stats?to=2099-01-01", nil) req.Header.Set("Authorization", "Bearer "+token) resp, _ := http.DefaultClient.Do(req) if resp.StatusCode != 200 { - t.Errorf("to only: expected 200, got %d", resp.StatusCode) + t.Fatalf("to only: expected 200, got %d", resp.StatusCode) + } + + var stats []struct { + Site string `json:"site"` + Path string `json:"path"` } + json.NewDecoder(resp.Body).Decode(&stats) resp.Body.Close() + if len(stats) == 0 { + t.Error("expected data with to-only filter, got empty") + } } func TestStatsDefaultTimeRange(t *testing.T) { diff --git a/internal/cli/stats.go b/internal/cli/stats.go index 7cdb86d..3438cf3 100644 --- a/internal/cli/stats.go +++ b/internal/cli/stats.go @@ -16,7 +16,7 @@ Options: --site DOMAIN Filter by site domain --last PERIOD Relative period: 24h, 7d, 30d, 1mo, 3mo, 6mo (default: 24h) --from DATE Start date (YYYY-MM-DD). Without --to, goes to now. - --to DATE End date (YYYY-MM-DD). Without --from, goes from all time. + --to DATE End date (YYYY-MM-DD). Without --from, queries all time up to this date. --verbose, -v Show detailed view Examples: diff --git a/internal/db/db_test.go b/internal/db/db_test.go index f7c6a45..ccf683d 100644 --- a/internal/db/db_test.go +++ b/internal/db/db_test.go @@ -437,7 +437,7 @@ func TestGetAggregateStats(t *testing.T) { } } -func TestGetAggregateStatsFromOnly(t *testing.T) { +func TestGetAggregateStatsToOnly(t *testing.T) { db := setupTestDB(t) site, _ := db.AddSite("example.com") db.InsertPageview(models.PageviewInput{SiteID: site.ID, IP: "1.2.3.4", Path: "/"}) @@ -449,14 +449,14 @@ func TestGetAggregateStatsFromOnly(t *testing.T) { rows, err := db.GetAggregateStats(q) if err != nil { - t.Fatalf("get aggregate stats with zero from: %v", err) + t.Fatalf("get aggregate stats with to only: %v", err) } if len(rows) != 1 { t.Errorf("expected 1 stat row, got %d", len(rows)) } } -func TestGetAggregateStatsToOnly(t *testing.T) { +func TestGetAggregateStatsFromOnly(t *testing.T) { db := setupTestDB(t) site, _ := db.AddSite("example.com") db.InsertPageview(models.PageviewInput{SiteID: site.ID, IP: "1.2.3.4", Path: "/"}) @@ -468,7 +468,7 @@ func TestGetAggregateStatsToOnly(t *testing.T) { rows, err := db.GetAggregateStats(q) if err != nil { - t.Fatalf("get aggregate stats with zero to: %v", err) + t.Fatalf("get aggregate stats with from only: %v", err) } if len(rows) != 1 { t.Errorf("expected 1 stat row, got %d", len(rows)) @@ -551,7 +551,7 @@ func TestGetVerboseStats(t *testing.T) { } } -func TestGetVerboseStatsFromOnly(t *testing.T) { +func TestGetVerboseStatsToOnly(t *testing.T) { db := setupTestDB(t) site, _ := db.AddSite("example.com") db.InsertPageview(models.PageviewInput{SiteID: site.ID, IP: "1.2.3.4", Path: "/"}) @@ -563,14 +563,14 @@ func TestGetVerboseStatsFromOnly(t *testing.T) { rows, err := db.GetVerboseStats(q) if err != nil { - t.Fatalf("get verbose stats with zero from: %v", err) + t.Fatalf("get verbose stats with to only: %v", err) } if len(rows) != 1 { t.Errorf("expected 1 row, got %d", len(rows)) } } -func TestGetVerboseStatsToOnly(t *testing.T) { +func TestGetVerboseStatsFromOnly(t *testing.T) { db := setupTestDB(t) site, _ := db.AddSite("example.com") db.InsertPageview(models.PageviewInput{SiteID: site.ID, IP: "1.2.3.4", Path: "/"}) @@ -582,7 +582,7 @@ func TestGetVerboseStatsToOnly(t *testing.T) { rows, err := db.GetVerboseStats(q) if err != nil { - t.Fatalf("get verbose stats with zero to: %v", err) + t.Fatalf("get verbose stats with from only: %v", err) } if len(rows) != 1 { t.Errorf("expected 1 row, got %d", len(rows))