Skip to content

Commit fe8da5a

Browse files
committed
Add http logic for ListBaselineStatusCounts
This change adds the logic to call the spanner adapter layer for ListBaselineStatusCounts This is similar to ListMissingOneImplCounts (also used on the stats page)
1 parent 397ba9c commit fe8da5a

File tree

4 files changed

+232
-5
lines changed

4 files changed

+232
-5
lines changed

backend/pkg/httpserver/list_aggregated_baseline_status_counts.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ package httpserver
1616

1717
import (
1818
"context"
19-
"net/http"
19+
"errors"
20+
"log/slog"
2021

22+
"github.com/GoogleChrome/webstatus.dev/lib/gcpspanner/spanneradapters/backendtypes"
2123
"github.com/GoogleChrome/webstatus.dev/lib/gen/openapi/backend"
2224
)
2325

@@ -26,8 +28,30 @@ import (
2628
func (s *Server) ListAggregatedBaselineStatusCounts(
2729
ctx context.Context, request backend.ListAggregatedBaselineStatusCountsRequestObject) (
2830
backend.ListAggregatedBaselineStatusCountsResponseObject, error) {
29-
return backend.ListAggregatedBaselineStatusCounts400JSONResponse{
30-
Code: http.StatusBadRequest,
31-
Message: "TODO",
32-
}, nil
31+
page, err := s.wptMetricsStorer.ListBaselineStatusCounts(
32+
ctx,
33+
request.Params.StartAt.Time,
34+
request.Params.EndAt.Time,
35+
getPageSizeOrDefault(request.Params.PageSize),
36+
request.Params.PageToken,
37+
)
38+
if err != nil {
39+
if errors.Is(err, backendtypes.ErrInvalidPageToken) {
40+
slog.WarnContext(ctx, "invalid page token", "token", request.Params.PageToken, "error", err)
41+
42+
return backend.ListAggregatedBaselineStatusCounts400JSONResponse{
43+
Code: 400,
44+
Message: "invalid page token",
45+
}, nil
46+
}
47+
48+
slog.ErrorContext(ctx, "unable to get missing one implementation count", "error", err)
49+
50+
return backend.ListAggregatedBaselineStatusCounts500JSONResponse{
51+
Code: 500,
52+
Message: "unable to get missing one implementation metrics",
53+
}, nil
54+
}
55+
56+
return backend.ListAggregatedBaselineStatusCounts200JSONResponse(*page), nil
3357
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package httpserver
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
"time"
8+
9+
"github.com/GoogleChrome/webstatus.dev/lib/gcpspanner/spanneradapters/backendtypes"
10+
"github.com/GoogleChrome/webstatus.dev/lib/gen/openapi/backend"
11+
)
12+
13+
func TestListAggregatedBaselineStatusCounts(t *testing.T) {
14+
testCases := []struct {
15+
name string
16+
mockConfig MockListBaselineStatusCountsConfig
17+
expectedCallCount int
18+
request *http.Request
19+
expectedResponse *http.Response
20+
}{
21+
{
22+
name: "Success Case - no optional params - use defaults",
23+
mockConfig: MockListBaselineStatusCountsConfig{
24+
expectedStartAt: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC),
25+
expectedEndAt: time.Date(2000, time.January, 10, 0, 0, 0, 0, time.UTC),
26+
expectedPageSize: 100,
27+
expectedPageToken: nil,
28+
pageToken: nil,
29+
err: nil,
30+
page: &backend.BaselineStatusMetricsPage{
31+
Metadata: &backend.PageMetadata{
32+
NextPageToken: nil,
33+
},
34+
Data: []backend.BaselineStatusMetric{
35+
{
36+
Count: valuePtr[int64](10),
37+
Timestamp: time.Date(2000, time.January, 10, 0, 0, 0, 0, time.UTC),
38+
},
39+
{
40+
Count: valuePtr[int64](9),
41+
Timestamp: time.Date(2000, time.January, 9, 0, 0, 0, 0, time.UTC),
42+
},
43+
},
44+
},
45+
},
46+
expectedCallCount: 1,
47+
expectedResponse: testJSONResponse(200, `
48+
{
49+
"data":[
50+
{
51+
"count":10,
52+
"timestamp":"2000-01-10T00:00:00Z"
53+
},
54+
{
55+
"count":9,
56+
"timestamp":"2000-01-09T00:00:00Z"
57+
}
58+
],
59+
"metadata":{
60+
61+
}
62+
}`),
63+
request: httptest.NewRequest(http.MethodGet,
64+
"/v1/stats/baseline_status/low_date_feature_counts?"+
65+
"startAt=2000-01-01&endAt=2000-01-10", nil),
66+
},
67+
{
68+
name: "Success Case - include optional params",
69+
mockConfig: MockListBaselineStatusCountsConfig{
70+
expectedStartAt: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC),
71+
expectedEndAt: time.Date(2000, time.January, 10, 0, 0, 0, 0, time.UTC),
72+
expectedPageSize: 50,
73+
expectedPageToken: inputPageToken,
74+
err: nil,
75+
page: &backend.BaselineStatusMetricsPage{
76+
Metadata: &backend.PageMetadata{
77+
NextPageToken: nextPageToken,
78+
},
79+
Data: []backend.BaselineStatusMetric{
80+
{
81+
Count: valuePtr[int64](10),
82+
Timestamp: time.Date(2000, time.January, 10, 0, 0, 0, 0, time.UTC),
83+
},
84+
{
85+
Count: valuePtr[int64](9),
86+
Timestamp: time.Date(2000, time.January, 9, 0, 0, 0, 0, time.UTC),
87+
},
88+
},
89+
},
90+
pageToken: nextPageToken,
91+
},
92+
expectedCallCount: 1,
93+
expectedResponse: testJSONResponse(200, `
94+
{
95+
"data":[
96+
{
97+
"count":10,
98+
"timestamp":"2000-01-10T00:00:00Z"
99+
},
100+
{
101+
"count":9,
102+
"timestamp":"2000-01-09T00:00:00Z"
103+
}
104+
],
105+
"metadata":{
106+
"next_page_token":"next-page-token"
107+
}
108+
}`),
109+
request: httptest.NewRequest(http.MethodGet,
110+
"/v1/stats/baseline_status/low_date_feature_counts?"+
111+
"startAt=2000-01-01&endAt=2000-01-10&page_size=50&page_token="+*inputPageToken, nil),
112+
},
113+
{
114+
name: "500 case",
115+
mockConfig: MockListBaselineStatusCountsConfig{
116+
expectedStartAt: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC),
117+
expectedEndAt: time.Date(2000, time.January, 10, 0, 0, 0, 0, time.UTC),
118+
expectedPageSize: 100,
119+
expectedPageToken: nil,
120+
page: nil,
121+
pageToken: nil,
122+
err: errTest,
123+
},
124+
expectedCallCount: 1,
125+
expectedResponse: testJSONResponse(
126+
500, `{"code":500,"message":"unable to get missing one implementation metrics"}`),
127+
request: httptest.NewRequest(http.MethodGet,
128+
"/v1/stats/baseline_status/low_date_feature_counts?"+
129+
"startAt=2000-01-01&endAt=2000-01-10", nil),
130+
},
131+
{
132+
name: "400 case - invalid page token",
133+
mockConfig: MockListBaselineStatusCountsConfig{
134+
expectedStartAt: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC),
135+
expectedEndAt: time.Date(2000, time.January, 10, 0, 0, 0, 0, time.UTC),
136+
expectedPageSize: 100,
137+
expectedPageToken: badPageToken,
138+
page: nil,
139+
pageToken: nil,
140+
err: backendtypes.ErrInvalidPageToken,
141+
},
142+
expectedCallCount: 1,
143+
expectedResponse: testJSONResponse(400, `{"code":400,"message":"invalid page token"}`),
144+
request: httptest.NewRequest(http.MethodGet,
145+
"/v1/stats/baseline_status/low_date_feature_counts?"+
146+
"startAt=2000-01-01&endAt=2000-01-10&page_token"+*badPageToken, nil),
147+
},
148+
}
149+
150+
for _, tc := range testCases {
151+
t.Run(tc.name, func(t *testing.T) {
152+
// nolint: exhaustruct
153+
mockStorer := &MockWPTMetricsStorer{
154+
listBaselineStatusCountsCfg: tc.mockConfig,
155+
t: t,
156+
}
157+
myServer := Server{wptMetricsStorer: mockStorer, metadataStorer: nil}
158+
assertTestServerRequest(t, &myServer, tc.request, tc.expectedResponse)
159+
assertMockCallCount(t, tc.expectedCallCount, mockStorer.callCountListBaselineStatusCounts,
160+
"ListBaselineStatusCounts")
161+
})
162+
}
163+
}

backend/pkg/httpserver/server.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ type WPTMetricsStorer interface {
9797
pageSize int,
9898
pageToken *string,
9999
) (*backend.BrowserReleaseFeatureMetricsPage, error)
100+
ListBaselineStatusCounts(
101+
ctx context.Context,
102+
startAt time.Time,
103+
endAt time.Time,
104+
pageSize int,
105+
pageToken *string,
106+
) (*backend.BaselineStatusMetricsPage, error)
100107
}
101108

102109
type Server struct {

backend/pkg/httpserver/server_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,29 @@ type MockListMissingOneImplCountsConfig struct {
144144
err error
145145
}
146146

147+
type MockListBaselineStatusCountsConfig struct {
148+
expectedStartAt time.Time
149+
expectedEndAt time.Time
150+
expectedPageSize int
151+
expectedPageToken *string
152+
pageToken *string
153+
page *backend.BaselineStatusMetricsPage
154+
err error
155+
}
156+
147157
type MockWPTMetricsStorer struct {
148158
featureCfg MockListMetricsForFeatureIDBrowserAndChannelConfig
149159
aggregateCfg MockListMetricsOverTimeWithAggregatedTotalsConfig
150160
featuresSearchCfg MockFeaturesSearchConfig
151161
listBrowserFeatureCountMetricCfg MockListBrowserFeatureCountMetricConfig
152162
listMissingOneImplCountCfg MockListMissingOneImplCountsConfig
163+
listBaselineStatusCountsCfg MockListBaselineStatusCountsConfig
153164
listChromiumDailyUsageStatsCfg MockListChromiumDailyUsageStatsConfig
154165
getFeatureByIDConfig MockGetFeatureByIDConfig
155166
getIDFromFeatureKeyConfig MockGetIDFromFeatureKeyConfig
156167
t *testing.T
157168
callCountListMissingOneImplCounts int
169+
callCountListBaselineStatusCounts int
158170
callCountListBrowserFeatureCountMetric int
159171
callCountFeaturesSearch int
160172
callCountListChromiumDailyUsageStats int
@@ -340,6 +352,27 @@ func (m *MockWPTMetricsStorer) ListMissingOneImplCounts(
340352
return m.listMissingOneImplCountCfg.page, m.listMissingOneImplCountCfg.err
341353
}
342354

355+
func (m *MockWPTMetricsStorer) ListBaselineStatusCounts(
356+
_ context.Context,
357+
startAt time.Time,
358+
endAt time.Time,
359+
pageSize int,
360+
pageToken *string,
361+
) (*backend.BaselineStatusMetricsPage, error) {
362+
m.callCountListBaselineStatusCounts++
363+
364+
if !startAt.Equal(m.listBaselineStatusCountsCfg.expectedStartAt) ||
365+
!endAt.Equal(m.listBaselineStatusCountsCfg.expectedEndAt) ||
366+
pageSize != m.listBaselineStatusCountsCfg.expectedPageSize ||
367+
!reflect.DeepEqual(pageToken, m.listBaselineStatusCountsCfg.expectedPageToken) {
368+
369+
m.t.Errorf("Incorrect arguments. Expected: %v, Got: { %s, %s, %d %v }",
370+
m.listBaselineStatusCountsCfg, startAt, endAt, pageSize, pageToken)
371+
}
372+
373+
return m.listBaselineStatusCountsCfg.page, m.listBaselineStatusCountsCfg.err
374+
}
375+
343376
func TestGetPageSizeOrDefault(t *testing.T) {
344377
testCases := []struct {
345378
name string

0 commit comments

Comments
 (0)