github.com/web-platform-tests/wpt.fyi@v0.0.0-20240530210107-70cf978996f1/api/query/search_test.go (about) 1 //go:build small 2 // +build small 3 4 // Copyright 2018 The WPT Dashboard Project. All rights reserved. 5 // Use of this source code is governed by a BSD-style license that can be 6 // found in the LICENSE file. 7 8 package query 9 10 import ( 11 "bytes" 12 "net/http" 13 "net/http/httptest" 14 "net/url" 15 "sort" 16 "strings" 17 "testing" 18 19 "github.com/golang/mock/gomock" 20 21 "github.com/stretchr/testify/assert" 22 "github.com/web-platform-tests/wpt.fyi/shared" 23 "github.com/web-platform-tests/wpt.fyi/shared/sharedtest" 24 ) 25 26 func doTestIC(t *testing.T, p, q string) { 27 runIDs := []int64{1, 2} 28 testRuns := []shared.TestRun{ 29 { 30 ID: runIDs[0], 31 ResultsURL: "https://example.com/1-summary_v2.json.gz", 32 }, 33 { 34 ID: runIDs[1], 35 ResultsURL: "https://example.com/2-summary_v2.json.gz", 36 }, 37 } 38 filters := shared.QueryFilter{ 39 RunIDs: runIDs, 40 Q: q, 41 } 42 summaries := []summary{ 43 { 44 "/a" + p + "c": { 45 Status: "T", Counts: []int{0, 0}, 46 }, 47 p + "c": { 48 Status: "O", Counts: []int{8, 8}, 49 }, 50 }, 51 { 52 "/z" + p + "c": { 53 Status: "F", Counts: []int{0, 7}, 54 }, 55 "/x/y/z": { 56 Status: "O", Counts: []int{2, 3}, 57 }, 58 p + "c": { 59 Status: "O", Counts: []int{4, 8}, 60 }, 61 }, 62 } 63 64 resp := prepareSearchResponse(&filters, testRuns, summaries) 65 assert.Equal(t, testRuns, resp.Runs) 66 expectedResults := []shared.SearchResult{ 67 { 68 Test: "/a" + p + "c", 69 LegacyStatus: []shared.LegacySearchRunResult{ 70 { 71 Passes: 0, 72 Total: 0, 73 Status: "T", 74 NewAggProcess: true, 75 }, 76 { 77 Passes: 0, 78 Total: 0, 79 Status: "", 80 NewAggProcess: false, 81 }, 82 }, 83 }, 84 { 85 Test: p + "c", 86 LegacyStatus: []shared.LegacySearchRunResult{ 87 { 88 Passes: 8, 89 Total: 8, 90 Status: "O", 91 NewAggProcess: true, 92 }, 93 { 94 Passes: 4, 95 Total: 8, 96 Status: "O", 97 NewAggProcess: true, 98 }, 99 }, 100 }, 101 { 102 Test: "/z" + p + "c", 103 LegacyStatus: []shared.LegacySearchRunResult{ 104 {}, 105 { 106 Passes: 0, 107 Total: 7, 108 Status: "F", 109 NewAggProcess: true, 110 }, 111 }, 112 }, 113 } 114 sort.Sort(byName(expectedResults)) 115 assert.Equal(t, expectedResults, resp.Results) 116 } 117 118 func testIC(t *testing.T, str string, upperQ bool) { 119 var p, q string 120 if upperQ { 121 p = strings.ToLower(str) 122 q = strings.ToUpper(str) 123 } else { 124 p = strings.ToUpper(str) 125 q = strings.ToLower(str) 126 } 127 128 doTestIC(t, p, q) 129 } 130 131 func TestPrepareSearchResponse_qUC(t *testing.T) { 132 testIC(t, "/b/", true) 133 } 134 135 func TestPrepareSearchResponse_pUC(t *testing.T) { 136 testIC(t, "/b/", false) 137 } 138 139 func TestStructuredSearchHandler_success(t *testing.T) { 140 ctrl := gomock.NewController(t) 141 defer ctrl.Finish() 142 mockStore := sharedtest.NewMockDatastore(ctrl) 143 144 respBytes := []byte(`{}`) 145 146 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 147 assert.Equal(t, "POST", r.Method) 148 assert.Equal(t, "/api/search/cache", r.URL.Path) 149 w.Write(respBytes) 150 })) 151 152 serverURL, err := url.Parse(server.URL) 153 assert.Nil(t, err) 154 hostname := serverURL.Host 155 156 runIDs := []int64{1, 2} 157 urls := []string{ 158 "https://example.com/1-summary_v2.json.gz", 159 "https://example.com/2-summary_v2.json.gz", 160 } 161 chrome, _ := shared.ParseProductSpec("chrome") 162 edge, _ := shared.ParseProductSpec("edge") 163 testRuns := shared.TestRunsByProduct{ 164 shared.ProductTestRuns{ 165 Product: chrome, 166 TestRuns: shared.TestRuns{ 167 shared.TestRun{ 168 ID: runIDs[0], 169 ResultsURL: urls[0], 170 }, 171 }, 172 }, 173 shared.ProductTestRuns{ 174 Product: edge, 175 TestRuns: shared.TestRuns{ 176 shared.TestRun{ 177 ID: runIDs[1], 178 ResultsURL: urls[1], 179 }, 180 }, 181 }, 182 } 183 for _, id := range runIDs { 184 mockStore.EXPECT().NewIDKey("TestRun", id).Return(sharedtest.MockKey{ID: id}) 185 } 186 mockStore.EXPECT().GetMulti(sharedtest.SameKeys(runIDs), gomock.Any()).DoAndReturn(sharedtest.MultiRuns(testRuns.AllRuns())) 187 188 api := sharedtest.NewMockAppEngineAPI(ctrl) 189 r := httptest.NewRequest("POST", "https://example.com/api/query", bytes.NewBuffer([]byte(`{"run_ids":[1,2],"query":{"browser_name":"chrome","status":"PASS"}}`))) 190 191 api.EXPECT().Context().Return(sharedtest.NewTestContext()) 192 api.EXPECT().GetServiceHostname("searchcache").Return(hostname) 193 api.EXPECT().GetHTTPClientWithTimeout(gomock.Any()).Return(server.Client()) 194 w := httptest.NewRecorder() 195 structuredSearchHandler{queryHandler{store: mockStore}, api}.ServeHTTP(w, r) 196 197 assert.Equal(t, http.StatusOK, w.Code) 198 assert.Equal(t, respBytes, w.Body.Bytes()) 199 } 200 201 func TestStructuredSearchHandler_failure(t *testing.T) { 202 ctrl := gomock.NewController(t) 203 defer ctrl.Finish() 204 mockStore := sharedtest.NewMockDatastore(ctrl) 205 206 respBytes := []byte(`Unknown run ID: 42`) 207 208 server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 209 assert.Equal(t, "POST", r.Method) 210 assert.Equal(t, "/api/search/cache", r.URL.Path) 211 w.WriteHeader(http.StatusBadRequest) 212 w.Write(respBytes) 213 })) 214 215 serverURL, err := url.Parse(server.URL) 216 assert.Nil(t, err) 217 hostname := serverURL.Host 218 runIDs := []int64{1, 2} 219 urls := []string{ 220 "https://example.com/1-summary_v2.json.gz", 221 "https://example.com/2-summary_v2.json.gz", 222 } 223 chrome, _ := shared.ParseProductSpec("chrome") 224 edge, _ := shared.ParseProductSpec("edge") 225 testRuns := shared.TestRunsByProduct{ 226 shared.ProductTestRuns{ 227 Product: chrome, 228 TestRuns: shared.TestRuns{ 229 shared.TestRun{ 230 ID: runIDs[0], 231 ResultsURL: urls[0], 232 }, 233 }, 234 }, 235 shared.ProductTestRuns{ 236 Product: edge, 237 TestRuns: shared.TestRuns{ 238 shared.TestRun{ 239 ID: runIDs[1], 240 ResultsURL: urls[1], 241 }, 242 }, 243 }, 244 } 245 var id int64 = 42 246 mockStore.EXPECT().NewIDKey("TestRun", id).Return(sharedtest.MockKey{ID: id}) 247 mockStore.EXPECT().GetMulti(sharedtest.SameKeys([]int64{id}), gomock.Any()).DoAndReturn(sharedtest.MultiRuns(testRuns.AllRuns())) 248 249 api := sharedtest.NewMockAppEngineAPI(ctrl) 250 r := httptest.NewRequest("POST", "https://example.com/api/query", bytes.NewBuffer([]byte(`{"run_ids":[42],"query":{"browser_name":"chrome","status":"PASS"}}`))) 251 252 api.EXPECT().Context().Return(sharedtest.NewTestContext()) 253 api.EXPECT().GetServiceHostname("searchcache").Return(hostname) 254 api.EXPECT().GetHTTPClientWithTimeout(gomock.Any()).Return(server.Client()) 255 256 w := httptest.NewRecorder() 257 structuredSearchHandler{queryHandler{store: mockStore}, api}.ServeHTTP(w, r) 258 259 assert.Equal(t, http.StatusBadRequest, w.Code) 260 assert.Equal(t, respBytes, w.Body.Bytes()) 261 }