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  }