github.com/web-platform-tests/wpt.fyi@v0.0.0-20240530210107-70cf978996f1/webapp/web/routes_test.go (about)

     1  // +build small
     2  
     3  // Copyright 2017 The WPT Dashboard Project. All rights reserved.
     4  // Use of this source code is governed by a BSD-style license that can be
     5  // found in the LICENSE file.
     6  
     7  package main
     8  
     9  import (
    10  	"fmt"
    11  	"net/http"
    12  	"net/http/httptest"
    13  	"testing"
    14  
    15  	"github.com/gorilla/mux"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/web-platform-tests/wpt.fyi/shared"
    18  )
    19  
    20  func TestLandingPageBound(t *testing.T) {
    21  	// Note that init() is always called by the Golang runtime.
    22  	assertHandlerIs(t, "/", "results-legacy")
    23  	assertHSTS(t, "/")
    24  	assertHandlerIs(t, "/2dcontext", "results-legacy")
    25  	assertHandlerIs(t, "/BackgroundSync/interfaces.any.html", "results-legacy")
    26  }
    27  
    28  func TestAboutBound(t *testing.T) {
    29  	assertHandlerIs(t, "/about", "about")
    30  }
    31  
    32  func TestAnalyzerBound(t *testing.T) {
    33  	assertHandlerIs(t, "/analyzer", "analyzer")
    34  }
    35  
    36  func TestFlagsBound(t *testing.T) {
    37  	assertHandlerIs(t, "/flags", "flags")
    38  }
    39  
    40  func TestRunsBound(t *testing.T) {
    41  	assertHandlerIs(t, "/test-runs", "test-runs")
    42  }
    43  
    44  func TestApiDiffBound(t *testing.T) {
    45  	assertHandlerIs(t, "/api/diff", "api-diff")
    46  }
    47  
    48  func TestApiManifestBound(t *testing.T) {
    49  	assertHandlerIs(t, "/api/manifest", "api-manifest")
    50  }
    51  
    52  func TestApiRunsBound(t *testing.T) {
    53  	assertHandlerIs(t, "/api/runs", "api-test-runs")
    54  }
    55  
    56  func TestApiShasBound(t *testing.T) {
    57  	assertHandlerIs(t, "/api/shas", "api-shas")
    58  }
    59  
    60  func TestApiRunBound(t *testing.T) {
    61  	assertHandlerIs(t, "/api/run", "api-test-run")
    62  	assertHandlerIs(t, "/api/runs/123", "api-test-run")
    63  }
    64  
    65  func TestApiStatusBound(t *testing.T) {
    66  	assertHandlerIs(t, "/api/status", "api-pending-test-runs")
    67  	assertHandlerIs(t, "/api/status/pending", "api-pending-test-runs")
    68  	assertHandlerIs(t, "/api/status/invalid", "api-pending-test-runs")
    69  	assertHandlerIs(t, "/api/status/123", "api-pending-test-run-update")
    70  	assertHandlerIsDefault(t, "/api/status/notavalidfilter")
    71  }
    72  
    73  func TestApiResultsBoundCORS(t *testing.T) {
    74  	assertHandlerIs(t, "/api/results", "api-results")
    75  	assertHSTS(t, "/api/results/upload")
    76  	assertCORS(t, "/api/results")
    77  }
    78  
    79  func TestApiScreenshotBoundCORS(t *testing.T) {
    80  	assertHandlerIs(t, "/api/screenshot/sha1:abc", "api-screenshot")
    81  	assertHSTS(t, "/api/screenshot/sha1:abc")
    82  	assertCORS(t, "/api/screenshot/sha1:abc")
    83  }
    84  
    85  func TestApiResultsUploadBoundHSTS(t *testing.T) {
    86  	assertHandlerIs(t, "/api/results/upload", "api-results-upload")
    87  	assertHSTS(t, "/api/results/upload")
    88  	assertNoCORS(t, "/api/results/upload")
    89  }
    90  
    91  func TestApiResultsCreateBoundHSTS(t *testing.T) {
    92  	assertHandlerIs(t, "/api/results/create", "api-results-create")
    93  	assertHSTS(t, "/api/results/create")
    94  	assertNoCORS(t, "/api/results/create")
    95  }
    96  
    97  func TestResultsBound(t *testing.T) {
    98  	assertHandlerIs(t, "/results", "results")
    99  	assertHandlerIs(t, "/results/", "results")
   100  	assertHandlerIs(t, "/results/2dcontext", "results")
   101  	assertHandlerIs(t, "/results/BackgroundSync/interfaces.any.html", "results")
   102  }
   103  
   104  func TestAdminResultsUploadBound(t *testing.T) {
   105  	assertHandlerIs(t, "/admin/results/upload", "admin-results-upload")
   106  }
   107  
   108  func TestAdminCacheFlushBound(t *testing.T) {
   109  	assertHandlerIs(t, "/admin/cache/flush", "admin-cache-flush")
   110  }
   111  
   112  func TestApiMetadataCORS(t *testing.T) {
   113  	// TODO(kyleju): Test CORS for POST/GET request.
   114  	assertHandlerIs(t, "/api/metadata", "api-metadata")
   115  	successPost := httptest.NewRequest("OPTIONS", "/api/metadata", nil)
   116  	successPost.Header.Set("Access-Control-Request-Headers", "content-type")
   117  	successPost.Header.Add("Origin", "https://jgraham.github.io")
   118  	successPost.Header.Add("Access-Control-Request-Method", "POST")
   119  
   120  	rr := sendHttptestRequest(successPost)
   121  
   122  	assert.Equal(t, http.StatusOK, rr.StatusCode)
   123  	assert.Equal(t, "Content-Type", rr.Header.Get("Access-Control-Allow-Headers"))
   124  	assert.Equal(t, "*", rr.Header.Get("Access-Control-Allow-Origin"))
   125  	assert.Equal(t, "", rr.Header.Get("Access-Control-Allow-Credentials"))
   126  }
   127  
   128  func TestApiMetadataTriageCORS(t *testing.T) {
   129  	// TODO(kyleju): Test CORS for PATCH request.
   130  	assertHandlerIs(t, "/api/metadata/triage", "api-metadata-triage")
   131  
   132  	successReq := httptest.NewRequest("OPTIONS", "/api/metadata/triage", nil)
   133  	successReq.Header.Set("Access-Control-Request-Headers", "content-type")
   134  	successReq.Header.Add("Origin", "https://jgraham.github.io")
   135  	successReq.Header.Add("Access-Control-Request-Method", "PATCH")
   136  
   137  	rr := sendHttptestRequest(successReq)
   138  
   139  	assert.Equal(t, http.StatusOK, rr.StatusCode)
   140  	assert.Equal(t, "Content-Type", rr.Header.Get("Access-Control-Allow-Headers"))
   141  	assert.Equal(t, "PATCH", rr.Header.Get("Access-Control-Allow-Methods"))
   142  	assert.Equal(t, "https://jgraham.github.io", rr.Header.Get("Access-Control-Allow-Origin"))
   143  	assert.Equal(t, "true", rr.Header.Get("Access-Control-Allow-Credentials"))
   144  
   145  	invalidOriginReq := httptest.NewRequest("OPTIONS", "/api/metadata/triage", nil)
   146  	invalidOriginReq.Header.Add("Origin", "https://foo")
   147  
   148  	rr = sendHttptestRequest(invalidOriginReq)
   149  
   150  	assert.Equal(t, "", rr.Header.Get("Access-Control-Allow-Origin"))
   151  
   152  	invalidMethodReq := httptest.NewRequest("OPTIONS", "/api/metadata/triage", nil)
   153  	invalidMethodReq.Header.Set("Access-Control-Request-Headers", "content-type")
   154  	invalidMethodReq.Header.Add("Origin", "https://jgraham.github.io")
   155  	invalidMethodReq.Header.Add("Access-Control-Request-Method", "POST")
   156  
   157  	rr = sendHttptestRequest(invalidMethodReq)
   158  
   159  	assert.Equal(t, http.StatusMethodNotAllowed, rr.StatusCode)
   160  }
   161  
   162  func TestApiBSFBound(t *testing.T) {
   163  	assertHandlerIs(t, "/api/bsf", "api-bsf")
   164  	assertHSTS(t, "/api/bsf")
   165  }
   166  
   167  func TestApiPendingMetadataBound(t *testing.T) {
   168  	assertHandlerIs(t, "/api/metadata/pending", "api-pending-metadata")
   169  	assertHSTS(t, "/api/metadata/pending")
   170  }
   171  
   172  func assertBound(t *testing.T, path string) mux.RouteMatch {
   173  	req := httptest.NewRequest("GET", path, nil)
   174  	router := shared.Router()
   175  	match := mux.RouteMatch{}
   176  	assert.Truef(t, router.Match(req, &match), "%s should match a route", path)
   177  	return match
   178  }
   179  
   180  func assertHandlerIs(t *testing.T, path string, name string) {
   181  	match := assertBound(t, path)
   182  	if match.Route != nil {
   183  		assert.Equal(t, name, match.Route.GetName())
   184  	}
   185  }
   186  
   187  func assertHSTS(t *testing.T, path string) {
   188  	req := httptest.NewRequest("GET", path, nil)
   189  	rr := httptest.NewRecorder()
   190  	handler, _ := http.DefaultServeMux.Handler(req)
   191  	handler.ServeHTTP(rr, req)
   192  	res := rr.Result()
   193  	assert.Equal(
   194  		t,
   195  		"[max-age=31536000; preload]",
   196  		fmt.Sprintf("%s", res.Header["Strict-Transport-Security"]))
   197  }
   198  
   199  func sendHttptestRequest(req *http.Request) *http.Response {
   200  	rr := httptest.NewRecorder()
   201  	handler, _ := http.DefaultServeMux.Handler(req)
   202  	handler.ServeHTTP(rr, req)
   203  	return rr.Result()
   204  }
   205  
   206  func assertCORS(t *testing.T, path string) {
   207  	req := httptest.NewRequest("OPTIONS", path, nil)
   208  	req.Header.Set("Access-Control-Request-Headers", "content-type")
   209  	rr := httptest.NewRecorder()
   210  	handler, _ := http.DefaultServeMux.Handler(req)
   211  	handler.ServeHTTP(rr, req)
   212  	assert.Equal(t, http.StatusOK, rr.Result().StatusCode)
   213  
   214  	req = httptest.NewRequest("GET", path, nil)
   215  	req.Header.Add("Origin", "localhost:8080")
   216  	rr = httptest.NewRecorder()
   217  	handler, _ = http.DefaultServeMux.Handler(req)
   218  	handler.ServeHTTP(rr, req)
   219  	res := rr.Result()
   220  	assert.Equal(
   221  		t,
   222  		"*",
   223  		res.Header.Get("Access-Control-Allow-Origin"))
   224  }
   225  
   226  func assertNoCORS(t *testing.T, path string) {
   227  	req := httptest.NewRequest("GET", path, nil)
   228  	rr := httptest.NewRecorder()
   229  	handler, _ := http.DefaultServeMux.Handler(req)
   230  	handler.ServeHTTP(rr, req)
   231  	res := rr.Result()
   232  	assert.Equal(t, "", res.Header.Get("Access-Control-Allow-Origin"))
   233  }
   234  
   235  func assertHandlerIsDefault(t *testing.T, path string) {
   236  	assertHandlerIs(t, path, "results-legacy")
   237  }