Copy disabled (too large)
Download .txt
Showing preview only (15,437K chars total). Download the full file to get everything.
Repository: web-platform-tests/wpt.fyi
Branch: main
Commit: 98e503590d39
Files: 439
Total size: 138.5 MB
Directory structure:
gitextract_pmdwueda/
├── .github/
│ ├── actions/
│ │ └── make-in-docker/
│ │ └── action.yml
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yml
│ ├── codeql.yml
│ ├── deploy.yml
│ └── docker-update.yml
├── .gitignore
├── .golangci.yaml
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── ISSUE_TEMPLATE/
│ ├── checks.md
│ ├── prod-deployment.md
│ ├── screenshots.md
│ └── search.md
├── ISSUE_TEMPLATE.md
├── LICENSE
├── Makefile
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── api/
│ ├── CORS_list.go
│ ├── README.md
│ ├── azure/
│ │ ├── api.go
│ │ ├── mock_azure/
│ │ │ └── api_mock.go
│ │ ├── notify.go
│ │ ├── routes.go
│ │ ├── webhook.go
│ │ └── webhook_test.go
│ ├── bsf_handler.go
│ ├── bsf_handler_test.go
│ ├── checks/
│ │ ├── README.md
│ │ ├── api.go
│ │ ├── jwt.go
│ │ ├── mock_checks/
│ │ │ └── api_mock.go
│ │ ├── routes.go
│ │ ├── runs.go
│ │ ├── suites.go
│ │ ├── suites_medium_test.go
│ │ ├── summaries/
│ │ │ ├── actions.go
│ │ │ ├── actions_test.go
│ │ │ ├── compile.go
│ │ │ ├── compile_test.go
│ │ │ ├── completed.go
│ │ │ ├── pending.go
│ │ │ ├── regressed.go
│ │ │ └── templates/
│ │ │ ├── _file_an_issue.md
│ │ │ ├── _pr_and_master_specs.md
│ │ │ ├── _pr_runs_links.md
│ │ │ ├── _successfully_scraped.md
│ │ │ ├── completed.md
│ │ │ ├── pending.md
│ │ │ └── regressed.md
│ │ ├── update.go
│ │ ├── update_medium_test.go
│ │ ├── update_test.go
│ │ ├── webhook.go
│ │ └── webhook_test.go
│ ├── diff.go
│ ├── ghactions/
│ │ ├── notify.go
│ │ ├── notify_test.go
│ │ └── routes.go
│ ├── labels.go
│ ├── labels_medium_test.go
│ ├── manifest/
│ │ ├── api.go
│ │ ├── mock_manifest/
│ │ │ └── api_mock.go
│ │ ├── util.go
│ │ └── util_test.go
│ ├── manifest.go
│ ├── manifest_test.go
│ ├── metadata_cache.go
│ ├── metadata_handler.go
│ ├── metadata_handler_test.go
│ ├── pending_test_runs.go
│ ├── pending_test_runs_medium_test.go
│ ├── query/
│ │ ├── README.md
│ │ ├── atoms.go
│ │ ├── atoms_test.go
│ │ ├── cache/
│ │ │ ├── README.md
│ │ │ ├── backfill/
│ │ │ │ ├── backfill.go
│ │ │ │ ├── backfill_medium_test.go
│ │ │ │ ├── backfill_test.go
│ │ │ │ └── mock_backfill/
│ │ │ │ └── backfill_mock.go
│ │ │ ├── index/
│ │ │ │ ├── aggregator.go
│ │ │ │ ├── filter.go
│ │ │ │ ├── index.go
│ │ │ │ ├── index_filter_test.go
│ │ │ │ ├── index_medium_test.go
│ │ │ │ ├── index_mock.go
│ │ │ │ ├── index_test.go
│ │ │ │ ├── results.go
│ │ │ │ ├── results_test.go
│ │ │ │ ├── tests.go
│ │ │ │ └── tests_test.go
│ │ │ ├── lru/
│ │ │ │ ├── lru.go
│ │ │ │ └── lru_test.go
│ │ │ ├── monitor/
│ │ │ │ ├── monitor.go
│ │ │ │ ├── monitor_mock.go
│ │ │ │ └── monitor_test.go
│ │ │ ├── poll/
│ │ │ │ ├── poll.go
│ │ │ │ └── poll_test.go
│ │ │ └── query/
│ │ │ ├── query.go
│ │ │ └── query_test.go
│ │ ├── concrete_query.go
│ │ ├── metadata_cache.go
│ │ ├── query.go
│ │ ├── query_test.go
│ │ ├── routes.go
│ │ ├── search.go
│ │ ├── search_medium_test.go
│ │ ├── search_test.go
│ │ ├── test/
│ │ │ └── types.go
│ │ ├── util.go
│ │ └── web_features_manifest_cache.go
│ ├── receiver/
│ │ ├── api.go
│ │ ├── api_cloud_test.go
│ │ ├── api_medium_test.go
│ │ ├── azure.go
│ │ ├── azure_test.go
│ │ ├── client/
│ │ │ ├── client.go
│ │ │ └── client_test.go
│ │ ├── create_run.go
│ │ ├── create_run_test.go
│ │ ├── gcs.go
│ │ ├── handlers.go
│ │ ├── mock_receiver/
│ │ │ └── api_mock.go
│ │ ├── receive_results.go
│ │ ├── receive_results_test.go
│ │ ├── routes.go
│ │ ├── update_pending_run.go
│ │ └── update_pending_run_test.go
│ ├── results_redirect_handler.go
│ ├── routes.go
│ ├── screenshot/
│ │ ├── cache.go
│ │ ├── model.go
│ │ ├── model_medium_test.go
│ │ └── routes.go
│ ├── screenshot_redirect_handler.go
│ ├── shas.go
│ ├── shas_medium_test.go
│ ├── taskcluster/
│ │ ├── mock_taskcluster/
│ │ │ └── webhook_mock.go
│ │ ├── routes.go
│ │ ├── webhook.go
│ │ └── webhook_test.go
│ ├── test_history.go
│ ├── test_history_test.go
│ ├── test_run.go
│ ├── test_run_medium_test.go
│ ├── test_runs.go
│ ├── test_runs_medium_test.go
│ ├── user.go
│ ├── versions.go
│ └── versions_medium_test.go
├── docs/
│ ├── admin.md
│ ├── api.md
│ ├── app-engine.md
│ ├── cache.md
│ ├── docker.md
│ ├── gcs.md
│ ├── triaging.md
│ ├── ui.md
│ └── upgrading-go.md
├── git/
│ └── hooks/
│ ├── README.md
│ └── pre-push
├── go.mod
├── go.sum
├── results-processor/
│ ├── .gcloudignore
│ ├── .gitignore
│ ├── .python-version
│ ├── Dockerfile
│ ├── README.md
│ ├── app.staging.yaml
│ ├── app.yaml
│ ├── config.py
│ ├── gsutil.py
│ ├── main.py
│ ├── mypy.ini
│ ├── processor.py
│ ├── processor_test.py
│ ├── requirements.in
│ ├── requirements.txt
│ ├── test_server.py
│ ├── test_util.py
│ ├── tox.ini
│ ├── wptreport.py
│ ├── wptreport_test.py
│ ├── wptscreenshot.py
│ └── wptscreenshot_test.py
├── scripts/
│ ├── README.md
│ ├── check_chromium_revision.py
│ ├── process_test_history.py
│ └── update_chromium_revision.py
├── shared/
│ ├── appengine.go
│ ├── appengine_test.go
│ ├── browsers.go
│ ├── browsers_test.go
│ ├── cache.go
│ ├── cache_test.go
│ ├── datastore.go
│ ├── datastore_cached.go
│ ├── datastore_cloud.go
│ ├── datastore_medium_test.go
│ ├── errors.go
│ ├── errors_test.go
│ ├── fetch_bsf.go
│ ├── fetch_bsf_test.go
│ ├── fetch_runs.go
│ ├── github_oauth.go
│ ├── logger.go
│ ├── manifest.go
│ ├── manifest_test.go
│ ├── metadata.go
│ ├── metadata_test.go
│ ├── metadata_util.go
│ ├── metadata_util_test.go
│ ├── metrics/
│ │ ├── models.go
│ │ └── models_test.go
│ ├── models.go
│ ├── models_test.go
│ ├── params.go
│ ├── params_test.go
│ ├── product_spec.go
│ ├── request_caching.go
│ ├── request_caching_test.go
│ ├── routing.go
│ ├── run_diff.go
│ ├── run_diff_test.go
│ ├── secret_manager.go
│ ├── secret_manager_cloud.go
│ ├── secret_manager_cloud_cloud_test.go
│ ├── sharedtest/
│ │ ├── README.md
│ │ ├── appengine_mock.go
│ │ ├── cache_mock.go
│ │ ├── datastore_mock.go
│ │ ├── fetch_bsf_mock.go
│ │ ├── github_oauth_mock.go
│ │ ├── io.go
│ │ ├── metadata_util_mock.go
│ │ ├── run_diff_mock.go
│ │ ├── test_run_query_mock.go
│ │ ├── triage_metadata_mock.go
│ │ └── util.go
│ ├── statuses.go
│ ├── statuses_test.go
│ ├── tag_test.go
│ ├── test_run_filter.go
│ ├── test_run_filter_test.go
│ ├── test_run_query.go
│ ├── test_run_query_medium_test.go
│ ├── triage_metadata.go
│ ├── triage_metadata_test.go
│ ├── util.go
│ ├── util_test.go
│ ├── web_features.go
│ ├── web_features_manifest_github_download.go
│ ├── web_features_manifest_github_download_test.go
│ ├── web_features_manifest_util.go
│ ├── web_features_manifest_util_test.go
│ └── web_features_test.go
├── util/
│ ├── __init__.py
│ ├── add_production_run.py
│ ├── cleanup-versions.sh
│ ├── commands.sh
│ ├── crontab-example
│ ├── deploy-comment.sh
│ ├── deploy-production.sh
│ ├── deploy-staging.sh
│ ├── deploy.sh
│ ├── docker-dev/
│ │ ├── dev_data.sh
│ │ ├── run.sh
│ │ └── web_server.sh
│ ├── generate_testrun_index.py
│ ├── gs-cors.json
│ ├── logging.sh
│ ├── populate_dev_data.go
│ ├── pull_run_into_static.py
│ ├── server-watch.sh
│ ├── tools.go
│ └── wct.sh
├── webapp/
│ ├── .gitignore
│ ├── README.md
│ ├── about_handler.go
│ ├── about_handler_medium_test.go
│ ├── admin_handler.go
│ ├── admin_handler_test.go
│ ├── analyzer_handler.go
│ ├── components/
│ │ ├── browser-picker.js
│ │ ├── channel-picker.js
│ │ ├── compat-2021.js
│ │ ├── display-logo.js
│ │ ├── github-login.js
│ │ ├── info-banner.js
│ │ ├── interop-dashboard.js
│ │ ├── interop-data-manager.js
│ │ ├── interop-data.js
│ │ ├── interop-feature-chart.js
│ │ ├── interop-summary.js
│ │ ├── interop.js
│ │ ├── loading-state.js
│ │ ├── ohm.js
│ │ ├── path.js
│ │ ├── pluralize.js
│ │ ├── product-builder.js
│ │ ├── product-info.js
│ │ ├── reftest-analyzer.js
│ │ ├── results-navigation.js
│ │ ├── self-navigator.js
│ │ ├── test/
│ │ │ ├── fixtures/
│ │ │ │ ├── interop.json
│ │ │ │ └── passrates.json
│ │ │ ├── interop-data.html
│ │ │ ├── loading-state.html
│ │ │ ├── path.html
│ │ │ ├── product-builder.html
│ │ │ ├── product-info.html
│ │ │ ├── reftest-analyzer.html
│ │ │ ├── test-file-results-table.html
│ │ │ ├── test-file-results.html
│ │ │ ├── test-run.html
│ │ │ ├── test-runs-query-builder.html
│ │ │ ├── test-runs-query.html
│ │ │ ├── test-runs.html
│ │ │ ├── test-search.html
│ │ │ ├── test-utils.html
│ │ │ ├── util/
│ │ │ │ └── helpers.js
│ │ │ ├── wpt-amend-metadata.html
│ │ │ ├── wpt-app.html
│ │ │ ├── wpt-flags.html
│ │ │ ├── wpt-metadata.html
│ │ │ ├── wpt-permalinks.html
│ │ │ └── wpt-results.html
│ │ ├── test-file-results-table.js
│ │ ├── test-file-results.js
│ │ ├── test-info.js
│ │ ├── test-results-history-timeline.js
│ │ ├── test-run.js
│ │ ├── test-runs-query-builder.js
│ │ ├── test-runs-query.js
│ │ ├── test-runs.js
│ │ ├── test-search.js
│ │ ├── utils.js
│ │ ├── wpt-amend-metadata.js
│ │ ├── wpt-bsf.js
│ │ ├── wpt-colors.js
│ │ ├── wpt-flags.js
│ │ ├── wpt-header.js
│ │ ├── wpt-insights.js
│ │ ├── wpt-metadata.js
│ │ ├── wpt-permalinks.js
│ │ ├── wpt-processor.js
│ │ └── wpt-runs.js
│ ├── components_handler.go
│ ├── components_handler_test.go
│ ├── dynamic-components/
│ │ ├── templates/
│ │ │ └── wpt-env-flags.js
│ │ └── wpt-env-flags.js
│ ├── dynamic_components_handler.go
│ ├── eslint.config.mjs
│ ├── flags_handler.go
│ ├── insights_handler.go
│ ├── interop_handler.go
│ ├── interop_handler_test.go
│ ├── login.go
│ ├── login_test.go
│ ├── package.json
│ ├── processor.go
│ ├── routes.go
│ ├── static/
│ │ ├── common.css
│ │ ├── interop-2021-experimental.csv
│ │ ├── interop-2021-stable.csv
│ │ ├── interop-2022-experimental.csv
│ │ ├── interop-2022-stable.csv
│ │ ├── interop-2023-experimental.csv
│ │ ├── interop-2023-stable.csv
│ │ ├── interop-2024-experimental.csv
│ │ ├── interop-2024-mobile-experimental.csv
│ │ ├── interop-2024-stable.csv
│ │ ├── interop-2025-experimental.csv
│ │ ├── interop-2025-mobile-experimental.csv
│ │ ├── interop-2025-stable.csv
│ │ ├── interop-data.json
│ │ ├── robots.txt
│ │ └── wptd-metrics/
│ │ └── 0-0/
│ │ ├── chrome-failures.json
│ │ ├── edge-failures.json
│ │ ├── firefox-failures.json
│ │ ├── pass-rates.json
│ │ └── safari-failures.json
│ ├── template.go
│ ├── templates/
│ │ ├── _ga.html
│ │ ├── _head_common.html
│ │ ├── _test_run_query_params.html
│ │ ├── _test_run_ui_query_params.html
│ │ ├── about.html
│ │ ├── admin_flags.html
│ │ ├── admin_upload.html
│ │ ├── analyzer.html
│ │ ├── compat-2021.html
│ │ ├── flags.html
│ │ ├── index.html
│ │ ├── insights.html
│ │ ├── interop.html
│ │ ├── processor.html
│ │ └── test-runs.html
│ ├── test_results_handler.go
│ ├── test_results_handler_medium_test.go
│ ├── test_runs_handler.go
│ ├── views/
│ │ ├── wpt-404.js
│ │ ├── wpt-app.js
│ │ └── wpt-results.js
│ ├── wct.conf.json
│ └── web/
│ ├── .gcloudignore
│ ├── Dockerfile
│ ├── app.staging.yaml
│ ├── app.yaml
│ ├── dispatch.yaml
│ ├── index.yaml
│ ├── main.go
│ ├── nginx.conf
│ ├── queue.yaml
│ └── routes_test.go
└── webdriver/
├── README.md
├── appserver.js
├── builder_test.go
├── chrome.go
├── datastore.js
├── dev-data.js
├── file_results_test.go
├── firefox.go
├── label_test.go
├── package.json
├── path-test.js
├── path_test.go
├── product_test.go
├── search_test.go
├── test_runs_test.go
├── util.js
├── webapp_server.go
├── webdriver.go
└── webdriver.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/actions/make-in-docker/action.yml
================================================
name: Run make in Docker
description: Run a make target inside a container created from Dockerfile
inputs:
target:
description: Target to make
required: true
runs:
using: docker
image: docker://webplatformtests/wpt.fyi:latest
args:
- /usr/bin/make
- ${{ inputs.target }}
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "pip"
directory: "/results-processor"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
ignore:
# https://github.com/web-platform-tests/wpt.fyi/commit/e52c7487ac4257ba39f8f081782a6443e9fd6a79
- dependency-name: "google.golang.org/genproto"
- package-ecosystem: "npm"
directory: "/webapp"
schedule:
interval: "weekly"
ignore:
# https://github.com/web-platform-tests/wpt.fyi/commit/9b99cfd70568dc8d991d2b13ad9c5aec53c390a6
- dependency-name: "@vaadin/vaadin-grid"
- dependency-name: "@vaadin/vaadin-date-picker"
- dependency-name: "@vaadin/vaadin-context-menu"
- package-ecosystem: "npm"
directory: "/webdriver"
schedule:
interval: "weekly"
ignore:
# https://github.com/web-platform-tests/wpt.fyi/commit/9b99cfd70568dc8d991d2b13ad9c5aec53c390a6
- dependency-name: "@vaadin/vaadin-grid"
- dependency-name: "@vaadin/vaadin-date-picker"
- dependency-name: "@vaadin/vaadin-context-menu"
- package-ecosystem: "docker"
directory: "/results-processor"
schedule:
interval: "weekly"
# Results Processor Docker image should ignore major and minor updates to Docker Python Image
# There may be deprecations moving between minor vesrions that we need to
# test.
ignore:
- dependency-name: "*"
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
# Webapp/Developer Docker image should ignore major and minor updates to Docker Go Image.
# Go versions are backwards compatible but we want to stay with the
# major.minor version supported by App Engine Standard. That should be
# updated manually.
ignore:
- dependency-name: "*"
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
- package-ecosystem: "docker"
directory: "/api/query/cache/service"
schedule:
interval: "weekly"
# Searchcache Docker image should ignore major and minor updates to Docker Go Image
# Searchcache follows the bring-your-own-container paradigm because it uses
# App Engine Flex. While we could use the latest version, we want this Go
# version to follow the same version used in the webapp above (which uses
# App Engine Standard).
ignore:
- dependency-name: "*"
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
- package-ecosystem: "docker"
directory: "/webapp/web"
schedule:
interval: "weekly"
# Searchcache Docker image should ignore major and minor updates to Docker Go Image
# Searchcache follows the bring-your-own-container paradigm because it uses
# App Engine Flex. While we could use the latest version, we want this Go
# version to follow the same version used in the webapp above (which uses
# App Engine Standard).
ignore:
- dependency-name: "*"
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
================================================
FILE: .github/workflows/ci.yml
================================================
name: Continuous Integration
on:
push:
branches:
- main
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker config check
uses: dorny/paths-filter@v3
id: dockerchanges
with:
filters: |
dockerconf:
- 'Dockerfile'
# run only if Docker configuration was changed
- if: steps.dockerchanges.outputs.dockerconf == 'true'
name: Rebuild Docker image
run: docker build -t webplatformtests/wpt.fyi:latest .
- uses: ./.github/actions/make-in-docker
with:
target: lint
python_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker config check
uses: dorny/paths-filter@v3
id: dockerchanges
with:
filters: |
dockerconf:
- 'Dockerfile'
# run only if Docker configuration was changed
- if: steps.dockerchanges.outputs.dockerconf == 'true'
name: Rebuild Docker image
run: docker build -t webplatformtests/wpt.fyi:latest .
- uses: ./.github/actions/make-in-docker
with:
target: python_test
go_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker config check
uses: dorny/paths-filter@v3
id: dockerchanges
with:
filters: |
dockerconf:
- 'Dockerfile'
# run only if Docker configuration was changed
- if: steps.dockerchanges.outputs.dockerconf == 'true'
name: Rebuild Docker image
run: docker build -t webplatformtests/wpt.fyi:latest .
- uses: ./.github/actions/make-in-docker
with:
target: go_test
web_components_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker config check
uses: dorny/paths-filter@v3
id: dockerchanges
with:
filters: |
dockerconf:
- 'Dockerfile'
# run only if Docker configuration was changed
- if: steps.dockerchanges.outputs.dockerconf == 'true'
name: Rebuild Docker image
run: docker build -t webplatformtests/wpt.fyi:latest .
- uses: ./.github/actions/make-in-docker
with:
target: web_components_test
go_chrome_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker config check
uses: dorny/paths-filter@v3
id: dockerchanges
with:
filters: |
dockerconf:
- 'Dockerfile'
# run only if Docker configuration was changed
- if: steps.dockerchanges.outputs.dockerconf == 'true'
name: Rebuild Docker image
run: docker build -t webplatformtests/wpt.fyi:latest .
- uses: ./.github/actions/make-in-docker
with:
target: go_chrome_test
go_firefox_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker config check
uses: dorny/paths-filter@v3
id: dockerchanges
with:
filters: |
dockerconf:
- 'Dockerfile'
# run only if Docker configuration was changed
- if: steps.dockerchanges.outputs.dockerconf == 'true'
name: Rebuild Docker image
run: docker build -t webplatformtests/wpt.fyi:latest .
- uses: ./.github/actions/make-in-docker
with:
target: go_firefox_test
go_cloud_test:
# This job uses real Cloud resources.
# This means this CI job will have access to the service account.
# In that case, similar to deploy.yml, trust only pull requests that are
# made within web-platform-tests and exclude forks.
if: |
(github.repository == 'web-platform-tests/wpt.fyi') &&
((github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'web-platform-tests/wpt.fyi' && github.actor != 'dependabot[bot]') ||
(github.event_name != 'pull_request'))
needs: [go_test, go_chrome_test, go_firefox_test]
runs-on: ubuntu-latest
env:
DOCKER_IMAGE: webplatformtests/wpt.fyi:latest
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: secrets
run: echo "$GCLOUD_KEY_FILE_JSON" > client-secret.json
env:
GCLOUD_KEY_FILE_JSON: ${{ secrets.GCLOUD_KEY_FILE_JSON }}
- name: Set DOCKER_INSTANCE
run: echo "DOCKER_INSTANCE=wptd-dev-$(echo $RANDOM)" >> $GITHUB_ENV
- name: Docker config check
uses: dorny/paths-filter@v3
id: dockerchanges
with:
filters: |
dockerconf:
- 'Dockerfile'
# run only if Docker configuration was changed
- if: steps.dockerchanges.outputs.dockerconf == 'true'
name: Rebuild Docker image
run: docker build -t webplatformtests/wpt.fyi:latest .
# run only if Docker configuration was not changed
- if: steps.dockerchanges.outputs.dockerconf == 'false'
name: Fetch latest Docker image
run: docker pull "${DOCKER_IMAGE}"
- name: pre-installation
run: bash ./util/docker-dev/run.sh -d -q
- name: run tests with "cloud" build tag
run: docker exec -t "${DOCKER_INSTANCE}" make go_cloud_test;
================================================
FILE: .github/workflows/codeql.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "main" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "main" ]
schedule:
- cron: '40 20 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go', 'javascript', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
================================================
FILE: .github/workflows/deploy.yml
================================================
name: Deploy
on:
push:
branches:
- main
pull_request:
jobs:
deploy-staging:
# Forks and dependabot cannot access secrets so the job would fail.
# Run for non dependabot PRs or regular pushes to web-platform-tests/wpt.fyi
if: |
(github.repository == 'web-platform-tests/wpt.fyi') &&
((github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'web-platform-tests/wpt.fyi' && github.actor != 'dependabot[bot]') ||
(github.event_name != 'pull_request'))
name: Deploy staging.wpt.fyi
runs-on: ubuntu-latest
env:
DOCKER_IMAGE: webplatformtests/wpt.fyi:latest
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: secrets
run: echo "$GCLOUD_KEY_FILE_JSON" > client-secret.json
env:
GCLOUD_KEY_FILE_JSON: ${{ secrets.GCLOUD_KEY_FILE_JSON }}
- name: Set DOCKER_INSTANCE
run: echo "DOCKER_INSTANCE=wptd-dev-$(echo $RANDOM)" >> $GITHUB_ENV
- name: Docker config check
uses: dorny/paths-filter@v3
id: dockerchanges
with:
filters: |
dockerconf:
- 'Dockerfile'
# run only if Docker configuration was changed
- if: steps.dockerchanges.outputs.dockerconf == 'true'
name: Rebuild Docker image
run: docker build -t webplatformtests/wpt.fyi:latest .
# run only if Docker configuration was not changed
- if: steps.dockerchanges.outputs.dockerconf == 'false'
name: Fetch latest Docker image
run: docker pull "${DOCKER_IMAGE}"
- name: pre-installation
run: bash ./util/docker-dev/run.sh -d -q
- name: installation
run: docker exec -t "${DOCKER_INSTANCE}" make go_build;
# Set -f for main branch.
- name: set deployment flag
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
run: echo "FORCE_DEPLOYMENT=-f" >> $GITHUB_ENV
- name: deploy webapp
run: ./util/deploy-staging.sh "${FORCE_DEPLOYMENT}" webapp/web/app.staging.yaml
- name: Run go_large_test in main
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
run: docker exec -t "${DOCKER_INSTANCE}" make go_large_test STAGING=true
- name: build processor
run: ./util/deploy-staging.sh "${FORCE_DEPLOYMENT}" results-processor/app.staging.yaml
- name: build searchcache
run: ./util/deploy-staging.sh "${FORCE_DEPLOYMENT}" api/query/cache/service/app.staging.yaml
- name: Clean up versions in main
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
run: docker exec -t "${DOCKER_INSTANCE}" make cleanup_staging_versions
================================================
FILE: .github/workflows/docker-update.yml
================================================
name: Update Docker image
on:
push:
# Rebuild the image when Dockerfile is changed. This is safe on a PR
# branch, too -- the automatically built Docker image will be tagged with
# the branch name instead of "latest".
paths:
- 'Dockerfile'
- '.github/workflows/docker-update.yml'
schedule:
# Rebuild the image weekly.
- cron: '0 0 * * 0'
jobs:
build-and-push:
# Forks and dependabot cannot access secrets so the job would fail.
# Run for non dependabot PRs or regular pushes to web-platform-tests/wpt.fyi
if: |
(github.repository == 'web-platform-tests/wpt.fyi' && github.actor != 'dependabot[bot]') &&
((github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'web-platform-tests/wpt.fyi') ||
(github.event_name != 'pull_request'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: elgohr/Publish-Docker-Github-Action@v5
# https://github.com/elgohr/Publish-Docker-Github-Action
with:
name: webplatformtests/wpt.fyi
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
dockerfile: Dockerfile
snapshot: true
================================================
FILE: .gitignore
================================================
node_modules/
debug.test
/web
# Google Cloud secret
client-secret.json
================================================
FILE: .golangci.yaml
================================================
version: "2"
linters:
default: none
enable:
- containedctx
- copyloopvar
- dogsled
- dupl
- errcheck
- errname
- errorlint
- exhaustive
- exhaustruct
- gochecknoglobals
- gocognit
- goconst
- gocyclo
- godot
- godox
- goheader
- gomoddirectives
- gosec
- govet
- importas
- ineffassign
- ireturn
- lll
- misspell
- nakedret
- nestif
- nilerr
- nilnil
- nlreturn
- noctx
- prealloc
- revive
- staticcheck
- unparam
- unused
- usestdlibvars
settings:
exhaustruct:
exclude:
- github\.com/google/go-github/v65/github\.CheckRunOutput
- github\.com/google/go-github/v65/github\.ListCheckRunsOptions
- github\.com/google/go-github/v65/github\.ListOptions
- github\.com/golang-jwt/jwt\.StandardClaims
- net/http\.Client
gomoddirectives:
replace-allow-list:
- launchpad.net/gocheck
gosec:
excludes:
# TODO(DanielRyanSmith): Remove these exclusions after this PR is part
# of the new version: https://github.com/securego/gosec/pull/1506
- G704
- G705
# TODO(jrobbins): Remove these exclusions after looking more into
# code changes needed to resolve them.
- G118
- G120
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gofmt
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
================================================
FILE: .vscode/launch.json
================================================
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Web server",
"type": "go",
"request": "attach",
"port": 12345,
"host": "localhost",
"mode": "remote",
"debugAdapter": "dlv-dap",
"dlvFlags": ["--check-go-version=false"],
"substitutePath": [
{
"from": "${workspaceFolder}", "to": "/home/user/wpt.fyi"
}
]
}
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"go.buildTags": "small,medium,large,cloud",
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"webapp/static": true
},
"debug.node.autoAttach": "on",
"go.formatTool": "goimports"
}
================================================
FILE: .vscode/tasks.json
================================================
{
"version": "2.0.0",
"tasks": [
{
"label": "Build",
"type": "shell",
"command": "make build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$go"
]
},
{
"label": "Install WebDriver Deps",
"type": "shell",
"command": "make chrome && make chromedriver",
},
{
"label": "Webdriver Single Chrome Test",
"type": "shell",
"command": "go test -v -timeout=15m -tags=large ./webdriver -run ${input:testName} -args -chrome_path=/usr/bin/google-chrome -chromedriver_path=/usr/bin/chromedriver -frame_buffer=false -staging=false -browser=chrome",
"group": {
"kind": "test",
"isDefault": true
},
"dependsOn": [
"Install WebDriver Deps"
],
"problemMatcher": [
"$go"
]
},
{
"label": "Webdriver Chrome Tests",
"type": "shell",
"command": "go test -v -timeout=15m -tags=large ./webdriver -args -chrome_path=/usr/bin/google-chrome -chromedriver_path=/usr/bin/chromedriver -frame_buffer=false -staging=false -browser=chrome",
"group": {
"kind": "test",
"isDefault": true
},
"dependsOn": [
"Install WebDriver Deps"
],
"problemMatcher": [
"$go"
]
}
],
"inputs": [
{
"id": "testName",
"type": "promptString",
"description": "Enter the test function name"
}
]
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct
All code and communication under WPT Dashboard is covered by the [Chromium Code of Conduct](https://chromium.googlesource.com/chromium/src/+/master/CODE_OF_CONDUCT.md).
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.
# Local Development
## Linting your code
There is a `make` rule for linting. Requirements for it are included in the docker image.
```sh
source util/commands.sh
wptd_exec_it make lint
```
To run outside docker, you'll need to install `golint` and `eslint`.
Globally (in `wpt.fyi` root):
```sh
npm install -g eslint babel-eslint eslint-plugin-html
make test
```
Locally (in `webapp/` dir):
```sh
npm install
npm test
```
## Testing your code
There is a number of `make` rule for testing. To run tests in docker:
```sh
source util/commands.sh
wptd_exec_it make test
```
See [`Makefile`](/Makefile) for more fine grained targets which take less time to run.
## Git prepush
You should set up your repo to run `make prepush` in docker when you're pushing, to help catch trivial build/lint errors.
See [the git hooks folder](/git/hooks) for instructions.
# Coding Guidelines
## License header
All source files (including `.js`, `.go`, `.html`, `.css`) must begin with a comment of the below header:
```go
// Copyright {YEAR} The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
```
================================================
FILE: Dockerfile
================================================
# vim: set expandtab sw=4
FROM golang:1.26.2-bookworm
# Create a non-priviledged user to run browsers as (Firefox and Chrome do not
# like to run as root).
RUN chmod a+rx $HOME && useradd --uid 9999 --user-group --create-home browser
# Add apt repositories for Java, Node.js and Google Cloud CLI
RUN export DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) && \
echo "deb [signed-by=/usr/share/keyrings/corretto.gpg] https://apt.corretto.aws stable main" > /etc/apt/sources.list.d/corretto.list && \
curl -s https://apt.corretto.aws/corretto.key | gpg --dearmor -o /usr/share/keyrings/corretto.gpg && \
export NODE_VERSION="20.x" && \
export ARCH=$(dpkg --print-architecture) && \
echo "deb [arch=$ARCH signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_VERSION nodistro main" > /etc/apt/sources.list.d/nodesource.list && \
curl -s https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /usr/share/keyrings/nodesource.gpg && \
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk-$DISTRO_CODENAME main" > /etc/apt/sources.list.d/google-cloud-sdk.list && \
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
# Sort the package names!
# firefox-esr: provides deps for Firefox (we don't use ESR directly)
# java-11-amazon-corretto-jdk: provides JDK/JRE to Selenium & gcloud SDK
# python-crcmod: native module to speed up CRC checksum in gsutil
RUN apt-get update -qqy && apt-get install -qqy --no-install-suggests \
curl \
firefox-esr \
java-11-amazon-corretto-jdk \
nodejs \
python3.11 \
python3-crcmod \
sudo \
tox \
wget \
xvfb && \
rm /usr/bin/firefox
# The base golang image adds Go paths to PATH, which cannot be inherited in
# sudo by default because of the `secure_path` directive. Overwrite sudoers to
# discard the setting.
RUN echo "root ALL=(ALL:ALL) ALL" > /etc/sudoers
# We must stick to 527.0.0 because the datastore emulator only requires Java 11.
# Versions 528.0.0 and onwards require Java 21.
# However, we can't upgrade to a newer version of Java because when Chrome
# runs with WCT/Selenium, it only runs with java 11 and not 17 or 21.
ENV CLOUD_SDK_VERSION=527.0.0
# Google Cloud SDK configuration
# Based on https://github.com/GoogleCloudPlatform/cloud-sdk-docker/blob/master/Dockerfile
RUN apt-get update -qqy && apt-get install -qqy --no-install-suggests \
google-cloud-cli=${CLOUD_SDK_VERSION}-0 \
google-cloud-cli-app-engine-python=${CLOUD_SDK_VERSION}-0 \
google-cloud-cli-app-engine-python-extras=${CLOUD_SDK_VERSION}-0 \
google-cloud-cli-app-engine-go=${CLOUD_SDK_VERSION}-0 \
google-cloud-cli-datastore-emulator=${CLOUD_SDK_VERSION}-0 && \
gcloud config set core/disable_usage_reporting true && \
gcloud config set component_manager/disable_update_check true && \
gcloud --version
================================================
FILE: ISSUE_TEMPLATE/checks.md
================================================
### Check
A link to the GitHub Check run containing my issue:
https://github.com/web-platform-tests/wpt/pull/[PR Number]/checks?check_run_id=[Check run ID]
### Description
<!--
Please provide a description of the issue that you are observing, along with any
more fine-grained links (such as specific test folders/views on wpt.fyi).
-->
================================================
FILE: ISSUE_TEMPLATE/prod-deployment.md
================================================
Previous deployment was #ISSUE_NUM (PREV_SHA)
Changelist PREV_SHA...NEW_SHA
Major changes:
- A pull request title (#PR_NUM)
- A different pull request title (#PR_NUM2)
This push is happening as part of the regular weekly push.
Pushing all three services - webapp, processor, and searchcache.
================================================
FILE: ISSUE_TEMPLATE/screenshots.md
================================================
<!-- Note that runs before 2019-04-01 might not have complete screenshots. -->
### Example
Permalink to an example reftest:
<!-- You can easily get the permalink using the "LINK" dialog. Please ensure you select "These runs". -->
Link to the reftest analyzer:
<!-- The URL after click "COMPARE". -->
### Description
<!-- Please provide a description of the issue that you are observing, e.g. missing screenshots, feature requests. -->
================================================
FILE: ISSUE_TEMPLATE/search.md
================================================
### Search
A link to the search containing my issue:
<!-- You can easily get the permalink using the "LINK" dialog. Please ensure you select "These runs". -->
### Description
<!-- Please provide a description of the issue that you are observing -->
================================================
FILE: ISSUE_TEMPLATE.md
================================================
<!--
This project's primary focus is visualizing test results. It is not responsible
for collecting web-platform-tests. The data is uploaded by external services,
primarily from https://github.com/web-platform-tests/wpt . Issues regarding the
collection methodology and/or accuracy of the data should be filed there.
-->
================================================
FILE: LICENSE
================================================
W3C 3-clause BSD License
http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of works must retain the original copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the original copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the W3C nor the names of its contributors may be
used to endorse or promote products derived from this work without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: Makefile
================================================
# Copyright 2017 The WPT Dashboard Project. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Make targets in this file are intended to be run inside the Docker container
# environment.
# Make targets can be run in a host environment, but that requires ensuring
# the correct version of tools are installed and environment variables are
# set appropriately.
# Prefer simply expanded variables (:=) to avoid confusion caused by recursion.
# All variables can be overridden in command line by `make target FOO=bar`.
SHELL := /bin/bash
# WPTD_PATH will have a trailing slash, e.g. /home/user/wpt.fyi/
WPTD_PATH := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
GECKODRIVER_TAG := v0.36.0
GECKODRIVER_PATH=/usr/bin/geckodriver
FIREFOX_PATH := /usr/bin/firefox
CHROME_VERSION := 138.0.7204.94
CHROME_INSTALL_DIR := /opt/chrome-for-testing
# CFT_BINARY can also be 'chrome-headless-shell'
CFT_BINARY := chrome
CFT_FOLDER := $(CFT_BINARY)-linux64
CHROME_ACTUAL_PATH := $(CHROME_INSTALL_DIR)/$(CFT_FOLDER)/$(CFT_BINARY)
# Needed because some tools are hardcoded to /usr/bin/google-chrome
CHROME_PATH := /usr/bin/google-chrome
CHROMEDRIVER_PATH=/usr/bin/chromedriver
USE_FRAME_BUFFER := true
STAGING := false
VERBOSE := -v
GO_FILES := $(shell find $(WPTD_PATH) -type f -name '*.go')
GO_TEST_FILES := $(shell find $(WPTD_PATH) -type f -name '*_test.go')
# Golangci version should be updated periodically.
# See: https://golangci-lint.run/welcome/install/
GOLANGCI_LINT_VERSION := v2.1.6
build: go_build
test: go_test python_test
lint: eslint go_lint golangci_lint # TODO: Replace go_lint with golangci_lint
prepush: VERBOSE := $() # Empty out the verbose flag.
prepush: go_build go_test lint
python_test: python3 tox
tox -c results-processor/
# Contains setup necessary only for github actions.
github_action_go_setup:
# https://github.com/web-platform-tests/wpt.fyi/issues/3089
if [ -d "/github/workspace" ]; then \
echo "Avoiding buildvcs error for Go 1.18+ by marking github workspace safe."; \
git config --global --add safe.directory /github/workspace ; \
else \
echo "Did not detect github workspace. Skipping." ; \
fi
# NOTE: We prune before generate, because node_modules are embedded into the
# binary (and part of the build).
go_build: git mockgen github_action_go_setup webapp_node_modules_prod
go generate ./...
# Check all packages without producing any output.
go build -v ./...
# Build the webapp.
go build -v ./webapp/web
go_build_dev:
@ # Disable packr to always serve local node modules and dynamic components.
@ # There's thus no need to prune node_modules.
@ # Disable inlining and optimizations that can interfere with debugging.
go build -v -tags skippackr -gcflags=all="-N -l" ./webapp/web
go_lint: golint go_test_tag_lint
golint -set_exit_status ./api/...
golint -set_exit_status ./shared/...
golint -set_exit_status ./util/...
golint -set_exit_status ./webapp/...
golint -set_exit_status ./webdriver/...
# TODO: run on /shared/, /util/, /webapp/, /webdriver/
golangci_lint: golangci-lint github_action_go_setup
golangci-lint cache clean
golangci-lint run ./api/...
go_test_tag_lint:
@ # Printing a list of test files without +build tag, asserting empty...
@TAGLESS=$$(grep -PL '\/\/(\s?\+build|go:build) !?(small|medium|large|cloud)' $(GO_TEST_FILES)); \
if [ -n "$$TAGLESS" ]; then echo -e "Files are missing '// +build TAG' or '//go:build TAG' tags:\n$$TAGLESS" && exit 1; fi
go_test: go_small_test go_medium_test
go_small_test: go_build gcc
go test -tags=small $(VERBOSE) ./...
go_medium_test: go_build dev_appserver_deps gcc
go test -tags=medium $(VERBOSE) $(FLAGS) ./...
# Use sub-make because otherwise make would only execute the first invocation
# of _go_webdriver_test. Variables will be passed into sub-make implicitly.
go_large_test:
make go_firefox_test
make go_chrome_test
go_firefox_test: firefox geckodriver
make _go_webdriver_test BROWSER=firefox
go_chrome_test: chrome chromedriver
make _go_webdriver_test BROWSER=chrome
go_cloud_test: go_build gcloud_login
gcloud config set project wptdashboard-staging; \
if [[ -f "$(WPTD_PATH)client-secret.json" ]]; then \
echo "Running with client-secret.json credentials instead of possible system credentials. This should happen for CI runs."; \
export GOOGLE_APPLICATION_CREDENTIALS="$(WPTD_PATH)client-secret.json"; \
fi ; \
GOOGLE_CLOUD_PROJECT=wptdashboard-staging GAE_SERVICE=test GAE_VERSION=1 go test -tags=cloud $(VERBOSE) $(FLAGS) ./...
puppeteer_chrome_test: go_build dev_appserver_deps webdriver_node_deps
cd webdriver; npm test
webdriver_node_deps:
cd webdriver; npm install
# _go_webdriver_test is not intended to be used directly; use go_firefox_test or
# go_chrome_test instead.
_go_webdriver_test: var-BROWSER java go_build xvfb geckodriver chromedriver dev_appserver_deps gcc
@ # This Go test manages Xvfb itself, so we don't start/stop Xvfb for it.
@ # The following variables are defined here because we don't know the
@ # path before installing geckodriver as it includes version strings.
GECKODRIVER_PATH=$(GECKODRIVER_PATH) \
COMMAND="go test $(VERBOSE) -timeout=15m -tags=large ./webdriver -args \
-firefox_path=$(FIREFOX_PATH) \
-geckodriver_path=$$GECKODRIVER_PATH \
-chrome_path=$(CHROME_PATH) \
-chromedriver_path=$(CHROMEDRIVER_PATH) \
-frame_buffer=$(USE_FRAME_BUFFER) \
-staging=$(STAGING) \
-browser=$(BROWSER) $(FLAGS)"; \
if [ "$$UID" == "0" ]; then sudo -u browser $$COMMAND; else $$COMMAND; fi
# NOTE: psmisc includes killall, needed by wct.sh
web_components_test: xvfb firefox chrome webapp_node_modules_all psmisc
util/wct.sh $(USE_FRAME_BUFFER)
dev_appserver_deps: gcloud-app-engine-go gcloud-cloud-datastore-emulator gcloud-beta java
chrome: wget unzip
if [[ ! -f "$(CHROME_ACTUAL_PATH)" ]]; then \
CHROME_CFT_URL="https://storage.googleapis.com/chrome-for-testing-public/$(CHROME_VERSION)/linux64/$(CFT_FOLDER).zip"; \
TEMP_DIR=$$(mktemp -d); \
wget -q -O $${TEMP_DIR}/$(CFT_FOLDER).zip $${CHROME_CFT_URL}; \
unzip -q $${TEMP_DIR}/$(CFT_FOLDER).zip -d $${TEMP_DIR}; \
sudo mkdir -p $(CHROME_INSTALL_DIR); \
sudo mv $${TEMP_DIR}/$(CFT_FOLDER) $(CHROME_INSTALL_DIR)/; \
sudo apt update; \
while read pkg ; do sudo apt-get satisfy -y --no-install-recommends "$${pkg}" ; done < $(CHROME_INSTALL_DIR)/$(CFT_FOLDER)/deb.deps; \
sudo chmod +x $(CHROME_ACTUAL_PATH); \
sudo ln -sf $(CHROME_ACTUAL_PATH) $(CHROME_PATH); \
rm -rf $${TEMP_DIR}; \
fi
# Pull ChromeDriver from Chrome For Testing (CfT)
# Need to create the CHROMEDRIVER_PATH and then move the files in because the
# directory structure in chromedriver_linux64.zip has changed.
#
# CfT only has ChromeDriver URLs for chrome versions >=115. But assuming `chrome`
# target above remains pulling the latest stable, this will not be a problem.
chromedriver: wget unzip chrome jq
if [[ ! -f "$(CHROMEDRIVER_PATH)" ]]; then \
CHROME_VERSION=$$(google-chrome --version | grep -ioE "[0-9]+\.[0-9]+\.[0-9]+"); \
CHROMEDRIVER_URL=$$(curl -s https://googlechromelabs.github.io/chrome-for-testing/latest-patch-versions-per-build-with-downloads.json | jq -r ".builds[\"$${CHROME_VERSION}\"].downloads.chromedriver[] | select(.platform == \"linux64\") | .url"); \
TEMP_DIR=$$(mktemp -d); \
wget -q -O $${TEMP_DIR}/chromedriver_linux64.zip $${CHROMEDRIVER_URL}; \
unzip -j $${TEMP_DIR}/chromedriver_linux64.zip -d $${TEMP_DIR}; \
sudo mv $${TEMP_DIR}/chromedriver $(CHROMEDRIVER_PATH); \
sudo chmod +x $(CHROMEDRIVER_PATH); \
fi
firefox: bzip2 wget
if [[ -z "$$(which firefox)" ]]; then \
wget -O firefox.tar.xz -q "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US"; \
mkdir -p $$HOME/browsers; \
tar -xaf firefox.tar.xz -C $$HOME/browsers; \
sudo ln -s $$HOME/browsers/firefox/firefox $(FIREFOX_PATH); \
fi
geckodriver: wget unzip curl jq
if [[ ! -f "$(GECKODRIVER_PATH)" ]]; then \
GECKODRIVER_URL="https://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_TAG}/geckodriver-${GECKODRIVER_TAG}-linux64.tar.gz"; \
TEMP_DIR=$$(mktemp -d); \
wget -q -O $${TEMP_DIR}/geckodriver-linux64.tar.gz $${GECKODRIVER_URL}; \
tar -xzf $${TEMP_DIR}/geckodriver-linux64.tar.gz -C $${TEMP_DIR}; \
sudo mv $${TEMP_DIR}/geckodriver $(GECKODRIVER_PATH); \
sudo chmod +x $(GECKODRIVER_PATH); \
rm -rf $${TEMP_DIR}; \
fi
golangci-lint: curl gpg
if [ "$$(which golangci-lint)" == "" ]; then \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/${GOLANGCI_LINT_VERSION}/install.sh | sh -s -- -b $$(go env GOPATH)/bin; \
fi
golint: git
if [ "$$(which golint)" == "" ]; then \
go install golang.org/x/lint/golint; \
fi
mockgen: git
if [ "$$(which mockgen)" == "" ]; then \
go install go.uber.org/mock/mockgen; \
fi
package_service: var-APP_PATH
# Trim the potential "app.staging.yaml" suffix.
if [[ "$(APP_PATH)" == "api/query/cache/service"* ]]; then \
APP_PATH="api/query/cache/service"; \
elif [[ "$(APP_PATH)" == "webapp/web"* ]]; then \
APP_PATH="webapp/web"; \
else \
APP_PATH="$(APP_PATH)"; \
fi ; \
if [[ "$${APP_PATH}" == "api/query/cache/service" || "$${APP_PATH}" == "webapp/web" ]]; then \
TMP_DIR=$$(mktemp -d); \
rm -rf $(WPTD_PATH)$${APP_PATH}/wpt.fyi; \
cp -r $(WPTD_PATH)* $${TMP_DIR}/; \
mkdir $(WPTD_PATH)$${APP_PATH}/wpt.fyi; \
cp -r $${TMP_DIR}/* $(WPTD_PATH)$${APP_PATH}/wpt.fyi/; \
rm -rf $${TMP_DIR}; \
fi
sys_deps: apt_update
make gcloud
make git
make node
apt_update:
sudo apt-get -qq update
bzip2: apt-get-bzip2
curl: apt-get-curl
gcc: apt-get-gcc
git: apt-get-git
jq: apt-get-jq
psmisc: apt-get-psmisc
python3: apt-get-python3.11
tox: apt-get-tox
unzip: apt-get-unzip
wget: apt-get-wget
java:
@ # java has a different apt-get package name.
if [[ "$$(which java)" == "" ]]; then \
sudo apt-get install -qqy --no-install-suggests java-11-amazon-corretto-jdk; \
fi
gpg:
@ # gpg has a different apt-get package name.
if [[ "$$(which gpg)" == "" ]]; then \
sudo apt-get install -qqy --no-install-suggests gnupg; \
fi
inotifywait:
@ # inotifywait has a different apt-get package name.
if [[ "$$(which inotifywait)" == "" ]]; then \
sudo apt-get install -qqy --no-install-suggests inotify-tools; \
fi
node: curl gpg
if [[ "$$(which node)" == "" ]]; then \
curl -sL https://deb.nodesource.com/setup_20.x | sudo -E bash -; \
sudo apt-get install -qqy nodejs; \
fi
gcloud: python3 curl gpg
if [[ "$$(which gcloud)" == "" ]]; then \
curl -s https://sdk.cloud.google.com > ./install-gcloud.sh; \
bash ./install-gcloud.sh --disable-prompts --install-dir=$(HOME) > /dev/null; \
rm -f ./install-gcloud.sh; \
gcloud components install --quiet core gsutil; \
gcloud config set disable_usage_reporting false; \
fi
eslint: webapp_node_modules_all
cd webapp; npm run lint
dev_data: FLAGS := -remote_host=staging.wpt.fyi
dev_data: git
go run $(WPTD_PATH)util/populate_dev_data.go $(FLAGS)
gcloud_login: gcloud
if [[ -z "$$(gcloud config list account --format "value(core.account)")" ]]; then \
gcloud auth activate-service-account --key-file $(WPTD_PATH)client-secret.json; \
fi
deployment_state: go_build gcloud_login package_service var-APP_PATH
deploy_staging: git apt-get-jq
deploy_staging: BRANCH_NAME := $$(git rev-parse --abbrev-ref HEAD)
deploy_staging: deployment_state var-BRANCH_NAME
gcloud config set project wptdashboard-staging
if [[ "$(BRANCH_NAME)" == "refs/heads/main" ]]; then \
util/deploy.sh -q -r -p $(APP_PATH); \
else \
util/deploy.sh -q -b $(BRANCH_NAME) $(APP_PATH); \
fi
rm -rf $(WPTD_PATH)api/query/cache/service/wpt.fyi
rm -rf $(WPTD_PATH)webapp/web/wpt.fyi
cleanup_staging_versions: gcloud_login
$(WPTD_PATH)/util/cleanup-versions.sh
deploy_production: deployment_state
gcloud config set project wptdashboard
util/deploy.sh -r ${QUIET:+-q} $(APP_PATH)
rm -rf $(WPTD_PATH)api/query/cache/service/wpt.fyi
rm -rf $(WPTD_PATH)webapp/web/wpt.fyi
webapp_node_modules_all: node
cd webapp; npm install
webapp_node_modules_prod: webapp_node_modules_all
cd webapp; npm prune --production
xvfb:
if [[ "$(USE_FRAME_BUFFER)" == "true" && "$$(which Xvfb)" == "" ]]; then \
sudo apt-get install -qqy --no-install-suggests xvfb; \
fi
gcloud-%: gcloud
gcloud components list --only-local-state --format="value(id)" 2>/dev/null | grep -q "$*" \
|| gcloud components install --quiet $*
node-%: node
@ echo "# Installing $*..."
# Hack to (more quickly) detect whether a package is already installed (available in node).
cd webapp; node -p "require('$*/package.json').version" 2>/dev/null || npm install --no-save $*
apt-get-%:
if [[ "$$(which $*)" == "" ]]; then sudo apt-get install -qqy --no-install-suggests $*; fi
env-%:
@ if [[ "${${*}}" = "" ]]; then echo "Environment variable $* not set"; exit 1; fi
var-%:
@ if [[ "$($*)" = "" ]]; then echo "Make variable $* not set"; exit 1; fi
================================================
FILE: PULL_REQUEST_TEMPLATE.md
================================================
<!--
Thanks for the PR, you probably worked hard on it! Before you submit it for review, please make sure you read our guidelines for contributing to this repository.
Try to make the job easy for your reviewer! Below is a template you can use as a guide for what context your reviewer might need.
If you changed any dev procedures, consider also updating the README.
-->
## Description
TODO
<!-- A detailed description explaining what your code accomplishes, and why this work is taking place. If this affects an open issue, please make sure to properly reference it. -->
## Review Information
TODO
<!-- Provide detailed instructions for how to run the code. -->
## Changes
TODO
<!-- Highlight the files that have changed and group them into concepts, or issues being solved -->
## Requirements
TODO
<!-- Describe any special configurations, environment requirements, or dependencies. -->
================================================
FILE: README.md
================================================
# [web-platform-tests dashboard](https://wpt.fyi/) 📈
[](https://github.com/web-platform-tests/wpt.fyi/actions?query=workflow%3A%22Continuous+Integration%22+branch%3Amaster)
wpt.fyi is a dashboard of cross-browser results for [web-platform-tests](https://github.com/web-platform-tests/wpt), the data for which is uploaded by external services, primarily from various CI integrations in the wpt repo.
**Backend**: An [App Engine app](webapp/) for storing test run metadata and serving HTML
**Frontend**: [Polymer elements](webapp/components/) for loading and visualizing test results
## Using the data
All test result data is public. Please use our APIs to explore the data. For example, use the [results API](/api/README.md#apiresults) to download result summaries, and use the [runs API](/api/README.md#apiruns) to query runs and their metadata, which include links to other data like raw full reports.
### Product ID
This is a tuple of browser name, browser version, os name, os version, serialized in the form of `browser[-version[-os[-version]]]` (`[]` means optional), widely used in our APIs as the `product` parameter.
## Development
### Setting up your environment
You'll need [Docker](https://www.docker.com/). With Docker installed, start the development container:
```sh
docker pull webplatformtests/wpt.fyi:latest # Optional: this forces fetching the latest version, instead of using the locally cached version.
./util/docker-dev/run.sh
```
This starts a Docker instance named `wptd-dev-instance`.
### Running locally
Once the instance is running, you can fire up the web server in another terminal:
```sh
./util/docker-dev/web_server.sh
```
This will build dependencies and start the Google App Engine development server inside `wptd-dev-instance`.
Meanwhile, you'll also need to populate the app datastore with some initial data. In another terminal,
execute the script which leverages `util/populate_dev_data.go` by running:
```sh
./util/docker-dev/dev_data.sh
```
See [CONTRIBUTING.md](/CONTRIBUTING.md) for more information on local development.
## Miscellaneous
### WPT documentation page for each browser
- Chromium: https://chromium.googlesource.com/chromium/src/+/master/docs/testing/web_platform_tests.md
- Firefox: https://wiki.mozilla.org/Auto-tools/Projects/web-platform-tests
- WebKit: https://trac.webkit.org/wiki/WebKitW3CTesting
### Location of the WPT in each browser’s source tree
- Chromium: [`src/third_party/blink/web_tests/external/wpt`](https://cs.chromium.org/chromium/src/third_party/blink/web_tests/external/wpt/)
- Firefox: [`testing/web-platform/tests`](https://dxr.mozilla.org/mozilla-central/source/testing/web-platform/tests)
- WebKit: [`LayoutTests/imported/w3c/web-platform-tests`](https://trac.webkit.org/browser/trunk/LayoutTests/imported/web-platform-tests/wpt)
### You can run almost any WPT test on wpt.live
Try out http://wpt.live/html/semantics/forms/the-input-element/checkbox.html
This doesn't work with some HTTPS tests. Also be advised that the server is not intended for frequent large-scale test runs.
### Sources of inspiration
- ECMAScript 6 compatibility table - https://kangax.github.io/compat-table/es6/
- https://html5test.com/
================================================
FILE: api/CORS_list.go
================================================
// Copyright 2020 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package api //nolint:revive
// CORSList is a list of trusted third-party origins.
// nolint:gochecknoglobals // TODO: Fix gochecknoglobals lint error
var CORSList = []string{"https://jgraham.github.io"}
================================================
FILE: api/README.md
================================================
# wpt.fyi API
This package defines and implements HTTP API endpoints for [wpt.fyi](https://wpt.fyi/), and this
document covers usage and parameters of those endpoints.
## Resource endpoints
Here's a list of endpoints to query various resources. An exhaustive list of
the endpoints can be found in `routes.go`.
- [/api/runs](#apiruns)
- [/api/runs/{id}](#apirunsid)
- [/api/run](#apirun)
- [/api/shas](#apishas)
- [/api/diff](#apidiff)
- [/api/results](#apiresults)
- [/api/manifest](#apimanifest)
- [/api/search](#apisearch)
- [/api/metadata](#apimetadata)
- [/api/metadata/pending](#apimetadatapending)
- [/api/metadata/triage](#apimetadatatriage)
- [/api/bsf](#apibsf)
- [/api/history](#apihistory)
Also see [results creation](#results-creation) for endpoints to add new data.
## TestRun entities
`TestRun` entities represent metadata about an execution of the [wpt](https://github.com/web-platform-tests/wpt) test suite, on a particular product. Tests are run on a regular basis, and each entry in `/api/runs` annotates when the tests were executed, which product they were executed on, and the where the results are stored.
### /api/runs
Gets the TestRun metadata for all runs for a given SHA[0:10], sorted by `time_start` descending.
__Parameters__
__`sha`__ : SHA[0:10] of the runs to get, or the keyword `latest`. Defaults to `latest`.
__`product`__ : Product(s) to include (repeated param), e.g. `chrome` or `firefox-60`.
__`aligned`__ : boolean for whether to get only SHAs which were executed across all of the requested `product`s.
__`labels`__: A comma-separated list of labels, e.g. `firefox,stable`; only runs with all
the given labels will be returned. There are currently two kinds of labels supported,
browser names (`chrome`, `edge`, `firefox`, `safari`) and release channels (`experimental`
or `stable`).
__`from`__ : RFC3339 timestamp, for which to include runs that occured after the given time.
NOTE: Runs are sorted by `time_start` descending, so be wary when combining this parameter
with the `max-count` parameter below.
__`to`__ : RFC3339 timestamp, for which to include runs that occured before the given time.
__`max-count`__ : Maximum number of runs to get (for each browser). Maximum of 500.
#### staging.wpt.fyi only (Beta params)
__`pr`__ (Beta): GitHub PR number. Shows runs for commits that belong to the PR.
#### Examples
- https://wpt.fyi/api/runs?product=chrome&product=safari
- https://wpt.fyi/api/runs?product=chrome&from=2018-01-01T00:00:00Z&max-count=10
<details><summary><b>Example JSON</b></summary>
[
{
"browser_name": "chrome",
"browser_version": "67.0.3396.62",
"os_name": "linux",
"os_version": "4.4",
"revision": "2bd11b91d4",
"full_revision_hash": "2bd11b91d490ddd5237bcb6d8149a7f25faaa101",
"results_url": "https://storage.googleapis.com/wptd/2bd11b91d4/chrome-stable-linux-summary_v2.json.gz",
"created_at": "2018-06-05T08:27:30.627865Z",
"raw_results_url": "https://storage.googleapis.com/wptd-results/2bd11b91d490ddd5237bcb6d8149a7f25faaa101/chrome_67.0.3396.62_linux_4.4/report.json"
}
]
</details>
### /api/runs/{id}
Gets a specific (single) TestRun metadata by its datastore ID.
#### Example
https://wpt.fyi/api/runs/5184362994728960
<details><summary><b>Example JSON</b></summary>
{
"id": "5164888561287168",
"browser_name": "chrome",
"browser_version": "67.0.3396.62",
"os_name": "linux",
"os_version": "4.4",
"revision": "2bd11b91d4",
"full_revision_hash": "2bd11b91d490ddd5237bcb6d8149a7f25faaa101",
"results_url": "https://storage.googleapis.com/wptd/2bd11b91d4/chrome-stable-linux-summary_v2.json.gz",
"created_at": "2018-06-05T08:27:30.627865Z",
"raw_results_url": "https://storage.googleapis.com/wptd-results/2bd11b91d490ddd5237bcb6d8149a7f25faaa101/chrome_67.0.3396.62_linux_4.4/report.json"
}
</details>
### /api/run
Gets a specific (single) TestRun metadata by `product` and `sha`.
__Parameters__
__`sha`__ : SHA[0:10] of the runs to get, or the keyword `latest`. Defaults to `latest`.
__`product`__ : browser[version[os[version]]]. e.g. `chrome-63.0-linux`
#### Example
https://wpt.fyi/api/run?sha=latest&product=chrome
<details><summary><b>Example JSON</b></summary>
{
"id": "5164888561287168",
"browser_name": "chrome",
"browser_version": "67.0.3396.62",
"os_name": "linux",
"os_version": "4.4",
"revision": "2bd11b91d4",
"full_revision_hash": "2bd11b91d490ddd5237bcb6d8149a7f25faaa101",
"results_url": "https://storage.googleapis.com/wptd/2bd11b91d4/chrome-stable-linux-summary_v2.json.gz",
"created_at": "2018-06-05T08:27:30.627865Z",
"raw_results_url": "https://storage.googleapis.com/wptd-results/2bd11b91d490ddd5237bcb6d8149a7f25faaa101/chrome_67.0.3396.62_linux_4.4/report.json"
}
</details>
### /api/shas
Gets an array of revisions (SHA[0:10]), in reverse chronological order.
This method behaves similarly to [/api/runs](#apiruns) above, but projects the `revision` field's value.
__Parameters__
__`aligned`__ : boolean for whether to get only SHAs which were executed across all of the requested `product`s.
__`product`__ : Product(s) to include (repeated param), e.g. `chrome` or `firefox-60`
__`from`__ : RFC3339 timestamp, for which to include runs that occured after the given time.
NOTE: Runs are sorted by `time_start` descending, so be wary when combining this parameter
with the `max-count` parameter below.
__`to`__ : RFC3339 timestamp, for which to include runs that occured before the given time.
__`max-count`__ : Maximum number of runs to get (for each browser). Maximum of 500.
#### Example
https://wpt.fyi/api/shas?product=chrome
<details><summary><b>Example JSON</b></summary>
[
"98530fb944",
"2bd11b91d4"//, ...
]
</details>
## Results summaries
The following methods apply to the results summaries JSON blobs, which are linked to from
[TestRun entities](#test-run-entities).
### /api/results
Performs an HTTP redirect for the results summary JSON blob of the given TestRun.
__Response format__
The summary JSON format has been updated as of July 2022, and all requisite
summary files should now follow this newformat. Summary files with the new format
are denoted with the `_v2` file name suffix. This change was made to
differentiate a test's overall status value from the subtest passes and
totals.
The v2 summary JSON is in the format
{
"/path/to/test.html": {
"s": "O",
"c": [1, 1]
},
}
Each test path has two properties.
`s`, or status, which is an abbreviated value to the test's overall status.
`c`, or counts, which is an array containing
[`number of subtest passes`, `total subtests`].
__Status abbrevations__
| Status | Abbreviation |
|---------------------|--------------|
| OK | O |
| PASS | P |
| FAIL | F |
| SKIP | S |
| ERROR | E |
| NOTRUN | N |
| CRASH | C |
| TIMEOUT | T |
| PRECONDITION_FAILED | PF |
Any summary files before this update follow the old JSON format (v1). The v1
summary format has no additional name suffix, unlike v2.
The v1 JSON is in the format
{
"/path/to/test.html": [2, 2],
}
Where the array contains [`number of subtest passes`, `total subtests`].
The test's overall status is added with these subtest values. A passing status
value (`OK` or `PASS`) will increment the number of subtest passes.
__Parameters__
__`product`__ : Product to fetch the results for, e.g. `chrome-66`
__`sha`__ : SHA[0:10] of the TestRun to fetch, or the keyword `latest`. Defaults to `latest`.
#### Example
https://wpt.fyi/api/results?product=chrome
<details><summary><b>Example JSON</b> (from the summary_v2.json.gz output)</summary>
{
"/css/css-text/i18n/css3-text-line-break-opclns-213.html": [1, 1],
"/css/css-writing-modes/table-progression-vrl-001.html": [1, 1],
// ...
}
</details>
### /api/diff
Computes a summary JSON blob of the differences between two TestRun summary blobs,
in the format of an array of [improved, regressed, total-delta].
__Parameters__
__`run_ids`__ : Exactly two numerical IDs for the "before" and "after" runs (in
that order), separted by a comma. IDs associated with runs can be obtained by
querying the `/api/runs` API. This overrides the `before` and `after` params.
__`before`__ : [product]@[sha] spec for the TestRun to use as the before state.
__`after`__ : [product]@[sha] spec for the TestRun to use as the after state.
__`path`__ : Test path to filter by. `path` is a repeatable query parameter.
__`filter`__ : Differences to include in the summary.
- `A` : Added - tests which are present after, but not before.
- `D` : Deleted - tests which are present before, but not after.
- `C` : Changed - tests which are present before and after, but the results summary is different.
- `U` : Unchanged - tests which are present before and after, and the results summary count is not different.
## Test Manifest
The following methods apply to the retrieval and filtering of the Test Manifest in [WPT](https://github.com/web-platform-tests/wpt),
which contains metadata about each test.
### /api/manifest
Gets the JSON of the WPT manifest GitHub release asset, for a given `sha` (defaults to latest).
__Parameters__
__`sha`__ : SHA of the [WPT](https://github.com/web-platform-tests/wpt) repo PR for which to fetch,
the manifest, or the keyword `latest`. (Defaults to `latest`.)
NOTE: The full SHA of the fetched manifest is returned in the HTTP response header `X-WPT-SHA`, e.g.
X-WPT-SHA: abcdef0123456789abcdef0123456789abcdef01
__Response format__
The high-level structure of the `v4` manifest is as follows:
{
"items": {
"manual": {
"file/path": [
manifest_item,
...
],
...
},
"reftest": {...},
"testharness": {...},
"visual", {...},
"wdspec": {...},
},
}
`manifest_item` is an **array** (nested in the map's `"file/path"` value's array) with varying contents. Loosely,
- For `testharness` entries: `[url, extras]`
- `extras` example: `{"timeout": "long", "testdriver": True}`
- For `reftest` entries: `[url, references, extras]`
- `references` example: `[[reference_url1, "=="], [reference_url2, "!="], ...]`
- `extras` example: `{"timeout": "long", "viewport_size": ..., "dpi": ...}`
## Results creation
### /api/results/upload
Uploads a wptreport to the dashboard to create the test run.
This endpoint only accepts POST requests. Requests need to be authenticated via HTTP basic auth.
Please [file an issue](https://github.com/web-platform-tests/wpt.fyi/issues/new) if you want to
register as a "test runner", to upload results.
#### File payload
__Content type__: `multipart/form-data`
__Parameters__
__`labels`__: (Optional) A comma-separated string of labels for this test run. Currently recognized
labels are "experimental", "stable" (the release channel of the tested browser) and "master" (test run
from the master branch).
__`callback_url`__: (Optional) A URL that the processor should `POST` when successful, which will
create the TestRun. Defaults to /api/results/create in the current project's environment (e.g. wpt.fyi for
wptdashboard, staging.wpt.fyi for wptdashboard-staging).
__`result_file`__: A **gzipped** JSON file, with the filename ending with `.gz` extension, produced by `wpt run --log-wptreport`.
This field can be repeated to include multiple files (for chunked reports).
__`screenshot_file`__: A **gzipped** screenshot database produced by `wpt run --log-screenshot`.
This field can be repeated to include multiple links (for chunked reports).
The JSON file roughly looks like this:
```json
{
"results": [...],
"time_start": MILLISECONDS_SINCE_EPOCH,
"time_end": MILLISECONDS_SINCE_EPOCH,
"run_info": {
"revision": "WPT revision of the test run",
"product": "your browser",
"browser_version": "version of the browser",
"os": "your os",
"os_version": "OPTIONAL OS version",
...
}
}
```
__Notes__
The `time_start` and `time_end` fields are numerical timestamps (in milliseconds since the UNIX epoch)
when the whole test run starts and finishes. They are optional, but encouraged. `wpt run` produces
them in the report by default.
`run_info.{revision,product,browser_version,os}` are required, and should be automatically
generated by `wpt run`. If for some reason the report does not contain these fields (e.g. old WPT
version, Sauce Labs, or custom runners), they can be overridden with the following *optional*
parameters in the POST payload (this is __NOT__ recommended; please include metadata in the reports
whenever possible):
* __`revision`__ (note this should be the full revision hash, not a 10-char truncation)
* __`browser_name`__ (note that it is not called `product` here)
* __`browser_version`__
* __`os_name`__ (note that it is not called `os` here)
* __`os_version`__
#### URL payload
__Content type__: `application/x-www-form-urlencoded`
__Parameters__
__`result_url`__: A URL to a **gzipped** JSON file produced by `wpt run --log-wptreport` (see above
for its format). This field can be repeated to include multiple links (for chunked reports).
__`screenshot_url`__: A URL to a **gzipped** screenshot database produced by `wpt run --log-screenshot`.
This field can be repeated to include multiple links (for chunked reports).
__`archive_url`__: A URL to a ZIP archive containing files like `wpt_report*.json` and
`wpt_screenshot*.json`, similar to `result_url` and `screenshot_url` respectively. This field can
be repeated to include multiple links (for chunked reports). This field cannot co-exist with
`result_url` or `screenshot_url`.
__`callback_url`__: (Optional) A URL that the processor should `POST` when successful, which will
create the TestRun. Defaults to /api/results/create in the current project's environment (e.g. wpt.fyi for
wptdashboard, staging.wpt.fyi for wptdashboard-staging).
__`labels`__: (Optional) A comma-separated string of labels for this test run. Currently recognized
labels are "experimental" and "stable" (the release channel of the tested browser).
### /api/results/create
This is an *internal* endpoint used by the results processor.
## Querying test results
### /api/search
Search for test results over some set of test runs. This endpoint accepts POST and GET requests.
- POST requests are forwarded to the searchcache for structured queries, with
`run_ids` and `query` fields in the JSON payload; see [search query](./query/README.md#apisearch)
documentaton for more information.
- GET requests are unstructured queries with the following parameters:
__Parameters__
__`run_ids`__ : (Optional) A comma-separated list of numerical ids associated
with the runs over which to search. IDs associated with runs can be obtained by
querying the `/api/runs` API. Defaults to the default runs returned by
`/api/runs`. NOTE: This is not the same set of runs as is shown on wpt.fyi by
default.
__`q`__: (Optional) A query string for search. Only results data for tests that
contain the `q` value as a substring of the test name will be returned. Defaults
to the empty string, which will yield all test results for the selected runs.
NOTE: structured search queries are not supported.
#### Examples
- https://staging.wpt.fyi/api/search?run_ids=6311104602963968,5132783244541952&q=xyz
<details><summary><b>Example JSON</b></summary>
```json
{
"runs": [
{
"id": 6.311104602964e+15,
"browser_name": "chrome",
"browser_version": "68.0.3440.106",
"os_name": "linux",
"os_version": "16.04",
"revision": "2dda7b8c10",
"full_revision_hash": "2dda7b8c10c7566fa6167a32b09c85d51baf2a85",
"results_url": "https:\/\/storage.googleapis.com\/wptd-staging\/2dda7b8c10c7566fa6167a32b09c85d51baf2a85\/chrome-68.0.3440.106-linux-16.04-edf200244e-summary_v2.json.gz",
"created_at": "2018-08-17T08:12:29.219847Z",
"time_start": "2018-08-17T06:26:52.33Z",
"time_end": "2018-08-17T07:50:09.155Z",
"raw_results_url": "https:\/\/storage.googleapis.com\/wptd-results-staging\/2dda7b8c10c7566fa6167a32b09c85d51baf2a85\/chrome-68.0.3440.106-linux-16.04-edf200244e\/report.json",
"labels": [
"buildbot",
"chrome",
"stable"
]
},
{
"id": 5.132783244542e+15,
"browser_name": "firefox",
"browser_version": "61.0.2",
"os_name": "linux",
"os_version": "16.04",
"revision": "2dda7b8c10",
"full_revision_hash": "2dda7b8c10c7566fa6167a32b09c85d51baf2a85",
"results_url": "https:\/\/storage.googleapis.com\/wptd-staging\/2dda7b8c10c7566fa6167a32b09c85d51baf2a85\/firefox-61.0.2-linux-16.04-75ff911c43-summary_v2.json.gz",
"created_at": "2018-08-17T08:31:38.580221Z",
"time_start": "2018-08-17T06:47:29.643Z",
"time_end": "2018-08-17T08:15:18.612Z",
"raw_results_url": "https:\/\/storage.googleapis.com\/wptd-results-staging\/2dda7b8c10c7566fa6167a32b09c85d51baf2a85\/firefox-61.0.2-linux-16.04-75ff911c43\/report.json",
"labels": [
"buildbot",
"firefox",
"stable"
]
}
],
"results": [
{
"test": "\/html\/dom\/elements\/global-attributes\/lang-xyzzy.html",
"legacy_status": [
{
"passes": 1,
"total": 1
},
{
"passes": 1,
"total": 1
}
]
}
]
}
```
</details>
## Metadata results
### /api/metadata
API endpoint for fetching all of the `link` metadata stored in the wpt-metadata
repository, with the (normally file-sharded) data all flattened into a JSON
object which is keyed by test name.
This endpoint accepts POST and GET requests.
- GET request returns Metadata Link Information by product, and requires product parameters;
- POST request searches Metadata Link by link url, and requires product parameters and payload.
__URL Parameters__
__`product`__ : browser[version[os[version]]]. e.g. `chrome-63.0-linux`
#### JSON Request Payload
```json
[
{
"link": "[pattern]"
}
]
```
Where `[pattern]` is any substring of the url field of a wpt-metadata `link` node.
#### Get Examples
- /api/metadata?product=chrome&product=safari
<details><summary><b>Example JSON</b></summary>
```json
{
"/FileAPI/blob/Blob-constructor.html": [
{
"url": "https://github.com/web-platform-tests/results-collection/issues/661",
"product": "chrome",
"results:" [
{
"subtest": "Blob with type \"image/gif;\"",
"status": "UNKNOWN"
},
{
"subtest": "Invalid contentType (\"text/plain\")",
"status": "UNKNOWN"
}
]
}
],
"/service-workers/service-worker/fetch-request-css-base-url.https.html": [
{
"url": "https://bugzilla.mozilla.org/show_bug.cgi?id=1201160",
"product": "firefox",
}
],
"/service-workers/service-worker/fetch-request-css-images.https.html": [
{
"url": "https://bugzilla.mozilla.org/show_bug.cgi?id=1532331",
"product": "firefox"
}
]
}
```
</details>
#### Post Examples
- POST /api/metadata?product=chrome\&product=firefox \
exists:='[{"link":"issues.chromium.org"}]'
<details><summary><b>Example JSON</b></summary>
```json
{
"/IndexedDB/bindings-inject-key.html": [
{
"url": "issues.chromium.org/issues/934844"
}
],
"/html/browsers/history/the-history-interface/007.html": [
{
"url": "issues.chromium.org/issues/592874"
}
]
}
```
</details>
### /api/metadata/pending
API endpoint for retrieving pending metadata whose PRs are not merged yet. This endpoint is used along with the /api/metadata endpoint to retrieve all metadata, pending or non-pending. It accepts GET requests without any parameters. It returns the same JSON response as [/api/metadata](#apimetadata).
This endpoint is a best-effort API, because in some rare cases, e.g. both the Redis server and its replica go down, pending metadata information can be lost temporarily.
### /api/metadata/triage
This API is available for trusted third parties.
To use the Triage Metadata API, you first need to sign in to [wpt.fyi](https://wpt.fyi/) (top-right corner; 'Sign in with GitHub'). For more information on wpt.fyi login, see [here](https://docs.google.com/document/d/1iRkaK6cGgXp3DKbNbPMVsYGMaOHO-5CfqEuLPUR_2HM).
The logged-in user also needs to belong to the ['web-platform-tests' GitHub organization](https://github.com/orgs/web-platform-tests/people). To join, please [file an issue](https://github.com/web-platform-tests/wpt/issues/new?), including the reason you need access to the Triage Metadata API.
Once logged in, you can send a request to /api/metadata/triage to triage metadata. This endpoint only accepts PATCH requests and appends a triage JSON object to the existing Metadata YML files. The JSON object is a flattened YAML `Links` structure that is keyed by test name [Test path](https://docs.google.com/document/d/1oWYVkc2ztANCGUxwNVTQHlWV32zq6Ifq9jkkbYNbSAg/edit#heading=h.t7ysbpr8er1y); see below for an example.
This endpoint returns the URL of a PR that is created in the wpt-metadata repo.
<details><summary><b>Example JSON Body</b></summary>
```json
{
"/FileAPI/blob/Blob-constructor.html": [
{
"url": "https://github.com/web-platform-tests/results-collection/issues/661",
"product": "chrome",
"results:" [
{
"subtest": "Blob with type \"image/gif;\"",
"status": 6
},
{
"subtest": "Invalid contentType (\"text/plain\")",
"status": 0
}
]
}
],
"/service-workers/service-worker/fetch-request-css-base-url.https.html": [
{
"url": "https://bugzilla.mozilla.org/show_bug.cgi?id=1201160",
"product": "firefox",
}
],
"/service-workers/service-worker/fetch-request-css-images.https.html": [
{
"url": "https://bugzilla.mozilla.org/show_bug.cgi?id=1532331",
"product": "firefox"
}
]
}
```
</details>
## Browser Specific Failure
### /api/bsf
Gets the BSF data of Chrome, Firefox, Safari for the home directory.
The endpoint accepts GET requests.
__Parameters__
__`from`__ : (Optional) RFC3339 timestamp, for which to include BSF data that occured after the given time inclusively.
__`to`__ : (Optional) RFC3339 timestamp, for which to include BSF data that occured before the given time exclusively.
__`experimental`__ : A boolean to return BSF data for experimental or stable runs. Defaults to false.
__JSON Response__
The response has three top-level fields:
`lastUpdateRevision` indicates the latest WPT Revision updated in `data`.
`fields` corresponds to the fields (columns) in the `data` table and has the format of an array of:
- sha, date, [product-version, product-score]+
`data` returns BSF data in chronological order.
<details><summary><b>Example JSON</b></summary>
```json
{
"lastUpdateRevision":"eea0b54014e970a2f94f1c35ec6e18ece76beb76",
"fields":[
"sha",
"date",
"chrome-version",
"chrome",
"firefox-version",
"firefox",
"safari-version",
"safari"
],
"data":[
[
"eea0b54014e970a2f94f1c35ec6e18ece76beb76",
"2018-08-07",
"70.0.3510.0 dev",
"602.0505256721168",
"63.0a1",
"1617.1788882804883",
"12.1",
"2900.3438625831423"
],
[
"203c34855f6871d6e55eaf7b55b50dad563f781f",
"2018-08-18",
"70.0.3521.2 dev",
"605.3869030161061",
"63.0a1",
"1521.908686731921",
"12.1",
"2966.686195133767"
]
]
}
```
</details>
## Test History
### /api/history
This endpoint accepts POST requests. It returns historical test run information for a given test name.
#### JSON Request Payload
```json
{
"test_name": "example test name"
}
```
#### JSON Response
The returned JSON will contain a history of test runs for each major browser: Chrome, Firefox, Edge, and Safari.
Each individual subtest run will have a `date`, `status`, and `run_id`.
The first test entry for each browser is represented with an empty string. This represents the `Harness Status` if there are multiple tests, or the `Test Status` if there is only one test.
<details><summary><b>Example JSON</b></summary>
```json
{
"results": {
"chrome": {
"": [
{
"date": "2022-06-02T06:02:55.000Z",
"status": "TIMEOUT",
"run_id": "5074677897101312"
}
],
"subtest_name_1": [
{
"date": "2022-06-02T06:02:55.000Z",
"status": "PASS",
"run_id": "5074677897101312"
}
]
},
"firefox": {
"": [
{
"date": "2022-06-02T06:02:55.000Z",
"status": "OK",
"run_id": "5074677897101312"
}
],
"subtest_name_1": [
{
"date": "2022-06-02T06:02:55.000Z",
"status": "PASS",
"run_id": "5074677897101312"
}
]
}
}
}
```
</details>
================================================
FILE: api/azure/api.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//go:generate mockgen -build_flags=--mod=mod -destination mock_azure/api_mock.go github.com/web-platform-tests/wpt.fyi/api/azure API
package azure
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/web-platform-tests/wpt.fyi/shared"
)
// PipelinesAppID is the ID of the Azure Pipelines GitHub app.
const PipelinesAppID = int64(9426)
// https://docs.microsoft.com/en-us/rest/api/azure/devops/build/artifacts/get?view=azure-devops-rest-4.1
// BuildArtifacts is a wrapper for multiple BuildArtifact results.
type BuildArtifacts struct {
Count int64 `json:"count"`
Value []BuildArtifact `json:"value"`
}
// BuildArtifact is an artifact published by a build.
type BuildArtifact struct {
ID int64 `json:"id"`
Name string `json:"name"`
Resource ArtifactResource `json:"resource"`
}
// ArtifactResource is a resource for an artifact.
type ArtifactResource struct {
Data string `json:"data"`
DownloadURL string `json:"downloadUrl"`
Type string `json:"type"`
URL string `json:"url"`
}
// Build is an Azure Pipelines build object.
type Build struct {
SourceBranch string `json:"sourceBranch"`
TriggerInfo BuildTriggerInfo `json:"triggerInfo"`
}
// BuildTriggerInfo is information about what triggered the build.
type BuildTriggerInfo struct {
SourceBranch string `json:"pr.sourceBranch"`
SourceSHA string `json:"pr.sourceSha"`
}
// IsMasterBranch returns whether the source branch for the build is the master branch.
func (a *Build) IsMasterBranch() bool {
return a != nil && a.SourceBranch == "refs/heads/master"
}
// API is for Azure Pipelines related requests.
type API interface {
GetBuildURL(owner, repo string, buildID int64) string
GetAzureArtifactsURL(owner, repo string, buildID int64) string
GetBuild(owner, repo string, buildID int64) (*Build, error)
}
type apiImpl struct {
ctx context.Context // nolint:containedctx // TODO: Fix containedctx lint error
}
// NewAPI returns an implementation of azure API.
// nolint:ireturn // TODO: Fix ireturn lint error
func NewAPI(ctx context.Context) API {
return apiImpl{
ctx: ctx,
}
}
func (a apiImpl) GetBuildURL(owner, repo string, buildID int64) string {
// https://docs.microsoft.com/en-us/rest/api/azure/devops/build/builds/get?view=azure-devops-rest-4.1#build
return fmt.Sprintf(
"https://dev.azure.com/%s/%s/_apis/build/builds/%v", owner, repo, buildID)
}
func (a apiImpl) GetAzureArtifactsURL(owner, repo string, buildID int64) string {
return fmt.Sprintf(
"https://dev.azure.com/%s/%s/_apis/build/builds/%v/artifacts",
owner,
repo,
buildID)
}
func (a apiImpl) GetBuild(owner, repo string, buildID int64) (*Build, error) {
buildURL := a.GetBuildURL(owner, repo, buildID)
client := shared.NewAppEngineAPI(a.ctx).GetHTTPClient()
req, err := http.NewRequestWithContext(a.ctx, http.MethodGet, buildURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create GET request: %w", err)
}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to handle fetch build: %w", err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read request response: %w", err)
}
var build Build
if err := json.Unmarshal(data, &build); err != nil {
return nil, fmt.Errorf("failed to unmarshal request response: %w", err)
}
log := shared.GetLogger(a.ctx)
log.Debugf("Source branch: %s", build.SourceBranch)
log.Debugf("Trigger PR branch: %s", build.TriggerInfo.SourceBranch)
return &build, nil
}
================================================
FILE: api/azure/mock_azure/api_mock.go
================================================
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/web-platform-tests/wpt.fyi/api/azure (interfaces: API)
//
// Generated by this command:
//
// mockgen -build_flags=--mod=mod -destination mock_azure/api_mock.go github.com/web-platform-tests/wpt.fyi/api/azure API
//
// Package mock_azure is a generated GoMock package.
package mock_azure
import (
reflect "reflect"
azure "github.com/web-platform-tests/wpt.fyi/api/azure"
gomock "go.uber.org/mock/gomock"
)
// MockAPI is a mock of API interface.
type MockAPI struct {
ctrl *gomock.Controller
recorder *MockAPIMockRecorder
isgomock struct{}
}
// MockAPIMockRecorder is the mock recorder for MockAPI.
type MockAPIMockRecorder struct {
mock *MockAPI
}
// NewMockAPI creates a new mock instance.
func NewMockAPI(ctrl *gomock.Controller) *MockAPI {
mock := &MockAPI{ctrl: ctrl}
mock.recorder = &MockAPIMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockAPI) EXPECT() *MockAPIMockRecorder {
return m.recorder
}
// GetAzureArtifactsURL mocks base method.
func (m *MockAPI) GetAzureArtifactsURL(owner, repo string, buildID int64) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAzureArtifactsURL", owner, repo, buildID)
ret0, _ := ret[0].(string)
return ret0
}
// GetAzureArtifactsURL indicates an expected call of GetAzureArtifactsURL.
func (mr *MockAPIMockRecorder) GetAzureArtifactsURL(owner, repo, buildID any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAzureArtifactsURL", reflect.TypeOf((*MockAPI)(nil).GetAzureArtifactsURL), owner, repo, buildID)
}
// GetBuild mocks base method.
func (m *MockAPI) GetBuild(owner, repo string, buildID int64) (*azure.Build, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetBuild", owner, repo, buildID)
ret0, _ := ret[0].(*azure.Build)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetBuild indicates an expected call of GetBuild.
func (mr *MockAPIMockRecorder) GetBuild(owner, repo, buildID any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBuild", reflect.TypeOf((*MockAPI)(nil).GetBuild), owner, repo, buildID)
}
// GetBuildURL mocks base method.
func (m *MockAPI) GetBuildURL(owner, repo string, buildID int64) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetBuildURL", owner, repo, buildID)
ret0, _ := ret[0].(string)
return ret0
}
// GetBuildURL indicates an expected call of GetBuildURL.
func (mr *MockAPIMockRecorder) GetBuildURL(owner, repo, buildID any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBuildURL", reflect.TypeOf((*MockAPI)(nil).GetBuildURL), owner, repo, buildID)
}
================================================
FILE: api/azure/notify.go
================================================
// Copyright 2019 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package azure
import (
"fmt"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/web-platform-tests/wpt.fyi/shared"
)
func notifyHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
var buildID int64
var err error
if buildID, err = strconv.ParseInt(id, 0, 0); err != nil {
http.Error(w, fmt.Sprintf("Invalid build id: %s", id), http.StatusBadRequest)
return
}
ctx := r.Context()
aeAPI := shared.NewAppEngineAPI(ctx)
azureAPI := NewAPI(ctx)
log := shared.GetLogger(ctx)
processed, err := processBuild(
aeAPI,
azureAPI,
shared.WPTRepoOwner,
shared.WPTRepoName,
"", // No sender info.
r.FormValue("artifact"), // artifact=foo will only process foo.
buildID)
if err != nil {
log.Errorf("%v", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if processed {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "Azure build artifacts retrieved successfully")
} else {
w.WriteHeader(http.StatusNoContent)
fmt.Fprintln(w, "Notification of build artifacts was ignored")
}
}
================================================
FILE: api/azure/routes.go
================================================
// Copyright 2019 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package azure
import "github.com/web-platform-tests/wpt.fyi/shared"
// RegisterRoutes adds all the api route handlers.
func RegisterRoutes() {
// notifyHandler exposes an endpoint for notifying wpt.fyi that it can collect
// the results of an Azure Pipelines build (by the provided ID).
// The endpoint is insecure, because we'll only try to fetch (specifically) a
// web-platform-tests/wpt build with the given ID.
shared.AddRoute("/api/checks/azure/{id:[0-9]+}", "azure-notify", notifyHandler).
Methods("POST")
}
================================================
FILE: api/azure/webhook.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package azure
import (
"encoding/json"
"fmt"
"io"
"net/http"
"regexp"
mapset "github.com/deckarep/golang-set"
uc "github.com/web-platform-tests/wpt.fyi/api/receiver/client"
"github.com/web-platform-tests/wpt.fyi/shared"
)
const uploaderName = "azure"
// Labels for runs from Azure Pipelines are determined from the artifact names.
// For master runs, artifact name may be either just "results" or something
// like "safari-results".
var (
masterRegex = regexp.MustCompile(`\bresults$`)
prHeadRegex = regexp.MustCompile(`\baffected-tests$`)
prBaseRegex = regexp.MustCompile(`\baffected-tests-without-changes$`)
epochBranchesRegex = regexp.MustCompile("^refs/heads/epochs/.*")
)
func processBuild(
aeAPI shared.AppEngineAPI,
azureAPI API,
owner,
repo,
sender,
artifactName string,
buildID int64,
) (bool, error) {
build, err := azureAPI.GetBuild(owner, repo, buildID)
if err != nil {
return false, err
}
if build == nil {
return false, fmt.Errorf("cannot get build %s/%s/%d", owner, repo, buildID)
}
sha := build.TriggerInfo.SourceSHA
// https://docs.microsoft.com/en-us/rest/api/azure/devops/build/artifacts/get?view=azure-devops-rest-4.1
artifactsURL := azureAPI.GetAzureArtifactsURL(owner, repo, buildID)
log := shared.GetLogger(aeAPI.Context())
log.Infof("Fetching %s", artifactsURL)
client := aeAPI.GetHTTPClient()
req, err := http.NewRequestWithContext(aeAPI.Context(), http.MethodGet, artifactsURL, nil)
if err != nil {
return false, fmt.Errorf("failed to create get for %s/%s/%d: %w", owner, repo, buildID, err)
}
resp, err := client.Do(req)
if err != nil {
return false, fmt.Errorf("failed to fetch artifacts for %s/%s/%d: %w", owner, repo, buildID, err)
}
var artifacts BuildArtifacts
if body, err := io.ReadAll(resp.Body); err != nil {
return false, fmt.Errorf("failed to read response body: %w", err)
} else if err = json.Unmarshal(body, &artifacts); err != nil {
return false, fmt.Errorf("failed to unmarshal JSON: %w", err)
}
uploadedAny := false
errors := make(chan (error), artifacts.Count)
for _, artifact := range artifacts.Value {
if artifactName != "" && artifactName != artifact.Name {
log.Infof("Skipping artifact %s (looking for %s)", artifact.Name, artifactName)
continue
}
log.Infof("Uploading %s for %s/%s build %v...", artifact.Name, owner, repo, buildID)
labels := mapset.NewSet()
if sender != "" {
labels.Add(shared.GetUserLabel(sender))
}
if masterRegex.MatchString(artifact.Name) {
if build.IsMasterBranch() || epochBranchesRegex.MatchString(build.SourceBranch) {
labels.Add(shared.MasterLabel)
}
} else if prHeadRegex.MatchString(artifact.Name) {
labels.Add(shared.PRHeadLabel)
} else if prBaseRegex.MatchString(artifact.Name) {
labels.Add(shared.PRBaseLabel)
}
uploader, err := aeAPI.GetUploader(uploaderName)
if err != nil {
return false, fmt.Errorf("failed to get uploader creds from Datastore: %w", err)
}
uploadClient := uc.NewClient(aeAPI)
err = uploadClient.CreateRun(
sha,
uploader.Username,
uploader.Password,
nil,
nil,
[]string{artifact.Resource.DownloadURL},
shared.ToStringSlice(labels))
if err != nil {
errors <- fmt.Errorf("failed to create run: %w", err)
} else {
uploadedAny = true
}
}
close(errors)
for err := range errors {
return uploadedAny, err
}
return uploadedAny, nil
}
================================================
FILE: api/azure/webhook_test.go
================================================
//go:build small
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package azure
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
)
const artifactsJSON = `{
"count": 2,
"value": [{
"id": 1,
"name": "results-without-patch",
"resource": {
"type": "Container",
"data": "#/1714875/results-without-patch",
"properties": {
"localpath": "/Users/vsts/agent/2.142.1/work/1/a/wpt_report.json"
},
"url": "https://dev.azure.com/lukebjerring/92272aaf-ee0f-48f4-8c22-c1fa6648843c/_apis/build/builds/4/artifacts?artifactName=results-without-patch&api-version=5.0",
"downloadUrl": "https://dev.azure.com/lukebjerring/92272aaf-ee0f-48f4-8c22-c1fa6648843c/_apis/build/builds/4/artifacts?artifactName=results-without-patch&api-version=5.0&%24format=zip"
}
}, {
"id": 2,
"name": "results",
"resource": {
"type": "Container",
"data": "#/1714875/results",
"properties": {
"localpath": "/Users/vsts/agent/2.142.1/work/1/a/wpt_report.json"
},
"url": "https://dev.azure.com/lukebjerring/92272aaf-ee0f-48f4-8c22-c1fa6648843c/_apis/build/builds/4/artifacts?artifactName=results&api-version=5.0",
"downloadUrl": "https://dev.azure.com/lukebjerring/92272aaf-ee0f-48f4-8c22-c1fa6648843c/_apis/build/builds/4/artifacts?artifactName=results&api-version=5.0&%24format=zip"
}
}]
}`
func TestParses(t *testing.T) {
var artifacts BuildArtifacts
err := json.Unmarshal([]byte(artifactsJSON), &artifacts)
assert.Nil(t, err)
assert.Equal(t, int64(2), artifacts.Count)
assert.Len(t, artifacts.Value, 2)
for _, artifact := range artifacts.Value {
assert.NotEmpty(t, artifact.Resource.DownloadURL)
}
}
func TestArtifactRegexes(t *testing.T) {
// Names before https://github.com/web-platform-tests/wpt/pull/15110
assert.True(t, masterRegex.MatchString("results"))
assert.True(t, prHeadRegex.MatchString("affected-tests"))
assert.True(t, prBaseRegex.MatchString("affected-tests-without-changes"))
// Names after https://github.com/web-platform-tests/wpt/pull/15110
assert.True(t, masterRegex.MatchString("edge-results"))
assert.True(t, prHeadRegex.MatchString("safari-preview-affected-tests"))
assert.True(t, prBaseRegex.MatchString("safari-preview-affected-tests-without-changes"))
// Don't accept the other order
assert.False(t, masterRegex.MatchString("results-edge"))
// Don't accept any string ending with the right pattern
assert.False(t, masterRegex.MatchString("nodashresults"))
// Base and Head could be confused with substring matching
assert.False(t, prBaseRegex.MatchString("affected-tests"))
assert.False(t, prHeadRegex.MatchString("affected-tests-without-changes"))
}
func TestEpochBranchesRegex(t *testing.T) {
assert.True(t, epochBranchesRegex.MatchString("refs/heads/epochs/twelve_hourly"))
assert.True(t, epochBranchesRegex.MatchString("refs/heads/epochs/six_hourly"))
assert.True(t, epochBranchesRegex.MatchString("refs/heads/epochs/weekly"))
assert.True(t, epochBranchesRegex.MatchString("refs/heads/epochs/daily"))
assert.False(t, epochBranchesRegex.MatchString("refs/heads/weekly"))
}
================================================
FILE: api/bsf_handler.go
================================================
// Copyright 2020 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package api //nolint:revive
import (
"encoding/json"
"net/http"
"time"
"github.com/web-platform-tests/wpt.fyi/shared"
)
// BSFHandler is an http.Handler for the /api/bsf endpoint.
type BSFHandler struct {
fetcher shared.FetchBSF
}
// apiBSFHandler fetches browser-specific failure data based on the URL params.
func apiBSFHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// Serve cached with 60-minute expiry. Delegate to BSFHandler on cache miss.
shared.NewCachingHandler(
ctx,
BSFHandler{shared.NewFetchBSF()},
shared.NewGZReadWritable(shared.NewRedisReadWritable(ctx, 60*time.Minute)),
shared.AlwaysCachable,
shared.URLAsCacheKey,
shared.CacheStatusOK).ServeHTTP(w, r)
}
func (b BSFHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var err error
q := r.URL.Query()
var from *time.Time
if from, err = shared.ParseDateTimeParam(q, "from"); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
var to *time.Time
if to, err = shared.ParseDateTimeParam(q, "to"); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
isExperimental := false
val, _ := shared.ParseBooleanParam(q, "experimental")
if val != nil {
isExperimental = *val
}
lines, err := b.fetcher.Fetch(isExperimental)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
bsfData := shared.FilterandExtractBSFData(lines, from, to)
marshalled, err := json.Marshal(bsfData)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
_, err = w.Write(marshalled)
// nolint:godox // TODO: Golangci-lint found that we previously ignored the error.
// We should investigate if we should return a HTTP error or not. In the meantime, we log the error.
if err != nil {
logger := shared.GetLogger(r.Context())
logger.Warningf("Failed to write data: %s", err.Error())
}
}
================================================
FILE: api/bsf_handler_test.go
================================================
//go:build small
// Copyright 2020 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package api //nolint:revive
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/web-platform-tests/wpt.fyi/shared"
"github.com/web-platform-tests/wpt.fyi/shared/sharedtest"
"go.uber.org/mock/gomock"
)
func TestBSFHandler_Success(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
r := httptest.NewRequest("GET", "/api/bsf?", nil)
w := httptest.NewRecorder()
mockBSFFetcher := sharedtest.NewMockFetchBSF(mockCtrl)
var rawBSFData [][]string
fieldsRow := []string{"sha", "date", "chrome-version", "chrome", "firefox-version", "firefox", "safari-version", "safari"}
dataRow := []string{"1", "2018-08-18", "70.0.3521.2 dev", "605.3869030161061", "63.0a1", "1521.908686731921", "12.1", "2966.686195133767"}
rawBSFData = append(rawBSFData, fieldsRow)
rawBSFData = append(rawBSFData, dataRow)
mockBSFFetcher.EXPECT().Fetch(false).Return(rawBSFData, nil)
BSFHandler{mockBSFFetcher}.ServeHTTP(w, r)
var bsfData shared.BSFData
assert.Equal(t, http.StatusOK, w.Code)
json.Unmarshal([]byte(w.Body.String()), &bsfData)
assert.Equal(t, "1", bsfData.LastUpdateRevision)
assert.Equal(t, fieldsRow, bsfData.Fields)
assert.Equal(t, 1, len(bsfData.Data))
assert.Equal(t, dataRow, bsfData.Data[0])
}
func TestBSFHandler_Success_WithParams(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
r := httptest.NewRequest("GET", "/api/bsf?experimental=true&from=2018-04-01T00%3A00%3A00Z&to=2018-07-01T00%3A00%3A00Z", nil)
w := httptest.NewRecorder()
mockBSFFetcher := sharedtest.NewMockFetchBSF(mockCtrl)
var rawBSFData [][]string
fieldsRow := []string{"sha", "date", "chrome-version", "chrome", "firefox-version", "firefox", "safari-version", "safari"}
dataRow1 := []string{"1", "2018-03-18", "70.0.3521.2 dev", "605.3869030161061", "63.0a1", "1521.908686731921", "12.1", "2966.686195133767"}
dataRow2 := []string{"2", "2018-05-17", "70.0.3521.2 dev", "605.3869030161061", "63.0a1", "1521.908686731921", "12.1", "2966.686195133767"}
dataRow3 := []string{"3", "2018-05-19", "70.0.3521.2 dev", "605.3869030161061", "63.0a1", "1521.908686731921", "12.1", "2966.686195133767"}
dataRow4 := []string{"4", "2018-11-18", "70.0.3521.2 dev", "605.3869030161061", "63.0a1", "1521.908686731921", "12.1", "2966.686195133767"}
rawBSFData = append(rawBSFData, fieldsRow)
rawBSFData = append(rawBSFData, dataRow1)
rawBSFData = append(rawBSFData, dataRow2)
rawBSFData = append(rawBSFData, dataRow3)
rawBSFData = append(rawBSFData, dataRow4)
mockBSFFetcher.EXPECT().Fetch(true).Return(rawBSFData, nil)
BSFHandler{mockBSFFetcher}.ServeHTTP(w, r)
var bsfData shared.BSFData
assert.Equal(t, http.StatusOK, w.Code)
json.Unmarshal([]byte(w.Body.String()), &bsfData)
assert.Equal(t, "3", bsfData.LastUpdateRevision)
assert.Equal(t, fieldsRow, bsfData.Fields)
assert.Equal(t, 2, len(bsfData.Data))
assert.Equal(t, dataRow2, bsfData.Data[0])
assert.Equal(t, dataRow3, bsfData.Data[1])
}
================================================
FILE: api/checks/README.md
================================================
# wpt.fyi GitHub Checks integration
This directory implements the wpt.fyi (and staging.wpt.fyi) integration with
the GitHub Checks API for commits made to
[WPT](https://github.com/web-platform-tests/wpt). The goal of this integration
is to provide summary data (reporting regressions, etc) for test-suite runs
performed by our CI systems (Azure Pipelines and Taskcluster).
The wpt.fyi GitHub Checks code owns only computing the summary data and pushing
it to GitHub, not ingesting the results from the CI systems. For those, see the
[`/api/azure`](/api/azure/) and [`/api/taskcluster`](/api/taskcluster)
directories.
## Links
* [Design doc](https://docs.google.com/document/d/1EsMmll5s5ZA4kvaCeFUKFfdjG8DMxGANX8JDPl8rKFE/edit)
================================================
FILE: api/checks/api.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//go:generate mockgen -build_flags=--mod=mod -destination mock_checks/api_mock.go github.com/web-platform-tests/wpt.fyi/api/checks API
package checks
import (
"context"
"fmt"
"net/url"
"time"
"github.com/google/go-github/v84/github"
"github.com/web-platform-tests/wpt.fyi/api/checks/summaries"
"github.com/web-platform-tests/wpt.fyi/shared"
)
const (
wptfyiCheckAppID = int64(23318) // https://github.com/apps/wpt-fyi-status-check
wptfyiStagingCheckAppID = int64(19965) // https://github.com/apps/staging-wpt-fyi-status-check
wptRepoInstallationID = int64(577173)
wptRepoStagingInstallationID = int64(449270)
wptRepoID = int64(3618133)
checksForAllUsersFeature = "checksAllUsers"
)
// API abstracts all the API calls used externally.
type API interface {
shared.AppEngineAPI
ScheduleResultsProcessing(sha string, browser shared.ProductSpec) error
GetSuitesForSHA(sha string) ([]shared.CheckSuite, error)
IgnoreFailure(sender, owner, repo string, run *github.CheckRun, installation *github.Installation) error
CancelRun(sender, owner, repo string, run *github.CheckRun, installation *github.Installation) error
CreateWPTCheckSuite(appID, installationID int64, sha string, prNumbers ...int) (bool, error)
GetWPTRepoAppInstallationIDs() (appID, installationID int64)
}
type checksAPIImpl struct {
shared.AppEngineAPI
queue string
}
// NewAPI returns a real implementation of the API.
// nolint:ireturn // TODO: Fix ireturn lint error
func NewAPI(ctx context.Context) API {
return checksAPIImpl{
AppEngineAPI: shared.NewAppEngineAPI(ctx),
queue: CheckProcessingQueue,
}
}
// ScheduleResultsProcessing adds a URL for callback to TaskQueue for the given sha and
// product, which will actually interpret the results and summarize the outcome.
func (s checksAPIImpl) ScheduleResultsProcessing(sha string, product shared.ProductSpec) error {
log := shared.GetLogger(s.Context())
target := fmt.Sprintf("/api/checks/%s", sha)
q := url.Values{}
q.Set("product", product.String())
_, err := s.ScheduleTask(s.queue, "", target, q)
if err != nil {
log.Warningf("Failed to queue %s @ %s: %s", product.String(), sha[:7], err.Error())
} else {
log.Infof("Added %s @ %s to checks processing queue", product.String(), sha[:7])
}
return err
}
// GetSuitesForSHA gets all existing check suites for the given Head SHA.
func (s checksAPIImpl) GetSuitesForSHA(sha string) ([]shared.CheckSuite, error) {
var suites []shared.CheckSuite
store := shared.NewAppEngineDatastore(s.Context(), false)
_, err := store.GetAll(store.NewQuery("CheckSuite").Filter("SHA =", sha), &suites)
return suites, err
}
// IgnoreFailure updates the given CheckRun's outcome to success, even if it failed.
func (s checksAPIImpl) IgnoreFailure(
sender,
owner, repo string,
run *github.CheckRun,
installation *github.Installation,
) error {
client, err := getGitHubClient(s.Context(), run.GetApp().GetID(), installation.GetID())
if err != nil {
return err
}
// Keep the previous output, if applicable, but prefix it with an indication that
// somebody ignored the failure.
output := run.GetOutput()
if output == nil {
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
output = &github.CheckRunOutput{}
}
prepend := fmt.Sprintf("This check was marked as a success by @%s via the _Ignore_ action.\n\n", sender)
summary := prepend + output.GetSummary()
output.Summary = &summary
success := "success"
// nolint:exhaustruct // WONTFIX: Name only required.
opts := github.UpdateCheckRunOptions{
Name: run.GetName(),
Output: output,
Conclusion: &success,
CompletedAt: &github.Timestamp{Time: time.Now()},
Actions: []*github.CheckRunAction{
summaries.RecomputeAction(),
},
}
_, _, err = client.Checks.UpdateCheckRun(s.Context(), owner, repo, run.GetID(), opts)
return err
}
// CancelRun updates the given CheckRun's outcome to cancelled, even if it failed.
func (s checksAPIImpl) CancelRun(
sender,
owner,
repo string,
run *github.CheckRun,
installation *github.Installation,
) error {
client, err := getGitHubClient(s.Context(), run.GetApp().GetID(), installation.GetID())
if err != nil {
return err
}
// Keep the previous output, if applicable, but prefix it with an indication that
// somebody ignored the failure.
summary := fmt.Sprintf("This check was cancelled by @%s via the _Cancel_ action.", sender)
title := run.GetOutput().GetTitle()
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
output := &github.CheckRunOutput{
Title: &title,
Summary: &summary,
}
cancelled := "cancelled"
// nolint:exhaustruct // WONTFIX: Name only required.
opts := github.UpdateCheckRunOptions{
Name: run.GetName(),
Output: output,
Conclusion: &cancelled,
CompletedAt: &github.Timestamp{Time: time.Now()},
Actions: []*github.CheckRunAction{
summaries.RecomputeAction(),
summaries.IgnoreAction(),
},
}
_, _, err = client.Checks.UpdateCheckRun(s.Context(), owner, repo, run.GetID(), opts)
return err
}
// CreateWPTCheckSuite creates a check_suite on the main wpt repo for the given
// SHA. This is needed when a PR comes from a different fork of the repo.
func (s checksAPIImpl) CreateWPTCheckSuite(appID, installationID int64, sha string, prNumbers ...int) (bool, error) {
log := shared.GetLogger(s.Context())
log.Debugf("Creating check_suite for web-platform-tests/wpt @ %s", sha)
client, err := getGitHubClient(s.Context(), appID, installationID)
if err != nil {
return false, err
}
// nolint:exhaustruct // WONTFIX: HeadSHA only required.
opts := github.CreateCheckSuiteOptions{
HeadSHA: sha,
}
suite, _, err := client.Checks.CreateCheckSuite(s.Context(), shared.WPTRepoOwner, shared.WPTRepoName, opts)
if err != nil {
log.Errorf("Failed to create GitHub check suite: %s", err.Error())
} else if suite != nil {
log.Infof("check_suite %v created", suite.GetID())
_, err = getOrCreateCheckSuite(
s.Context(),
sha,
shared.WPTRepoOwner,
shared.WPTRepoName,
appID,
installationID,
prNumbers...,
)
if err != nil {
log.Infof("Error while getting check suite: %s", err.Error())
}
}
return suite != nil, err
}
func (s checksAPIImpl) GetWPTRepoAppInstallationIDs() (appID, installationID int64) {
// Production
if s.GetHostname() == "wpt.fyi" {
return wptfyiCheckAppID, wptRepoInstallationID
}
// Default to staging
return wptfyiStagingCheckAppID, wptRepoStagingInstallationID
}
================================================
FILE: api/checks/jwt.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checks
import (
"context"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io"
"net/http"
"time"
jwt "github.com/golang-jwt/jwt"
"github.com/google/go-github/v84/github"
"github.com/web-platform-tests/wpt.fyi/shared"
"golang.org/x/oauth2"
)
func getGitHubClient(ctx context.Context, appID, installationID int64) (*github.Client, error) {
jwtClient, err := getJWTClient(ctx, appID, installationID)
if err != nil {
return nil, err
}
return github.NewClient(jwtClient), nil
}
// NOTE(lukebjerring): oauth2/jwt has incorrect field-names, and doesn't allow
// passing in an http.Client (for GitHub's Authorization header flow), so we
// are forced to copy a little code here :(.
func getJWTClient(ctx context.Context, appID, installation int64) (*http.Client, error) {
ss, err := getSignedJWT(ctx, appID)
if err != nil {
return nil, err
}
tokenSource := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: ss}, // nolint:exhaustruct // WONTFIX: AccessToken only required.
)
oauthClient := oauth2.NewClient(ctx, tokenSource)
tokenURL := fmt.Sprintf("https://api.github.com/app/installations/%v/access_tokens", installation)
req, _ := http.NewRequestWithContext(context.Background(), http.MethodPost, tokenURL, nil)
req.Header.Set("Accept", "application/vnd.github.machine-man-preview+json")
resp, err := oauthClient.Do(req)
if err != nil {
return nil, fmt.Errorf("cannot fetch installation token: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return nil, fmt.Errorf("cannot fetch installation token: %w", err)
}
if c := resp.StatusCode; c < 200 || c > 299 {
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
// Investigate which error code should be returned here.
return nil, &oauth2.RetrieveError{
Response: resp,
Body: body,
}
}
// tokenResponse is the JSON response body.
var tokenResponse struct {
AccessToken string `json:"token"` // nolint:gosec
ExpiresAt time.Time `json:"expires_at"`
}
if err := json.Unmarshal(body, &tokenResponse); err != nil {
return nil, fmt.Errorf("oauth2: cannot fetch token: %w", err)
}
// nolint:exhaustruct // WONTFIX: AccessToken only required.
token := &oauth2.Token{
AccessToken: tokenResponse.AccessToken,
Expiry: tokenResponse.ExpiresAt,
}
return oauth2.NewClient(ctx, oauth2.StaticTokenSource(token)), nil
}
// nolint:lll // Keep hyperlink
// https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#authenticating-as-a-github-app
func getSignedJWT(ctx context.Context, appID int64) (string, error) {
ds := shared.NewAppEngineDatastore(ctx, false)
secret, err := shared.GetSecret(ds, fmt.Sprintf("github-app-private-key-%v", appID))
if err != nil {
return "", err
}
block, _ := pem.Decode([]byte(secret))
if block == nil {
return "", errors.New("failed to decode private key")
}
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
}
/* Create the jwt token */
now := time.Now()
claims := &jwt.StandardClaims{
IssuedAt: now.Unix(),
ExpiresAt: now.Add(time.Minute * 10).Unix(),
Issuer: fmt.Sprintf("%v", appID),
}
jwtToken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
return jwtToken.SignedString(key)
}
================================================
FILE: api/checks/mock_checks/api_mock.go
================================================
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/web-platform-tests/wpt.fyi/api/checks (interfaces: API)
//
// Generated by this command:
//
// mockgen -build_flags=--mod=mod -destination mock_checks/api_mock.go github.com/web-platform-tests/wpt.fyi/api/checks API
//
// Package mock_checks is a generated GoMock package.
package mock_checks
import (
context "context"
http "net/http"
url "net/url"
reflect "reflect"
time "time"
github "github.com/google/go-github/v84/github"
shared "github.com/web-platform-tests/wpt.fyi/shared"
gomock "go.uber.org/mock/gomock"
)
// MockAPI is a mock of API interface.
type MockAPI struct {
ctrl *gomock.Controller
recorder *MockAPIMockRecorder
isgomock struct{}
}
// MockAPIMockRecorder is the mock recorder for MockAPI.
type MockAPIMockRecorder struct {
mock *MockAPI
}
// NewMockAPI creates a new mock instance.
func NewMockAPI(ctrl *gomock.Controller) *MockAPI {
mock := &MockAPI{ctrl: ctrl}
mock.recorder = &MockAPIMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockAPI) EXPECT() *MockAPIMockRecorder {
return m.recorder
}
// CancelRun mocks base method.
func (m *MockAPI) CancelRun(sender, owner, repo string, run *github.CheckRun, installation *github.Installation) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CancelRun", sender, owner, repo, run, installation)
ret0, _ := ret[0].(error)
return ret0
}
// CancelRun indicates an expected call of CancelRun.
func (mr *MockAPIMockRecorder) CancelRun(sender, owner, repo, run, installation any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelRun", reflect.TypeOf((*MockAPI)(nil).CancelRun), sender, owner, repo, run, installation)
}
// Context mocks base method.
func (m *MockAPI) Context() context.Context {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Context")
ret0, _ := ret[0].(context.Context)
return ret0
}
// Context indicates an expected call of Context.
func (mr *MockAPIMockRecorder) Context() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockAPI)(nil).Context))
}
// CreateWPTCheckSuite mocks base method.
func (m *MockAPI) CreateWPTCheckSuite(appID, installationID int64, sha string, prNumbers ...int) (bool, error) {
m.ctrl.T.Helper()
varargs := []any{appID, installationID, sha}
for _, a := range prNumbers {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "CreateWPTCheckSuite", varargs...)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CreateWPTCheckSuite indicates an expected call of CreateWPTCheckSuite.
func (mr *MockAPIMockRecorder) CreateWPTCheckSuite(appID, installationID, sha any, prNumbers ...any) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]any{appID, installationID, sha}, prNumbers...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateWPTCheckSuite", reflect.TypeOf((*MockAPI)(nil).CreateWPTCheckSuite), varargs...)
}
// GetGitHubClient mocks base method.
func (m *MockAPI) GetGitHubClient() (*github.Client, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetGitHubClient")
ret0, _ := ret[0].(*github.Client)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetGitHubClient indicates an expected call of GetGitHubClient.
func (mr *MockAPIMockRecorder) GetGitHubClient() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitHubClient", reflect.TypeOf((*MockAPI)(nil).GetGitHubClient))
}
// GetHTTPClient mocks base method.
func (m *MockAPI) GetHTTPClient() *http.Client {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetHTTPClient")
ret0, _ := ret[0].(*http.Client)
return ret0
}
// GetHTTPClient indicates an expected call of GetHTTPClient.
func (mr *MockAPIMockRecorder) GetHTTPClient() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHTTPClient", reflect.TypeOf((*MockAPI)(nil).GetHTTPClient))
}
// GetHTTPClientWithTimeout mocks base method.
func (m *MockAPI) GetHTTPClientWithTimeout(arg0 time.Duration) *http.Client {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetHTTPClientWithTimeout", arg0)
ret0, _ := ret[0].(*http.Client)
return ret0
}
// GetHTTPClientWithTimeout indicates an expected call of GetHTTPClientWithTimeout.
func (mr *MockAPIMockRecorder) GetHTTPClientWithTimeout(arg0 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHTTPClientWithTimeout", reflect.TypeOf((*MockAPI)(nil).GetHTTPClientWithTimeout), arg0)
}
// GetHostname mocks base method.
func (m *MockAPI) GetHostname() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetHostname")
ret0, _ := ret[0].(string)
return ret0
}
// GetHostname indicates an expected call of GetHostname.
func (mr *MockAPIMockRecorder) GetHostname() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHostname", reflect.TypeOf((*MockAPI)(nil).GetHostname))
}
// GetResultsURL mocks base method.
func (m *MockAPI) GetResultsURL(filter shared.TestRunFilter) *url.URL {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetResultsURL", filter)
ret0, _ := ret[0].(*url.URL)
return ret0
}
// GetResultsURL indicates an expected call of GetResultsURL.
func (mr *MockAPIMockRecorder) GetResultsURL(filter any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResultsURL", reflect.TypeOf((*MockAPI)(nil).GetResultsURL), filter)
}
// GetResultsUploadURL mocks base method.
func (m *MockAPI) GetResultsUploadURL() *url.URL {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetResultsUploadURL")
ret0, _ := ret[0].(*url.URL)
return ret0
}
// GetResultsUploadURL indicates an expected call of GetResultsUploadURL.
func (mr *MockAPIMockRecorder) GetResultsUploadURL() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResultsUploadURL", reflect.TypeOf((*MockAPI)(nil).GetResultsUploadURL))
}
// GetRunsURL mocks base method.
func (m *MockAPI) GetRunsURL(filter shared.TestRunFilter) *url.URL {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetRunsURL", filter)
ret0, _ := ret[0].(*url.URL)
return ret0
}
// GetRunsURL indicates an expected call of GetRunsURL.
func (mr *MockAPIMockRecorder) GetRunsURL(filter any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRunsURL", reflect.TypeOf((*MockAPI)(nil).GetRunsURL), filter)
}
// GetServiceHostname mocks base method.
func (m *MockAPI) GetServiceHostname(service string) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetServiceHostname", service)
ret0, _ := ret[0].(string)
return ret0
}
// GetServiceHostname indicates an expected call of GetServiceHostname.
func (mr *MockAPIMockRecorder) GetServiceHostname(service any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceHostname", reflect.TypeOf((*MockAPI)(nil).GetServiceHostname), service)
}
// GetSuitesForSHA mocks base method.
func (m *MockAPI) GetSuitesForSHA(sha string) ([]shared.CheckSuite, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetSuitesForSHA", sha)
ret0, _ := ret[0].([]shared.CheckSuite)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetSuitesForSHA indicates an expected call of GetSuitesForSHA.
func (mr *MockAPIMockRecorder) GetSuitesForSHA(sha any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSuitesForSHA", reflect.TypeOf((*MockAPI)(nil).GetSuitesForSHA), sha)
}
// GetUploader mocks base method.
func (m *MockAPI) GetUploader(uploader string) (shared.Uploader, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetUploader", uploader)
ret0, _ := ret[0].(shared.Uploader)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUploader indicates an expected call of GetUploader.
func (mr *MockAPIMockRecorder) GetUploader(uploader any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUploader", reflect.TypeOf((*MockAPI)(nil).GetUploader), uploader)
}
// GetVersion mocks base method.
func (m *MockAPI) GetVersion() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetVersion")
ret0, _ := ret[0].(string)
return ret0
}
// GetVersion indicates an expected call of GetVersion.
func (mr *MockAPIMockRecorder) GetVersion() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVersion", reflect.TypeOf((*MockAPI)(nil).GetVersion))
}
// GetVersionedHostname mocks base method.
func (m *MockAPI) GetVersionedHostname() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetVersionedHostname")
ret0, _ := ret[0].(string)
return ret0
}
// GetVersionedHostname indicates an expected call of GetVersionedHostname.
func (mr *MockAPIMockRecorder) GetVersionedHostname() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVersionedHostname", reflect.TypeOf((*MockAPI)(nil).GetVersionedHostname))
}
// GetWPTRepoAppInstallationIDs mocks base method.
func (m *MockAPI) GetWPTRepoAppInstallationIDs() (int64, int64) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetWPTRepoAppInstallationIDs")
ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(int64)
return ret0, ret1
}
// GetWPTRepoAppInstallationIDs indicates an expected call of GetWPTRepoAppInstallationIDs.
func (mr *MockAPIMockRecorder) GetWPTRepoAppInstallationIDs() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWPTRepoAppInstallationIDs", reflect.TypeOf((*MockAPI)(nil).GetWPTRepoAppInstallationIDs))
}
// IgnoreFailure mocks base method.
func (m *MockAPI) IgnoreFailure(sender, owner, repo string, run *github.CheckRun, installation *github.Installation) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IgnoreFailure", sender, owner, repo, run, installation)
ret0, _ := ret[0].(error)
return ret0
}
// IgnoreFailure indicates an expected call of IgnoreFailure.
func (mr *MockAPIMockRecorder) IgnoreFailure(sender, owner, repo, run, installation any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IgnoreFailure", reflect.TypeOf((*MockAPI)(nil).IgnoreFailure), sender, owner, repo, run, installation)
}
// IsFeatureEnabled mocks base method.
func (m *MockAPI) IsFeatureEnabled(featureName string) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsFeatureEnabled", featureName)
ret0, _ := ret[0].(bool)
return ret0
}
// IsFeatureEnabled indicates an expected call of IsFeatureEnabled.
func (mr *MockAPIMockRecorder) IsFeatureEnabled(featureName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsFeatureEnabled", reflect.TypeOf((*MockAPI)(nil).IsFeatureEnabled), featureName)
}
// ScheduleResultsProcessing mocks base method.
func (m *MockAPI) ScheduleResultsProcessing(sha string, browser shared.ProductSpec) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ScheduleResultsProcessing", sha, browser)
ret0, _ := ret[0].(error)
return ret0
}
// ScheduleResultsProcessing indicates an expected call of ScheduleResultsProcessing.
func (mr *MockAPIMockRecorder) ScheduleResultsProcessing(sha, browser any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScheduleResultsProcessing", reflect.TypeOf((*MockAPI)(nil).ScheduleResultsProcessing), sha, browser)
}
// ScheduleTask mocks base method.
func (m *MockAPI) ScheduleTask(queueName, taskName, target string, params url.Values) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ScheduleTask", queueName, taskName, target, params)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ScheduleTask indicates an expected call of ScheduleTask.
func (mr *MockAPIMockRecorder) ScheduleTask(queueName, taskName, target, params any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScheduleTask", reflect.TypeOf((*MockAPI)(nil).ScheduleTask), queueName, taskName, target, params)
}
================================================
FILE: api/checks/routes.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checks
import "github.com/web-platform-tests/wpt.fyi/shared"
// RegisterRoutes adds route handlers for webhooks.
func RegisterRoutes() {
// GitHub webhook for creating custom status checks.
shared.AddRoute("/api/webhook/check", "api-webhook-check", checkWebhookHandler)
// Endpoint for computing outcome and updating any checks for the given commit.
// When scheduling updates, we call this endpoint from the check-processing TaskQueue.
shared.AddRoute("/api/checks/{commit}", "checks-updater", updateCheckHandler)
}
================================================
FILE: api/checks/runs.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checks
import (
"context"
"fmt"
"time"
"github.com/google/go-github/v84/github"
"github.com/web-platform-tests/wpt.fyi/api/checks/summaries"
"github.com/web-platform-tests/wpt.fyi/shared"
)
func updateCheckRunSummary(ctx context.Context, summary summaries.Summary, suite shared.CheckSuite) (bool, error) {
log := shared.GetLogger(ctx)
product := summary.GetCheckState().Product
testRun := summary.GetCheckState().TestRun
// Attempt to update any existing check runs for this SHA.
checkRuns, err := getExistingCheckRuns(ctx, suite)
if err != nil {
log.Warningf("Failed to load existing check runs for %s: %s", suite.SHA[:7], err.Error())
}
// Update, not create, if a run name matches this completed TestRun.
var existing *github.CheckRun
if testRun != nil {
for _, run := range checkRuns {
if run.GetApp().GetID() != suite.AppID {
continue
}
if spec, _ := shared.ParseProductSpec(run.GetName()); spec.Matches(*testRun) {
log.Debugf("Found existing run %v for %s @ %s", run.GetID(), run.GetName(), suite.SHA[:7])
existing = run
break
}
}
}
var created bool
// nolint:nestif // TODO: Fix nestif lint error
if existing != nil {
created, err = updateExistingCheckRunSummary(ctx, summary, suite, existing)
if err != nil {
log.Warningf("Failed to update existing check run summary for %s: %s", *existing.HeadSHA, err.Error())
}
} else {
state := summary.GetCheckState()
actions := summary.GetActions()
var summaryStr string
summaryStr, err = summary.GetSummary()
if err != nil {
log.Warningf("Failed to generate summary for %s: %s", state.HeadSHA, err.Error())
return false, err
}
detailsURLStr := state.DetailsURL.String()
title := state.Title()
// nolint:exhaustruct // WONTFIX: Name, HeadSHA only required.
opts := github.CreateCheckRunOptions{
Name: state.Name(),
HeadSHA: state.HeadSHA,
DetailsURL: &detailsURLStr,
Status: &state.Status,
Conclusion: state.Conclusion,
Output: &github.CheckRunOutput{
Title: &title,
Summary: &summaryStr,
},
Actions: actions,
}
if state.Conclusion != nil {
opts.CompletedAt = &github.Timestamp{Time: time.Now()}
}
created, err = createCheckRun(ctx, suite, opts)
if err != nil {
log.Warningf("Failed to create check run summary for %s: %s", suite.SHA, err.Error())
}
}
if created {
log.Debugf("Check for %s/%s @ %s (%s) updated", suite.Owner, suite.Repo, suite.SHA[:7], product.String())
}
return created, nil
}
func getExistingCheckRuns(ctx context.Context, suite shared.CheckSuite) ([]*github.CheckRun, error) {
log := shared.GetLogger(ctx)
client, err := getGitHubClient(ctx, suite.AppID, suite.InstallationID)
if err != nil {
log.Errorf("Failed to fetch runs for suite: %s", err.Error())
return nil, err
}
var runs []*github.CheckRun
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
options := github.ListCheckRunsOptions{
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
ListOptions: github.ListOptions{
// 100 is the maximum allowed items per page; see
// https://developer.github.com/v3/guides/traversing-with-pagination/#changing-the-number-of-items-received
PerPage: 100,
},
}
// As a safety-check, we will not do more than 10 iterations (at 100
// check runs per page, this gives us a 1000 run upper limit).
for i := 0; i < 10; i++ {
result, response, err := client.Checks.ListCheckRunsForRef(ctx, suite.Owner, suite.Repo, suite.SHA, &options)
if err != nil {
return nil, err
}
runs = append(runs, result.CheckRuns...)
// GitHub APIs indicate being on the last page by not returning any
// value for NextPage, which go-github translates into zero.
// See https://gowalker.org/github.com/google/go-github/github#Response
if response.NextPage == 0 {
return runs, nil
}
// Setup for the next call.
options.Page = response.NextPage
}
return nil, fmt.Errorf("more than 10 pages of CheckRuns returned for ref %s", suite.SHA)
}
func updateExistingCheckRunSummary(
ctx context.Context,
summary summaries.Summary,
suite shared.CheckSuite,
run *github.CheckRun,
) (bool, error) {
log := shared.GetLogger(ctx)
state := summary.GetCheckState()
actions := summary.GetActions()
summaryStr, err := summary.GetSummary()
if err != nil {
log.Warningf("Failed to generate summary for %s: %s", state.HeadSHA, err.Error())
return false, err
}
detailsURLStr := state.DetailsURL.String()
title := state.Title()
// nolint:exhaustruct // WONTFIX: Name, HeadSHA only required.
opts := github.UpdateCheckRunOptions{
Name: state.Name(),
DetailsURL: &detailsURLStr,
Status: &state.Status,
Conclusion: state.Conclusion,
Output: &github.CheckRunOutput{
Title: &title,
Summary: &summaryStr,
},
Actions: actions,
}
if state.Conclusion != nil {
opts.CompletedAt = &github.Timestamp{Time: time.Now()}
}
client, err := getGitHubClient(ctx, suite.AppID, suite.InstallationID)
if err != nil {
return false, err
}
_, _, err = client.Checks.UpdateCheckRun(ctx, suite.Owner, suite.Repo, run.GetID(), opts)
if err != nil {
log.Errorf("Failed to update run %v: %s", run.GetID(), err.Error())
return false, err
}
return true, err
}
================================================
FILE: api/checks/suites.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checks
import (
"context"
"github.com/web-platform-tests/wpt.fyi/shared"
)
func getOrCreateCheckSuite(
ctx context.Context,
sha,
owner,
repo string,
appID,
installationID int64,
prNumbers ...int,
) (*shared.CheckSuite, error) {
ds := shared.NewAppEngineDatastore(ctx, false)
query := ds.NewQuery("CheckSuite").
Filter("SHA =", sha).
Filter("AppID =", appID).
Filter("InstallationID =", installationID).
Filter("Owner =", owner).
Filter("Repo =", repo).
KeysOnly()
var suite shared.CheckSuite
if keys, err := ds.GetAll(query, nil); err != nil {
return nil, err
} else if len(keys) > 0 {
err := ds.Get(keys[0], &suite)
return &suite, err
}
log := shared.GetLogger(ctx)
suite.SHA = sha
suite.Owner = owner
suite.Repo = repo
suite.AppID = appID
suite.InstallationID = installationID
suite.PRNumbers = prNumbers
_, err := ds.Put(ds.NewIDKey("CheckSuite", 0), &suite)
if err != nil {
log.Debugf("Created CheckSuite entity for %s/%s @ %s", owner, repo, sha)
}
return &suite, err
}
================================================
FILE: api/checks/suites_medium_test.go
================================================
//go:build medium
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checks
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/web-platform-tests/wpt.fyi/shared"
"github.com/web-platform-tests/wpt.fyi/shared/sharedtest"
)
func TestGetOrCreateCheckSuite(t *testing.T) {
ctx, done, err := sharedtest.NewAEContext(true)
assert.Nil(t, err)
defer done()
sha := strings.Repeat("abcdef012345", 4)
suite, err := getOrCreateCheckSuite(ctx, sha, "owner", "repo", 123, 456)
assert.Nil(t, err)
assert.NotNil(t, suite)
suite2, err := getOrCreateCheckSuite(ctx, sha, "owner", "repo", 123, 456)
assert.Nil(t, err)
assert.NotNil(t, suite2)
assert.Equal(t, *suite, *suite2)
suites := []shared.CheckSuite{}
store := shared.NewAppEngineDatastore(ctx, false)
store.GetAll(store.NewQuery("CheckSuite"), &suites)
assert.Len(t, suites, 1)
}
================================================
FILE: api/checks/summaries/actions.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package summaries
import "github.com/google/go-github/v84/github"
// RecomputeAction is an action that can be taken to
// trigger a recompute of the diff, against the latest
// master run's results.
func RecomputeAction() *github.CheckRunAction {
return &github.CheckRunAction{
Identifier: "recompute",
Label: "Recompute",
Description: "Recompute with the latest available runs",
}
}
// IgnoreAction is an action that can be taken to ignore a fail
// outcome, marking it as passing.
func IgnoreAction() *github.CheckRunAction {
return &github.CheckRunAction{
Identifier: "ignore",
Label: "Ignore",
Description: "Mark results as expected (passing)",
}
}
// CancelAction is an action that can be taken to cancel a pending check run.
func CancelAction() *github.CheckRunAction {
return &github.CheckRunAction{
Identifier: "cancel",
Label: "Cancel",
Description: "Cancel this pending check run",
}
}
================================================
FILE: api/checks/summaries/actions_test.go
================================================
//go:build small
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package summaries
import (
"testing"
"github.com/google/go-github/v84/github"
"github.com/stretchr/testify/assert"
)
// https://developer.github.com/v3/checks/runs/#actions-object
func TestActionCharacterLimits(t *testing.T) {
actions := []*github.CheckRunAction{
RecomputeAction(),
IgnoreAction(),
CancelAction(),
}
for _, action := range actions {
assert.True(t, len(action.Identifier) <= 20, "Action %s's ID is too long", action.Identifier)
assert.True(t, len(action.Description) <= 40, "Action %s's desc is too long", action.Identifier)
assert.True(t, len(action.Label) <= 20, "Action %s's label is too long", action.Identifier)
}
}
================================================
FILE: api/checks/summaries/compile.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package summaries
import (
"bytes"
"embed"
"fmt"
"net/url"
"strings"
"text/template"
mapset "github.com/deckarep/golang-set"
"github.com/google/go-github/v84/github"
"github.com/web-platform-tests/wpt.fyi/shared"
)
// nolint:gochecknoglobals // TODO: Fix gochecknoglobals lint error
var templates *template.Template
//go:embed templates/*.md
var mdFiles embed.FS
func init() {
templates = template.New("all.md").
Funcs(template.FuncMap{
"escapeMD": escapeMD,
})
_, err := templates.ParseFS(mdFiles, "templates/*.md")
if err != nil {
panic(err)
}
}
// escapeMD returns the escaped MD equivalent of the plain text data s.
func escapeMD(s string) string {
return strings.ReplaceAll(s, "|", `\|`)
}
// Summary is the generic interface of a summary template data type.
type Summary interface {
// GetCheckState returns the info needed to update a check.
GetCheckState() CheckState
// GetActions returns the actions that can be taken by the user.
GetActions() []*github.CheckRunAction
// GetSummary compiles the summary markdown template.
GetSummary() (string, error)
}
// CheckState represents all the status fields for updating a check.
type CheckState struct {
HostName string // The host (e.g. wpt.fyi)
TestRun *shared.TestRun // The (completed) TestRun, if applicable.
Product shared.ProductSpec
HeadSHA string
DetailsURL *url.URL
// The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.)
Status string
// Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required".
// (Optional. Required if you provide a status of "completed".)
Conclusion *string
Actions []github.CheckRunAction
PRNumbers []int
}
// Name returns the check run's name, based on the product.
func (c CheckState) Name() string {
host := c.HostName
if host == "" {
host = "wpt.fyi"
}
spec := shared.ProductSpec{} // nolint:exhaustruct // TODO: Fix exhaustruct lint error
spec.BrowserName = c.Product.BrowserName
if c.Product.IsExperimental() {
spec.Labels = mapset.NewSetWith(shared.ExperimentalLabel)
}
return fmt.Sprintf("%s - %s", host, spec.String())
}
// Title returns the check run's title, based on the product.
func (c CheckState) Title() string {
return fmt.Sprintf("%s results", c.Product.DisplayName())
}
// GetCheckState returns the info in the CheckState struct.
// It's a dumb placeholder since we can't define fields on interfaces.
func (c CheckState) GetCheckState() CheckState {
return c
}
// FileIssueURL returns a URL for filing an issue in wpt.fyi repo about checks.
func (c CheckState) FileIssueURL() *url.URL {
result, _ := url.Parse("https://github.com/web-platform-tests/wpt.fyi/issues/new")
q := result.Query()
q.Set("title", "Regression checks issue")
q.Set("projects", "web-platform-tests/wpt.fyi/6")
q.Set("template", "checks.md")
q.Set("labels", "bug")
result.RawQuery = q.Encode()
return result
}
func compile(i interface{}, t string) (string, error) {
var dest bytes.Buffer
if err := templates.ExecuteTemplate(&dest, t, i); err != nil {
return "", err
}
return dest.String(), nil
}
================================================
FILE: api/checks/summaries/compile_test.go
================================================
//go:build medium
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package summaries
import (
"flag"
"log"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/web-platform-tests/wpt.fyi/shared"
)
// To output the rendered content during execution of the test(s), set this flag, e.g.
// go test ./api/checks/summaries -tags="medium" -print_output -test.v
var renderOutputToConsole = flag.Bool("print_output", false, "Whether to render compiled markdown during test execution.")
func TestGetSummary_Completed(t *testing.T) {
master := shared.TestRun{}
master.BrowserName = "chrome"
master.Revision = "abcdef0123"
master.FullRevisionHash = strings.Repeat(master.Revision, 4)
pr := shared.TestRun{}
pr.BrowserName = "chrome"
pr.Revision = "0123456789"
pr.FullRevisionHash = strings.Repeat(pr.Revision, 4)
foo := Completed{}
foo.BaseRun = master
foo.HeadRun = pr
foo.DiffURL = "https://foo.com/diff?before=chrome[master]&after=chrome@0123456789"
foo.HostName = "foo.com"
foo.HostURL = "https://foo.com/"
testName := "/foo.html?exclude=(Document|window|HTML.*)"
foo.Results = BeforeAndAfter{
testName: TestBeforeAndAfter{
PassingBefore: 2,
TotalBefore: 3,
PassingAfter: 2,
TotalAfter: 2,
},
}
foo.More = 1
s, err := foo.GetSummary()
printOutput(s)
if err != nil {
assert.FailNow(t, err.Error())
}
assert.Contains(t, s, foo.HostName)
assert.Contains(t, s, foo.HostURL)
assert.Contains(t, s, foo.DiffURL)
assert.Contains(t, s, "2 / 3")
assert.Contains(t, s, "And 1 others...")
assert.Contains(t, s, foo.FileIssueURL().String())
// And with MasterDiffURL
foo.MasterDiffURL = "https://foo.com/?products=chrome[master],chrome@0123456789&diff"
s, err = foo.GetSummary()
printOutput(s)
if err != nil {
assert.FailNow(t, err.Error())
}
assert.Contains(t, s, foo.MasterDiffURL)
// With PRNumbers
foo.PRNumbers = []int{123}
s, err = foo.GetSummary()
printOutput(s)
if err != nil {
assert.FailNow(t, err.Error())
}
assert.Contains(t, s, escapeMD(testName))
assert.Contains(t, s, "https://foo.com/runs/?pr=123")
assert.Contains(t, s, "https://foo.com/results/?pr=123")
}
func TestGetSummary_Pending(t *testing.T) {
foo := Pending{
RunsURL: "https://foo.com/runs?products=chrome&sha=0123456789",
}
foo.HostName = "https://foo.com"
s, err := foo.GetSummary()
printOutput(s)
if err != nil {
assert.FailNow(t, err.Error())
}
assert.Contains(t, s, foo.HostName)
assert.Contains(t, s, foo.RunsURL)
assert.Contains(t, s, foo.FileIssueURL().String())
}
func TestGetSummary_Regressed(t *testing.T) {
master := shared.TestRun{}
master.BrowserName = "chrome"
master.Revision = "abcdef0123"
master.FullRevisionHash = strings.Repeat(master.Revision, 4)
pr := shared.TestRun{}
pr.BrowserName = "chrome"
pr.Revision = "0123456789"
pr.FullRevisionHash = strings.Repeat(pr.Revision, 4)
foo := Regressed{}
foo.BaseRun = master
foo.HeadRun = pr
foo.HostName = "foo.com"
foo.HostURL = "https://foo.com/"
foo.DiffURL = "https://foo.com/?products=chrome@0000000000,chrome@0123456789&diff"
testName := "/foo.html?exclude=(Document|window|HTML.*)"
foo.Regressions = BeforeAndAfter{
testName: TestBeforeAndAfter{
PassingBefore: 1,
TotalBefore: 1,
PassingAfter: 0,
TotalAfter: 1,
},
}
foo.More = 1
s, err := foo.GetSummary()
printOutput(s)
if err != nil {
assert.FailNow(t, err.Error())
}
assert.Contains(t, s, foo.HostName)
assert.Contains(t, s, foo.HostURL)
assert.Contains(t, s, foo.DiffURL)
assert.Contains(t, s, master.String())
assert.Contains(t, s, pr.String())
assert.Contains(t, s, "0 / 1")
assert.Contains(t, s, "1 / 1")
assert.Contains(t, s, "And 1 others...")
assert.Contains(t, s, foo.FileIssueURL().String())
// And with MasterDiffURL
foo.MasterDiffURL = "https://foo.com/?products=chrome[master],chrome@0123456789&diff"
s, err = foo.GetSummary()
printOutput(s)
if err != nil {
assert.FailNow(t, err.Error())
}
assert.Contains(t, s, foo.MasterDiffURL)
// With PRNumbers
foo.PRNumbers = []int{123}
s, err = foo.GetSummary()
printOutput(s)
if err != nil {
assert.FailNow(t, err.Error())
}
assert.Contains(t, s, "https://foo.com/runs/?pr=123")
assert.Contains(t, s, "https://foo.com/results/?pr=123")
}
func printOutput(s string) {
if *renderOutputToConsole {
log.Printf("MD output:\n-----------\n%s", s)
}
}
================================================
FILE: api/checks/summaries/completed.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package summaries
import (
"github.com/google/go-github/v84/github"
"github.com/web-platform-tests/wpt.fyi/shared"
)
// ResultsComparison is all the fields shared across summaries that
// involve a result comparison.
type ResultsComparison struct {
BaseRun shared.TestRun
HeadRun shared.TestRun
MasterDiffURL string
DiffURL string // URL for the diff-view of the results
HostURL string // Host environment URL, e.g. "https://wpt.fyi"
}
// Completed is the struct for completed.md.
type Completed struct {
CheckState
ResultsComparison
Results BeforeAndAfter
More int
}
// GetCheckState returns the info needed to update a check.
func (c Completed) GetCheckState() CheckState {
return c.CheckState
}
// GetSummary executes the template for the data.
func (c Completed) GetSummary() (string, error) {
return compile(&c, "completed.md")
}
// GetActions returns the actions that can be taken by the user.
func (c Completed) GetActions() []*github.CheckRunAction {
return []*github.CheckRunAction{
RecomputeAction(),
}
}
================================================
FILE: api/checks/summaries/pending.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package summaries
import "github.com/google/go-github/v84/github"
// Pending is the struct for pending.md.
type Pending struct {
CheckState
RunsURL string // URL for the list of test runs
}
// GetCheckState returns the info needed to update a check.
func (p Pending) GetCheckState() CheckState {
return p.CheckState
}
// GetSummary executes the template for the data.
func (p Pending) GetSummary() (string, error) {
return compile(&p, "pending.md")
}
// GetActions returns the actions that can be taken by the user.
func (p Pending) GetActions() []*github.CheckRunAction {
return []*github.CheckRunAction{
CancelAction(),
}
}
================================================
FILE: api/checks/summaries/regressed.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package summaries
import (
"github.com/google/go-github/v84/github"
"github.com/web-platform-tests/wpt.fyi/shared"
)
// BeforeAndAfter summarizes counts for pass/total before and after, across a
// particular path (could be a folder, could be a test).
type BeforeAndAfter map[string]TestBeforeAndAfter
// Add the given before/after counts to the totals.
func (bna BeforeAndAfter) Add(p string, before, after shared.TestSummary) {
sum := TestBeforeAndAfter{} // nolint:exhaustruct // TODO: Fix exhaustruct lint error
if existing, ok := bna[p]; ok {
sum = existing
}
if before != nil {
sum.PassingBefore += before[0]
sum.TotalBefore += before[1]
}
if after != nil {
sum.PassingAfter += after[0]
sum.TotalAfter += after[1]
}
bna[p] = sum
}
// TestBeforeAndAfter is a struct summarizing pass rates before and after in a diff.
type TestBeforeAndAfter struct {
PassingBefore int
PassingAfter int
TotalBefore int
TotalAfter int
}
// Regressed is the struct for regressed.md.
type Regressed struct {
CheckState
ResultsComparison
Regressions BeforeAndAfter
More int
}
// GetCheckState returns the info needed to update a check.
func (r Regressed) GetCheckState() CheckState {
return r.CheckState
}
// GetSummary executes the template for the data.
func (r Regressed) GetSummary() (string, error) {
return compile(&r, "regressed.md")
}
// GetActions returns the actions that can be taken by the user.
func (r Regressed) GetActions() []*github.CheckRunAction {
return []*github.CheckRunAction{
RecomputeAction(),
IgnoreAction(),
}
}
================================================
FILE: api/checks/summaries/templates/_file_an_issue.md
================================================
> _Note: wpt.fyi checks are still in beta!_
>
> See something wrong? Please [file an issue]({{ .FileIssueURL }})!
================================================
FILE: api/checks/summaries/templates/_pr_and_master_specs.md
================================================
Run | Spec
--- | ---
`master` | {{ .BaseRun.String }}
`{{ printf "%.7s" .HeadRun.FullRevisionHash }}` | {{ .HeadRun.String }}
================================================
FILE: api/checks/summaries/templates/_pr_runs_links.md
================================================
{{- range $pr := .CheckState.PRNumbers }}
- [Latest results for PR #{{ $pr }}]({{ $.HostURL }}results/?pr={{ $pr }}&label=pr_head&max-count=1)
- [All runs for PR #{{ $pr }}]({{ $.HostURL }}runs/?pr={{ $pr }})
{{- end}}
================================================
FILE: api/checks/summaries/templates/_successfully_scraped.md
================================================
Results have successfully been scraped and added to [{{ .HostName }}]({{ .HostURL }}).
================================================
FILE: api/checks/summaries/templates/completed.md
================================================
{{ template "_successfully_scraped.md" . }}
There were no regressions detected in the results.
{{ template "_pr_and_master_specs.md" . }}
### Results
Test | `master` | `{{ printf "%.7s" .HeadRun.FullRevisionHash }}`
--- | --- | ---
{{ range $test, $results := .Results -}}
{{ escapeMD $test }} | {{ $results.PassingBefore }} / {{ $results.TotalBefore }} | {{ $results.PassingAfter }} / {{ $results.TotalAfter }}
{{end}}
{{ if gt .More 0 -}}
And {{ .More }} others...
{{ end }}
[Visual comparison of the results]({{ .DiffURL }})
Other links that might be useful:
{{ template "_pr_runs_links.md" . }}
- [`{{ printf "%.7s" .HeadRun.FullRevisionHash }}` vs its merge base]({{ .DiffURL }})
{{- if .MasterDiffURL }}
- [`{{ printf "%.7s" .HeadRun.FullRevisionHash }}` vs latest master]({{ .MasterDiffURL }})
{{- end }}
- [Latest results for `{{ printf "%.7s" .HeadRun.FullRevisionHash }}`]({{.HostURL}}?sha={{.HeadRun.Revision}}&label=pr_head)
{{ template "_file_an_issue.md" . }}
================================================
FILE: api/checks/summaries/templates/pending.md
================================================
Results have been produced, and are being collected as we speak...
They'll eventually be visible on [{{ .HostName }}]({{ .RunsURL }}).
{{ template "_file_an_issue.md" . }}
================================================
FILE: api/checks/summaries/templates/regressed.md
================================================
{{ template "_successfully_scraped.md" . }}
Uh-oh - it looks like there are some newly-failing results when we compared the affected tests
to the latest run against the `master` branch.
{{ template "_pr_and_master_specs.md" . }}
### Regressions
Test | `master` | `{{ printf "%.7s" .HeadRun.FullRevisionHash }}`
--- | --- | ---
{{ range $test, $results := .Regressions -}}
{{ escapeMD $test }} | {{ $results.PassingBefore }} / {{ $results.TotalBefore }} | {{ $results.PassingAfter }} / {{ $results.TotalAfter }}
{{end}}
{{ if gt .More 0 -}}
And {{ .More }} others...
{{ end }}
[Visual comparison of the results]({{ .DiffURL }})
Other links that might be useful:
{{ template "_pr_runs_links.md" . }}
- [`{{ printf "%.7s" .HeadRun.FullRevisionHash }}` vs its merge base]({{ .DiffURL }})
{{- if .MasterDiffURL }}
- [`{{ printf "%.7s" .HeadRun.FullRevisionHash }}` vs latest master]({{ .MasterDiffURL }})
{{- end }}
- [Latest results for `{{ printf "%.7s" .HeadRun.FullRevisionHash }}`]({{.HostURL}}results/?sha={{.HeadRun.Revision}}&label=pr_head)
{{ template "_file_an_issue.md" . }}
================================================
FILE: api/checks/update.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checks
import (
"context"
"errors"
"fmt"
"net/http"
"sort"
"strings"
"time"
mapset "github.com/deckarep/golang-set"
"github.com/gorilla/mux"
"github.com/web-platform-tests/wpt.fyi/api/checks/summaries"
"github.com/web-platform-tests/wpt.fyi/shared"
)
// CheckProcessingQueue is the name of the TaskQueue that handles processing and
// interpretation of TestRun results, in order to update the GitHub checks.
const CheckProcessingQueue = "check-processing"
const failChecksOnRegressionFeature = "failChecksOnRegression"
const onlyChangesAsRegressionsFeature = "onlyChangesAsRegressions"
// updateCheckHandler handles /api/checks/[commit] POST requests.
func updateCheckHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := shared.GetLogger(ctx)
vars := mux.Vars(r)
sha, err := shared.ParseSHA(vars["commit"])
if err != nil {
log.Warningf("Failed to parse commit: %s", err.Error())
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := r.ParseForm(); err != nil {
log.Warningf("Failed to parse form: %s", err.Error())
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
filter, err := shared.ParseTestRunFilterParams(r.Form)
if err != nil {
log.Warningf("Failed to parse params: %s", err.Error())
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if len(filter.Products) != 1 {
msg := "product param is missing"
log.Warningf("%s", msg)
http.Error(w, msg, http.StatusBadRequest)
return
}
filter.SHAs = shared.SHAs{sha}
headRun, baseRun, err := loadRunsToCompare(ctx, filter)
if err != nil {
msg := "Could not find runs to compare: " + err.Error()
log.Warningf("%s", msg)
http.Error(w, msg, http.StatusNotFound)
return
}
sha = headRun.FullRevisionHash
aeAPI := shared.NewAppEngineAPI(ctx)
diffAPI := shared.NewDiffAPI(ctx)
suites, err := NewAPI(ctx).GetSuitesForSHA(sha)
if err != nil {
log.Warningf("Failed to load CheckSuites for %s: %s", sha, err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} else if len(suites) < 1 {
log.Debugf("No CheckSuites found for %s", sha)
}
updatedAny := false
for _, suite := range suites {
var summaryData summaries.Summary
summaryData, err = getDiffSummary(aeAPI, diffAPI, suite, *baseRun, *headRun)
if errors.Is(err, shared.ErrRunNotInSearchCache) {
http.Error(w, err.Error(), http.StatusUnprocessableEntity)
return
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
updated, updateErr := updateCheckRunSummary(ctx, summaryData, suite)
if updateErr != nil {
err = updateErr
}
updatedAny = updatedAny || updated
}
if err != nil {
log.Errorf("Failed to update check_run(s): %s", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
} else if updatedAny {
_, err = w.Write([]byte("Check(s) updated"))
} else {
_, err = w.Write([]byte("No check(s) updated"))
}
if err != nil {
log.Warningf("Failed to write data in api/checks handler: %s", err.Error())
}
}
func loadRunsToCompare(ctx context.Context, filter shared.TestRunFilter) (
headRun,
baseRun *shared.TestRun,
err error,
) {
one := 1
store := shared.NewAppEngineDatastore(ctx, false)
runs, err := store.TestRunQuery().LoadTestRuns(
filter.Products,
filter.Labels,
filter.SHAs,
filter.From,
filter.To,
&one,
nil,
)
if err != nil {
return nil, nil, err
}
run := runs.First()
if run == nil {
return nil, nil, fmt.Errorf("no test run found for %s @ %s",
filter.Products[0].String(),
shared.CropString(filter.SHAs.FirstOrLatest(), 7))
}
labels := run.LabelsSet()
if labels.Contains(shared.MasterLabel) {
headRun = run
baseRun, err = loadMasterRunBefore(ctx, filter, headRun)
} else if labels.Contains(shared.PRBaseLabel) {
baseRun = run
headRun, err = loadPRRun(ctx, filter, shared.PRHeadLabel)
} else if labels.Contains(shared.PRHeadLabel) {
headRun = run
baseRun, err = loadPRRun(ctx, filter, shared.PRBaseLabel)
} else {
return nil, nil, fmt.Errorf("test run %d doesn't have pr_base, pr_head or master label", run.ID)
}
return headRun, baseRun, err
}
func loadPRRun(ctx context.Context, filter shared.TestRunFilter, extraLabel string) (*shared.TestRun, error) {
// Find the corresponding pr_base or pr_head run.
one := 1
store := shared.NewAppEngineDatastore(ctx, false)
labels := mapset.NewSetWith(extraLabel)
runs, err := store.TestRunQuery().LoadTestRuns(
filter.Products,
labels,
filter.SHAs,
nil,
nil,
&one,
nil,
)
run := runs.First()
if err != nil {
return nil, err
}
if run == nil {
err = fmt.Errorf("no test run found for %s @ %s with label %s",
filter.Products[0].String(), filter.SHAs.FirstOrLatest(), extraLabel)
}
return run, err
}
func loadMasterRunBefore(
ctx context.Context,
filter shared.TestRunFilter,
headRun *shared.TestRun,
) (*shared.TestRun, error) {
// Get the most recent, but still earlier, master run to compare.
store := shared.NewAppEngineDatastore(ctx, false)
one := 1
to := headRun.TimeStart.Add(-time.Millisecond)
labels := mapset.NewSetWith(headRun.Channel(), shared.MasterLabel)
runs, err := store.TestRunQuery().LoadTestRuns(filter.Products, labels, nil, nil, &to, &one, nil)
baseRun := runs.First()
if err != nil {
return nil, err
}
if baseRun == nil {
err = fmt.Errorf("no master run found for %s before %s",
filter.Products[0].String(), filter.SHAs.FirstOrLatest())
}
return baseRun, err
}
// nolint:ireturn // TODO: Fix ireturn lint error
func getDiffSummary(
aeAPI shared.AppEngineAPI,
diffAPI shared.DiffAPI,
suite shared.CheckSuite,
baseRun,
headRun shared.TestRun,
) (summaries.Summary, error) { // nolint:ireturn // TODO: Fix ireturn lint error
// nolint:exhaustruct // TODO: Fix exhauststruct lint error
diffFilter := shared.DiffFilterParam{Added: true, Changed: true, Deleted: true}
diff, err := diffAPI.GetRunsDiff(baseRun, headRun, diffFilter, nil)
if err != nil {
return nil, err
}
checkProduct := shared.ProductSpec{
// [browser]@[sha] is plenty specific, and avoids bad version strings.
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
ProductAtRevision: shared.ProductAtRevision{
Product: shared.Product{BrowserName: headRun.BrowserName},
Revision: headRun.Revision, // nolint:staticcheck // TODO: Fix staticcheck lint error (SA1019).
},
Labels: mapset.NewSetWith(baseRun.Channel()),
}
diffURL := diffAPI.GetDiffURL(baseRun, headRun, &diffFilter)
host := aeAPI.GetHostname()
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
checkState := summaries.CheckState{
HostName: host,
TestRun: &headRun,
Product: checkProduct,
HeadSHA: headRun.FullRevisionHash,
DetailsURL: diffURL,
Status: "completed",
PRNumbers: suite.PRNumbers,
}
var regressions mapset.Set
if aeAPI.IsFeatureEnabled(onlyChangesAsRegressionsFeature) {
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
regressionFilter := shared.DiffFilterParam{Changed: true} // Only changed items
changeOnlyDiff, err := diffAPI.GetRunsDiff(baseRun, headRun, regressionFilter, nil)
if err != nil {
return nil, err
}
regressions = changeOnlyDiff.Differences.Regressions()
} else {
regressions = diff.Differences.Regressions()
}
hasRegressions := regressions.Cardinality() > 0
neutral := "neutral"
checkState.Conclusion = &neutral
checksCanBeNonNeutral := aeAPI.IsFeatureEnabled(failChecksOnRegressionFeature)
// Set URL path to deepest shared dir.
var tests []string
if hasRegressions {
tests = shared.ToStringSlice(regressions)
} else {
tests, _ = shared.MapStringKeys(diff.AfterSummary)
}
sharedPath := "/results" + shared.GetSharedPath(tests...)
diffURL.Path = sharedPath
var summary summaries.Summary
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
resultsComparison := summaries.ResultsComparison{
BaseRun: baseRun,
HeadRun: headRun,
HostURL: fmt.Sprintf("https://%s/", host),
DiffURL: diffURL.String(),
}
if headRun.LabelsSet().Contains(shared.PRHeadLabel) {
// Deletions are meaningless and abundant comparing to master; ignore them.
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
masterDiffFilter := shared.DiffFilterParam{Added: true, Changed: true, Unchanged: true}
masterDiffURL := diffAPI.GetMasterDiffURL(headRun, &masterDiffFilter)
masterDiffURL.Path = sharedPath
resultsComparison.MasterDiffURL = masterDiffURL.String()
}
// nolint:nestif // TODO: Fix nestif lint error
if !hasRegressions {
collapsed := collapseSummary(diff, 10)
data := summaries.Completed{ // nolint:exhaustruct // TODO: Fix exhaustruct lint error.
CheckState: checkState,
ResultsComparison: resultsComparison,
Results: make(summaries.BeforeAndAfter),
}
tests, _ := shared.MapStringKeys(collapsed)
sort.Strings(tests)
for _, test := range tests {
if len(data.Results) < 10 {
data.Results[test] = collapsed[test]
} else {
data.More++
}
}
success := "success"
data.Conclusion = &success
summary = data
} else {
// nolint:exhaustruct // TODO: Fix exhaustruct lint error
data := summaries.Regressed{
CheckState: checkState,
ResultsComparison: resultsComparison,
Regressions: make(summaries.BeforeAndAfter),
}
tests := shared.ToStringSlice(regressions)
sort.Strings(tests)
for _, path := range tests {
if len(data.Regressions) <= 10 {
data.Regressions.Add(path, diff.BeforeSummary[path], diff.AfterSummary[path])
} else {
data.More++
}
}
if checksCanBeNonNeutral {
actionRequired := "action_required"
data.Conclusion = &actionRequired
}
summary = data
}
return summary, nil
}
type pathKeys []string
func (e pathKeys) Len() int { return len(e) }
func (e pathKeys) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
func (e pathKeys) Less(i, j int) bool {
return len(strings.Split(e[i], "/")) > len(strings.Split(e[j], "/"))
}
// collapseSummary collapses a tree of file paths into a smaller tree of folders.
func collapseSummary(diff shared.RunDiff, limit int) summaries.BeforeAndAfter {
beforeKeys, _ := shared.MapStringKeys(diff.BeforeSummary)
afterKeys, _ := shared.MapStringKeys(diff.AfterSummary)
keys := shared.ToStringSlice(
shared.NewSetFromStringSlice(beforeKeys).Union(shared.NewSetFromStringSlice(afterKeys)),
)
paths := shared.ToStringSlice(collapsePaths(keys, limit))
result := make(summaries.BeforeAndAfter)
for _, k := range keys {
for _, p := range paths {
if strings.HasPrefix(k, p) {
result.Add(p, diff.BeforeSummary[k], diff.AfterSummary[k])
break
}
}
}
return result
}
func collapsePaths(keys []string, limit int) mapset.Set { // nolint:ireturn // TODO: Fix ireturn lint error
result := shared.NewSetFromStringSlice(keys)
// 10 iterations to avoid edge-case infinite looping risk.
for i := 0; i < 10 && result.Cardinality() > limit; i++ {
sort.Sort(pathKeys(keys))
collapsed := mapset.NewSet()
depth := -1
for _, k := range keys {
// Something might have already collapsed down 1 dir into this one.
if collapsed.Contains(k) {
continue
}
parts := strings.Split(k, "/")
if parts[len(parts)-1] == "" {
parts = parts[:len(parts)-1]
}
if len(parts) < depth {
collapsed.Add(k)
continue
}
path := strings.Join(parts[:len(parts)-1], "/") + "/"
collapsed.Add(path)
depth = len(parts)
}
if i > 0 && depth < 3 {
break
}
keys = shared.ToStringSlice(collapsed)
result = collapsed
}
return result
}
================================================
FILE: api/checks/update_medium_test.go
================================================
//go:build medium
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checks
import (
"strconv"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/web-platform-tests/wpt.fyi/shared"
"github.com/web-platform-tests/wpt.fyi/shared/sharedtest"
)
func TestLoadRunsToCompare_master(t *testing.T) {
ctx, done, err := sharedtest.NewAEContext(true)
assert.Nil(t, err)
defer done()
testRun := shared.TestRun{
ProductAtRevision: shared.ProductAtRevision{
Product: shared.Product{
BrowserName: "chrome",
},
},
Labels: []string{"master"},
}
yesterday := time.Now().AddDate(0, 0, -1)
store := shared.NewAppEngineDatastore(ctx, false)
for i := 0; i < 2; i++ {
testRun.FullRevisionHash = strings.Repeat(strconv.Itoa(i), 40)
testRun.Revision = testRun.FullRevisionHash[:10]
testRun.TimeStart = yesterday.Add(time.Duration(i) * time.Hour)
key := store.NewIncompleteKey("TestRun")
key, _ = store.Put(key, &testRun)
}
chrome, _ := shared.ParseProductSpec("chrome")
filter := shared.TestRunFilter{
SHAs: shared.SHAs{"1111111111"},
Products: shared.ProductSpecs{chrome},
}
headRun, baseRun, err := loadRunsToCompare(ctx, filter)
assert.Nil(t, err)
assert.NotNil(t, headRun)
assert.NotNil(t, baseRun)
assert.Equal(t, "0000000000", baseRun.Revision)
assert.Equal(t, "1111111111", headRun.Revision)
}
func TestLoadRunsToCompare_pr_base_first(t *testing.T) {
ctx, done, err := sharedtest.NewAEContext(true)
assert.Nil(t, err)
defer done()
labelsForRuns := [][]string{{"pr_base"}, {"pr_head"}}
yesterday := time.Now().AddDate(0, 0, -1)
store := shared.NewAppEngineDatastore(ctx, false)
for i := 0; i < 2; i++ {
testRun := shared.TestRun{
ProductAtRevision: shared.ProductAtRevision{
Product: shared.Product{
BrowserName: "chrome",
},
Revision: "1234567890",
FullRevisionHash: "1234567890123456789012345678901234567890",
},
TimeStart: yesterday.Add(time.Duration(i) * time.Hour),
Labels: labelsForRuns[i],
}
key := store.NewIncompleteKey("TestRun")
key, _ = store.Put(key, &testRun)
}
chrome, _ := shared.ParseProductSpec("chrome")
filter := shared.TestRunFilter{
SHAs: shared.SHAs{"1234567890"},
Products: shared.ProductSpecs{chrome},
}
headRun, baseRun, err := loadRunsToCompare(ctx, filter)
assert.Nil(t, err)
assert.NotNil(t, headRun)
assert.NotNil(t, baseRun)
assert.Equal(t, []string{"pr_base"}, baseRun.Labels)
assert.Equal(t, []string{"pr_head"}, headRun.Labels)
}
func TestLoadRunsToCompare_pr_head_first(t *testing.T) {
ctx, done, err := sharedtest.NewAEContext(true)
assert.Nil(t, err)
defer done()
labelsForRuns := [][]string{{"pr_head"}, {"pr_base"}}
yesterday := time.Now().AddDate(0, 0, -1)
store := shared.NewAppEngineDatastore(ctx, false)
for i := 0; i < 2; i++ {
testRun := shared.TestRun{
ProductAtRevision: shared.ProductAtRevision{
Product: shared.Product{
BrowserName: "chrome",
},
Revision: "1234567890",
FullRevisionHash: "1234567890123456789012345678901234567890",
},
TimeStart: yesterday.Add(time.Duration(i) * time.Hour),
Labels: labelsForRuns[i],
}
key := store.NewIncompleteKey("TestRun")
key, _ = store.Put(key, &testRun)
}
chrome, _ := shared.ParseProductSpec("chrome")
filter := shared.TestRunFilter{
SHAs: shared.SHAs{"1234567890"},
Products: shared.ProductSpecs{chrome},
}
headRun, baseRun, err := loadRunsToCompare(ctx, filter)
assert.Nil(t, err)
assert.NotNil(t, headRun)
assert.NotNil(t, baseRun)
assert.Equal(t, []string{"pr_base"}, baseRun.Labels)
assert.Equal(t, []string{"pr_head"}, headRun.Labels)
}
================================================
FILE: api/checks/update_test.go
================================================
//go:build small
package checks
import (
"context"
"fmt"
"net/url"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/web-platform-tests/wpt.fyi/api/checks/summaries"
"github.com/web-platform-tests/wpt.fyi/shared"
"github.com/web-platform-tests/wpt.fyi/shared/sharedtest"
"go.uber.org/mock/gomock"
)
func TestGetDiffSummary_Regressed(t *testing.T) {
testSummary := func(enabled bool) {
t.Run(fmt.Sprintf("%s=%v", onlyChangesAsRegressionsFeature, enabled), func(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
before, after := getBeforeAndAfterRuns()
runDiff := shared.RunDiff{
Differences: shared.ResultsDiff{"/foo.html": shared.TestDiff{0, 1, 0}},
}
aeAPI := sharedtest.NewMockAppEngineAPI(mockCtrl)
aeAPI.EXPECT().Context().AnyTimes().Return(context.Background())
aeAPI.EXPECT().IsFeatureEnabled(onlyChangesAsRegressionsFeature).Return(enabled)
aeAPI.EXPECT().IsFeatureEnabled(failChecksOnRegressionFeature).Return(false)
aeAPI.EXPECT().GetHostname()
diffAPI := sharedtest.NewMockDiffAPI(mockCtrl)
diffAPI.EXPECT().GetRunsDiff(before, after, sharedtest.SameDiffFilter("ADC"), gomock.Any()).Return(runDiff, nil)
if enabled {
diffAPI.EXPECT().GetRunsDiff(before, after, sharedtest.SameDiffFilter("C"), gomock.Any()).Return(runDiff, nil)
}
diffURL, _ := url.Parse("https://wpt.fyi/results?diff")
diffAPI.EXPECT().GetDiffURL(before, after, gomock.Any()).Return(diffURL)
diffAPI.EXPECT().GetMasterDiffURL(after, sharedtest.SameDiffFilter("ACU")).Return(diffURL)
suite := shared.CheckSuite{
PRNumbers: []int{123},
}
summary, err := getDiffSummary(aeAPI, diffAPI, suite, before, after)
assert.Nil(t, err)
_, ok := summary.(summaries.Regressed)
assert.True(t, ok)
assert.Equal(t, suite.PRNumbers, summary.GetCheckState().PRNumbers)
})
}
testSummary(false)
testSummary(true)
}
func TestGetDiffSummary_Completed(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
before, after := getBeforeAndAfterRuns()
runDiff := shared.RunDiff{
Differences: shared.ResultsDiff{"/foo.html": shared.TestDiff{1, 0, 1}},
}
aeAPI := sharedtest.NewMockAppEngineAPI(mockCtrl)
aeAPI.EXPECT().Context().AnyTimes().Return(context.Background())
aeAPI.EXPECT().IsFeatureEnabled(onlyChangesAsRegressionsFeature).Return(false)
aeAPI.EXPECT().IsFeatureEnabled(failChecksOnRegressionFeature).Return(false)
aeAPI.EXPECT().GetHostname()
diffAPI := sharedtest.NewMockDiffAPI(mockCtrl)
diffAPI.EXPECT().GetRunsDiff(before, after, gomock.Any(), gomock.Any()).Return(runDiff, nil)
diffURL, _ := url.Parse("https://wpt.fyi/results?diff")
diffAPI.EXPECT().GetDiffURL(before, after, gomock.Any()).Return(diffURL)
diffAPI.EXPECT().GetMasterDiffURL(after, sharedtest.SameDiffFilter("ACU")).Return(diffURL)
suite := shared.CheckSuite{
PRNumbers: []int{123},
}
summary, err := getDiffSummary(aeAPI, diffAPI, suite, before, after)
assert.Nil(t, err)
_, ok := summary.(summaries.Completed)
assert.True(t, ok)
assert.Equal(t, suite.PRNumbers, summary.GetCheckState().PRNumbers)
}
func getBeforeAndAfterRuns() (before, after shared.TestRun) {
before.FullRevisionHash = strings.Repeat("0", 40)
before.BrowserName = "chrome"
before.Labels = []string{shared.PRBaseLabel}
after.FullRevisionHash = strings.Repeat("1", 40)
after.BrowserName = "chrome"
after.Labels = []string{shared.PRHeadLabel}
return before, after
}
func TestCollapseSummary_Nesting(t *testing.T) {
diff := shared.RunDiff{
BeforeSummary: shared.ResultsSummary{
"/foo/test.html": shared.TestSummary{1, 1},
"/foo/bar/test.html": shared.TestSummary{1, 1},
"/foo/bar/baz/test.html": shared.TestSummary{1, 1},
"/foo/bar/baz/qux/test.html": shared.TestSummary{1, 1},
},
AfterSummary: shared.ResultsSummary{
"/foo/test.html": shared.TestSummary{2, 2},
"/foo/bar/test.html": shared.TestSummary{2, 2},
"/foo/bar/baz/test.html": shared.TestSummary{2, 2},
"/foo/bar/baz/qux/test.html": shared.TestSummary{2, 2},
},
}
summary := summaries.BeforeAndAfter{
"/foo/test.html": summaries.TestBeforeAndAfter{PassingBefore: 1, TotalBefore: 1, PassingAfter: 2, TotalAfter: 2},
"/foo/bar/test.html": summaries.TestBeforeAndAfter{PassingBefore: 1, TotalBefore: 1, PassingAfter: 2, TotalAfter: 2},
"/foo/bar/baz/test.html": summaries.TestBeforeAndAfter{PassingBefore: 1, TotalBefore: 1, PassingAfter: 2, TotalAfter: 2},
"/foo/bar/baz/qux/test.html": summaries.TestBeforeAndAfter{PassingBefore: 1, TotalBefore: 1, PassingAfter: 2, TotalAfter: 2},
}
assert.Equal(t, summary, collapseSummary(diff, 4))
assert.Equal(t, summaries.BeforeAndAfter{
"/foo/test.html": summaries.TestBeforeAndAfter{PassingBefore: 1, TotalBefore: 1, PassingAfter: 2, TotalAfter: 2},
"/foo/bar/test.html": summaries.TestBeforeAndAfter{PassingBefore: 1, TotalBefore: 1, PassingAfter: 2, TotalAfter: 2},
"/foo/bar/baz/": summaries.TestBeforeAndAfter{PassingBefore: 2, TotalBefore: 2, PassingAfter: 4, TotalAfter: 4},
}, collapseSummary(diff, 3))
assert.Equal(t, summaries.BeforeAndAfter{
"/foo/test.html": summaries.TestBeforeAndAfter{PassingBefore: 1, TotalBefore: 1, PassingAfter: 2, TotalAfter: 2},
"/foo/bar/": summaries.TestBeforeAndAfter{PassingBefore: 3, TotalBefore: 3, PassingAfter: 6, TotalAfter: 6},
}, collapseSummary(diff, 2))
assert.Equal(t, summaries.BeforeAndAfter{
"/foo/": summaries.TestBeforeAndAfter{PassingBefore: 4, TotalBefore: 4, PassingAfter: 8, TotalAfter: 8},
}, collapseSummary(diff, 1))
}
func TestCollapseSummary_ManyFiles(t *testing.T) {
diff := shared.RunDiff{
BeforeSummary: make(shared.ResultsSummary),
AfterSummary: make(shared.ResultsSummary),
}
for i := 1; i <= 20; i++ {
diff.BeforeSummary[fmt.Sprintf("/foo/test%v.html", i)] = shared.TestSummary{1, 1}
diff.BeforeSummary[fmt.Sprintf("/bar/test%v.html", i)] = shared.TestSummary{1, 1}
diff.BeforeSummary[fmt.Sprintf("/baz/test%v.html", i)] = shared.TestSummary{1, 1}
diff.AfterSummary[fmt.Sprintf("/foo/test%v.html", i)] = shared.TestSummary{2, 3}
diff.AfterSummary[fmt.Sprintf("/bar/test%v.html", i)] = shared.TestSummary{2, 3}
diff.AfterSummary[fmt.Sprintf("/baz/test%v.html", i)] = shared.TestSummary{2, 3}
}
assert.Equal(t, summaries.BeforeAndAfter{
"/foo/": summaries.TestBeforeAndAfter{PassingBefore: 20, TotalBefore: 20, PassingAfter: 40, TotalAfter: 60},
"/bar/": summaries.TestBeforeAndAfter{PassingBefore: 20, TotalBefore: 20, PassingAfter: 40, TotalAfter: 60},
"/baz/": summaries.TestBeforeAndAfter{PassingBefore: 20, TotalBefore: 20, PassingAfter: 40, TotalAfter: 60},
}, collapseSummary(diff, 10))
// A number too small still does its best to collapse.
assert.Equal(t, summaries.BeforeAndAfter{
"/foo/": summaries.TestBeforeAndAfter{PassingBefore: 20, TotalBefore: 20, PassingAfter: 40, TotalAfter: 60},
"/bar/": summaries.TestBeforeAndAfter{PassingBefore: 20, TotalBefore: 20, PassingAfter: 40, TotalAfter: 60},
"/baz/": summaries.TestBeforeAndAfter{PassingBefore: 20, TotalBefore: 20, PassingAfter: 40, TotalAfter: 60},
}, collapseSummary(diff, 1))
}
================================================
FILE: api/checks/webhook.go
================================================
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checks
import (
"context"
"encoding/json"
"fmt"
"net/http"
"regexp"
"github.com/google/go-github/v84/github"
"github.com/web-platform-tests/wpt.fyi/shared"
)
const requestedAction = "requested"
const rerequestedAction = "rerequested"
// webhookGithubEvent represents the allowed GitHub webhook event types.
type webhookGithubEvent string
const (
eventCheckSuite webhookGithubEvent = "check_suite"
eventCheckRun webhookGithubEvent = "check_run"
eventPullRequest webhookGithubEvent = "pull_request"
)
var runNameRegex = regexp.MustCompile(`^(?:(?:staging\.)?wpt\.fyi - )(.*)$`)
func isWPTFYIApp(appID int64) bool {
return appID == wptfyiCheckAppID || appID == wptfyiStagingCheckAppID
}
// checkWebhookHandler handles GitHub events relating to our wpt.fyi and
// staging.wpt.fyi GitHub Apps[0], sent to the /api/webhook/check endpoint.
//
// [0]: https://github.com/apps/wpt-fyi and https://github.com/apps/staging-wpt-fyi
func checkWebhookHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := shared.GetLogger(ctx)
ds := shared.NewAppEngineDatastore(ctx, false)
contentType := r.Header.Get("Content-Type")
if contentType != "application/json" {
log.Errorf("Invalid content-type: %s", contentType)
w.WriteHeader(http.StatusBadRequest)
return
}
event := r.Header.Get("X-GitHub-Event")
inputEvent := webhookGithubEvent(event)
switch inputEvent {
case eventCheckSuite, eventCheckRun, eventPullRequest:
break
default:
log.Debugf("Ignoring %s event", event)
w.WriteHeader(http.StatusBadRequest)
return
}
secret, err := shared.GetSecret(ds, "github-check-webhook-secret")
if err != nil {
log.Errorf("Missing secret: github-check-webhook-secret")
http.Error(w, "Unable to verify request: secret not found", http.StatusInternalServerError)
return
}
payload, err := github.ValidatePayload(r, []byte(secret))
if err != nil {
log.Errorf("%v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
log.Debugf("GitHub Delivery: %s", r.Header.Get("X-GitHub-Delivery"))
var processed bool
api := NewAPI(ctx)
switch inputEvent {
case eventCheckSuite:
processed, err = handleCheckSuiteEvent(api, payload)
case eventCheckRun:
processed, err = handleCheckRunEvent(api, payload)
case eventPullRequest:
processed, err = handlePullRequestEvent(api, payload)
}
if err != nil {
log.Errorf("%v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if processed {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "wpt.fyi check(s) scheduled successfully")
} else {
w.WriteHeader(http.StatusNoContent)
fmt.Fprintln(w, "Status was ignored")
}
}
// handleCheckSuiteEvent handles a check_suite (re)requested event by ensuring
// that a check_run exists for each product that contains results for the head SHA.
// nolint:gocognit // TODO: Fix gocognit lint error
func handleCheckSuiteEvent(api API, payload []byte) (bool, error) {
log := shared.GetLogger(api.Context())
var checkSuite github.CheckSuiteEvent
if err := json.Unmarshal(payload, &checkSuite); err != nil {
return false, err
}
action := checkSuite.GetAction()
owner := checkSuite.GetRepo().GetOwner().GetLogin()
repo := checkSuite.GetRepo().GetName()
sha := checkSuite.GetCheckSuite().GetHeadSHA()
appName := checkSuite.GetCheckSuite().GetApp().GetName()
appID := checkSuite.GetCheckSuite().GetApp().GetID()
log.Debugf("Check suite %s: %s/%s @ %s (App %v, ID %v)",
action,
owner,
repo,
shared.CropString(sha, 7),
appName,
appID,
)
if !isWPTFYIApp(appID) {
log.Infof("Ignoring check_suite App ID %v", appID)
return false, nil
}
login := checkSuite.GetSender().GetLogin()
if !checksEnabledForUser(api, login) {
log.Infof("Checks not enabled for sender %s", login)
return false, nil
}
// nolint:nestif // TODO: Fix nestif lint error
if action == requestedAction || action == rerequestedAction {
pullRequests := checkSuite.GetCheckSuite().PullRequests
prNumbers := []int{}
for _, pr := range pullRequests {
if pr.GetBase().GetRepo().GetID() == wptRepoID {
prNumbers = append(prNumbers, pr.GetNumber())
}
}
installationID := checkSuite.GetInstallation().GetID()
if action == requestedAction {
for _, p := range pullRequests {
destRepoID := p.GetBase().GetRepo().GetID()
if destRepoID == wptRepoID && p.GetHead().GetRepo().GetID() != destRepoID {
// Errors are already logged by CreateWPTCheckSuite
_, _ = api.CreateWPTCheckSuite(appID, installationID, sha, prNumbers...)
}
}
}
suite, err := getOrCreateCheckSuite(api.Context(), sha, owner, repo, appID, installationID, prNumbers...)
if err != nil || suite == nil {
return false, err
}
if action == rerequestedAction {
return scheduleProcessingForExistingRuns(api.Context(), sha)
}
}
return false, nil
}
// handleCheckRunEvent handles a check_run rerequested events by updating
// the status based on whether results for the check_run's product exist.
func handleCheckRunEvent(
api API,
payload []byte) (bool, error) {
log := shared.GetLogger(api.Context())
checkRun := new(github.CheckRunEvent)
if err := json.Unmarshal(payload, checkRun); err != nil {
return false, err
}
action := checkRun.GetAction()
owner := checkRun.GetRepo().GetOwner().GetLogin()
repo := checkRun.GetRepo().GetName()
sha := checkRun.GetCheckRun().GetHeadSHA()
appName := checkRun.GetCheckRun().GetApp().GetName()
appID := checkRun.GetCheckRun().GetApp().GetID()
log.Debugf("Check run %s: %s/%s @ %s (App %v, ID %v)", action, owner, repo, shared.CropString(sha, 7), appName, appID)
if !isWPTFYIApp(appID) {
log.Infof("Ignoring check_run App ID %v", appID)
return false, nil
}
login := checkRun.GetSender().GetLogin()
if !checksEnabledForUser(api, login) {
log.Infof("Checks not enabled for sender %s", login)
return false, nil
}
// Determine whether or not we need to schedule processing the results
// of a CheckRun. The 'requested_action' event occurs when a user
// clicks on one of the 'action' buttons we setup as part of our
// CheckRuns[0]; see summaries.Summary.GetActions().
//
// [0]: https://developer.github.com/v3/checks/runs/#check-runs-and-requested-actions
status := checkRun.GetCheckRun().GetStatus()
shouldSchedule := false
if (action == "created" && status != "completed") || action == "rerequested" {
shouldSchedule = true
} else if action == "requested_action" {
actionID := checkRun.GetRequestedAction().Identifier
switch actionID {
case "recompute":
shouldSchedule = true
case "ignore":
err := api.IgnoreFailure(
login,
owner,
repo,
checkRun.GetCheckRun(),
checkRun.GetInstallation())
return err == nil, err
case "cancel":
err := api.CancelRun(
login,
owner,
repo,
checkRun.GetCheckRun(),
checkRun.GetInstallation())
return err == nil, err
default:
log.Debugf("Ignoring %s action with id %s", action, actionID)
return false, nil
}
}
if shouldSchedule {
name := checkRun.GetCheckRun().GetName()
log.Debugf("GitHub check run %v (%s @ %s) was %s", checkRun.GetCheckRun().GetID(), name, sha, action)
// Strip any "wpt.fyi - " prefix.
if runNameRegex.MatchString(name) {
name = runNameRegex.FindStringSubmatch(name)[1]
}
spec, err := shared.ParseProductSpec(name)
if err != nil {
log.Errorf("Failed to parse \"%s\" as product spec", name)
return false, err
}
// Errors are logged by ScheduleResultsProcessing
_ = api.ScheduleResultsProcessing(sha, spec)
return true, nil
}
log.Debugf("Ignoring %s action for %s check_run", action, status)
return false, nil
}
// handlePullRequestEvent reaches to pull requests from forks, ensuring that a
// GitHub check_suite is created in the main WPT repository for those. GitHub
// automatically creates a check_suite for code pushed to the WPT repository,
// so we don't need to do anything for same-repo pull requests.
func handlePullRequestEvent(api API, payload []byte) (bool, error) {
log := shared.GetLogger(api.Context())
var pullRequest github.PullRequestEvent
if err := json.Unmarshal(payload, &pullRequest); err != nil {
return false, err
}
login := pullRequest.GetPullRequest().GetUser().GetLogin()
if !checksEnabledForUser(api, login) {
log.Infof("Checks not enabled for sender %s", login)
return false, nil
}
switch pullRequest.GetAction() {
case "opened", "synchronize":
break
default:
log.Debugf("Skipping pull request action %s", pullRequest.GetAction())
return false, nil
}
sha := pullRequest.GetPullRequest().GetHead().GetSHA()
destRepoID := pullRequest.GetPullRequest().GetBase().GetRepo().GetID()
if destRepoID == wptRepoID && pullRequest.GetPullRequest().GetHead().GetRepo().GetID() != destRepoID {
// Pull is across forks; request a check suite on the main fork too.
appID, installationID := api.GetWPTRepoAppInstallationIDs()
return api.CreateWPTCheckSuite(appID, installationID, sha, pullRequest.GetNumber())
}
return false, nil
}
func scheduleProcessingForExistingRuns(ctx context.Context, sha string, products ...shared.ProductSpec) (bool, error) {
// Jump straight to completed check_run for already-present runs for the SHA.
store := shared.NewAppEngineDatastore(ctx, false)
products = shared.ProductSpecs(products).OrDefault()
runsByProduct, err := store.TestRunQuery().LoadTestRuns(products, nil, shared.SHAs{sha}, nil, nil, nil, nil)
if err != nil {
return false, fmt.Errorf("failed to load test runs: %s", err.Error())
}
createdSome := false
api := NewAPI(ctx)
for _, rbp := range runsByProduct {
if len(rbp.TestRuns) > 0 {
err := api.ScheduleResultsProcessing(sha, rbp.Product)
createdSome = createdSome || err == nil
if err != nil {
return createdSome, err
}
}
}
return createdSome, nil
}
// createCheckRun submits an http POST to create the check run on GitHub, handling JWT auth for the app.
func createCheckRun(ctx context.Context, suite shared.CheckSuite, opts github.CreateCheckRunOptions) (bool, error) {
log := shared.GetLogger(ctx)
status := ""
if opts.Status != nil {
status = *opts.Status
}
log.Debugf("Creating %s %s check_run for %s/%s @ %s", status, opts.Name, suite.Owner, suite.Repo, suite.SHA)
if suite.AppID == 0 {
suite.AppID = wptfyiStagingCheckAppID
}
client, err := getGitHubClient(ctx, suite.AppID, suite.InstallationID)
if err != nil {
log.Errorf("Failed to create JWT client: %s", err.Error())
return false, err
}
checkRun, resp, err := client.Checks.CreateCheckRun(ctx, suite.Owner, suite.Repo, opts)
if err != nil {
msg := "Failed to create check_run"
if resp != nil {
msg = fmt.Sprintf("%s: %s", msg, resp.Status)
}
log.Warningf("%s", msg)
return false, err
} else if checkRun != nil {
log.Infof("Created check_run %v", checkRun.GetID())
}
return true, nil
}
// checksEnabledForUser returns if a commit from a given GitHub username should
// cause wpt.fyi or staging.wpt.fyi summary results to show up in the GitHub
// UI. Currently this is enabled for all users on prod, but only for some users
// on staging to avoid having a confusing double-set of checks appear.
func checksEnabledForUser(api API, login string) bool {
if api.IsFeatureEnabled(checksForAllUsersFeature) {
return true
}
enabledLogins := []string{
"chromium-wpt-export-bot",
"gsnedders",
"jgraham",
"jugglinmike",
"lukebjerring",
"Ms2ger",
}
return shared.StringSliceContains(enabledLogins, login)
}
================================================
FILE: api/checks/webhook_test.go
================================================
//go:build small
// Copyright 2018 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checks
import (
"encoding/json"
"strings"
"testing"
"github.com/google/go-github/v84/github"
"github.com/stretchr/testify/assert"
"github.com/web-platform-tests/wpt.fyi/api/checks/mock_checks"
"github.com/web-platform-tests/wpt.fyi/shared"
"github.com/web-platform-tests/wpt.fyi/shared/sharedtest"
"go.uber.org/mock/gomock"
)
func TestHandleCheckRunEvent_InvalidApp(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
id := int64(123)
chrome := "chrome"
event := github.CheckRunEvent{
CheckRun: &github.CheckRun{
App: &github.App{
ID: &id,
},
Name: &chrome,
},
}
payload, _ := json.Marshal(event)
api := mock_checks.NewMockAPI(mockCtrl)
api.EXPECT().Context().AnyTimes().Return(sharedtest.NewTestContext())
processed, err := handleCheckRunEvent(api, payload)
assert.Nil(t, err)
assert.False(t, processed)
}
func TestHandleCheckRunEvent_Created_Completed(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
sha := strings.Repeat("1234567890", 4)
event := getCheckRunCreatedEvent("completed", "lukebjerring", sha)
payload, _ := json.Marshal(event)
api := mock_checks.NewMockAPI(mockCtrl)
api.EXPECT().Context().AnyTimes().Return(sharedtest.NewTestContext())
api.EXPECT().IsFeatureEnabled(checksForAllUsersFeature).Return(false)
processed, err := handleCheckRunEvent(api, payload)
assert.Nil(t, err)
assert.False(t, processed)
}
func TestHandleCheckRunEvent_Created_Pending_ChecksNotEnabledForUser(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
sha := strings.Repeat("0123456789", 4)
event := getCheckRunCreatedEvent("pending", "user-without-checks", sha)
payload, _ := json.Marshal(event)
api := mock_checks.NewMockAPI(mockCtrl)
api.EXPECT().Context().AnyTimes().Return(sharedtest.NewTestContext())
api.EXPECT().IsFeatureEnabled(checksForAllUsersFeature).Return(false)
processed, err := handleCheckRunEvent(api, payload)
assert.Nil(t, err)
assert.False(t, processed)
}
func TestHandleCheckRunEvent_Created_Pending(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
sha := strings.Repeat("0123456789", 4)
event := getCheckRunCreatedEvent("pending", "lukebjerring", sha)
payload, _ := json.Marshal(event)
api := mock_checks.NewMockAPI(mockCtrl)
api.EXPECT().Context().AnyTimes().Return(sharedtest.NewTestContext())
api.EXPECT().IsFeatureEnabled(checksForAllUsersFeature).Return(false)
api.EXPECT().ScheduleResultsProcessing(sha, sharedtest.SameProductSpec("chrome")).Return(nil)
processed, err := handleCheckRunEvent(api, payload)
assert.Nil(t, err)
assert.True(t, processed)
}
func TestHandleCheckRunEvent_ActionRequested_Ignore(t *testing.T) {
for _, prefix := range []string{"staging.wpt.fyi - ", "wpt.fyi - ", ""} {
t.Run(prefix, func(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
id := int64(wptfyiStagingCheckAppID)
sha := strings.Repeat("0123456789", 4)
name := prefix + "chrome"
requestedAction := "requested_action"
pending := "pending"
username := "lukebjerring"
owner := shared.WPTRepoOwner
repo := shared.WPTRepoName
appID := int64(wptfyiStagingCheckAppID)
event := github.CheckRunEvent{
Action: &requestedAction,
CheckRun: &github.CheckRun{
App: &github.App{ID: &id},
Name: &name,
Status: &pending,
HeadSHA: &sha,
},
Repo: &github.Repository{
Owner: &github.User{Login: &owner},
Name: &repo,
},
RequestedAction: &github.RequestedAction{Identifier: "ignore"},
Installation: &github.Installation{AppID: &appID},
Sender: &github.User{Login: &username},
}
payload, _ := json.Marshal(event)
api := mock_checks.NewMockAPI(mockCtrl)
api.EXPECT().Context().AnyTimes().Return(sharedtest.NewTestContext())
api.EXPECT().IsFeatureEnabled(checksForAllUsersFeature).Return(false)
api.EXPECT().IgnoreFailure(username, owner, repo, event.GetCheckRun(), event.GetInstallation())
processed, err := handleCheckRunEvent(api, payload)
assert.Nil(t, err)
assert.True(t, processed)
})
}
}
func TestHandleCheckRunEvent_ActionRequested_Recompute(t *testing.T) {
for _, prefix := range []string{"staging.wpt.fyi - ", "wpt.fyi - ", ""} {
t.Run(prefix, func(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
id := int64(wptfyiStagingCheckAppID)
sha := strings.Repeat("0123456789", 4)
name := prefix + "chrome[experimental]"
requestedAction := "requested_action"
pending := "pending"
username := "lukebjerring"
owner := shared.WPTRepoOwner
repo := shared.WPTRepoName
appID := int64(wptfyiStagingCheckAppID)
event := github.CheckRunEvent{
Action: &requestedAction,
CheckRun: &github.CheckRun{
App: &github.App{ID: &id},
Name: &name,
Status: &pending,
HeadSHA: &sha,
},
Repo: &github.Repository{
Owner: &github.User{Login: &owner},
Name: &repo,
},
RequestedAction: &github.RequestedAction{Identifier: "recompute"},
Installation: &github.Installation{AppID: &appID},
Sender: &github.User{Login: &username},
}
payload, _ := json.Marshal(event)
api := mock_checks.NewMockAPI(mockCtrl)
api.EXPECT().Context().AnyTimes().Return(sharedtest.NewTestContext())
api.EXPECT().IsFeatureEnabled(checksForAllUsersFeature).Return(false)
api.EXPECT().ScheduleResultsProcessing(sha, sharedtest.SameProductSpec("chrome[experimental]")).Return(nil)
processed, err := handleCheckRunEvent(api, payload)
assert.Nil(t, err)
assert.True(t, processed)
})
}
}
func TestHandleCheckRunEvent_ActionRequested_Cancel(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
sha := strings.Repeat("0123456789", 4)
username := "lukebjerring"
event := getCheckRunCreatedEvent("completed", username, sha)
requestedAction := "requested_action"
event.Action = &requestedAction
event.RequestedAction = &github.RequestedAction{Identifier: "cancel"}
payload, _ := json.Marshal(event)
api := mock_checks.NewMockAPI(mockCtrl)
api.EXPECT().Context().AnyTimes().Return(sharedtest.NewTestContext())
api.EXPECT().IsFeatureEnabled(checksForAllUsersFeature).Return(false)
api.EXPECT().CancelRun(username, shared.WPTRepoOwner, shared.WPTRepoName, event.GetCheckRun(), event.GetInstallation())
processed, err := handleCheckRunEvent(api, payload)
assert.Nil(t, err)
assert.True(t, processed)
}
func getCheckRunCreatedEvent(status, sender, sha string) github.CheckRunEvent {
id := int64(wptfyiStagingCheckAppID)
chrome := "chrome"
created := "created"
repoName := shared.WPTRepoName
repoOwner := shared.WPTRepoOwner
return github.CheckRunEvent{
Action: &created,
CheckRun: &github.CheckRun{
App: &github.App{ID: &id},
Name: &chrome,
Status: &status,
HeadSHA: &sha,
},
Repo: &github.Repository{
Name: &repoName,
Owner: &github.User{Login: &repoOwner},
},
Sender: &github.User{Login: &sender},
}
}
func TestHandlePullRequestEvent_ChecksNotEnabledForUser(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
sha := strings.Repeat("1234567890", 4)
event := getOpenedPREvent("user-without-checks", sha)
payload, _ := json.Marshal(event)
api := mock_checks.NewMockAPI(mockCtrl)
api.EXPECT().Context().AnyTimes().Return(sharedtest.NewTestContext())
api.EXPECT().IsFeatureEnabled(checksForAllUsersFeature).Return(false)
processed, err := handlePullRequestEvent(api, payload)
assert.Nil(t, err)
assert.False(t, processed)
}
func TestHandlePullRequestEvent_ChecksEnabledForUser(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
sha := strings.Repeat("1234567890", 4)
event := getOpenedPREvent("lukebjerring", sha)
payload, _ := json.Marshal(event)
api := mock_checks.NewMockAPI(mockCtrl)
api.EXPECT().Context().AnyTimes().Return(sharedtest.NewTestContext())
api.EXPECT().IsFeatureEnabled(checksForAllUsersFeature).Return(false)
api.EXPECT().GetWPTRepoAppInstallationIDs().Return(wptfyiStagingCheckAppID, wptRepoStagingInstallationID)
api.EXPECT().CreateWPTCheckSuite(wptfyiStagingCheckAppID, wptRepoStagingInstallationID, sha, 123).Return(true, nil)
processed, err := handlePullRequestEvent(api, payload)
assert.Nil(t, err)
assert.True(t, processed)
}
func getOpenedPREvent(user, sha string) github.PullRequestEvent {
opened := "opened"
// handlePullRequestEvent only operates on pull requests from forks, so
// the head repo must be different from the base.
headRepoID := wptRepoID - 1
baseRepoID := wptRepoID
number := 123
return github.PullRequestEvent{
Number: &number,
PullRequest: &github.PullRequest{
User: &github.User{Login: &user},
Head: &github.PullRequestBranch{
SHA: &sha,
Repo: &github.Repository{ID: &headRepoID},
},
Base: &github.PullRequestBranch{
Repo: &github.Repository{ID: &baseRepoID},
},
},
Action: &opened,
}
}
================================================
FILE: api/diff.go
================================================
package api //nolint:revive
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
mapset "github.com/deckarep/golang-set"
"github.com/web-platform-tests/wpt.fyi/shared"
)
// apiDiffHandler takes 2 test-run results JSON blobs and produces JSON in the same format, with only the differences
// between runs.
//
// GET takes before and after params, for historical production runs.
// POST takes only a before param, and the after state is provided in the body of the POST request.
func apiDiffHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
handleAPIDiffGet(w, r)
case http.MethodPost:
handleAPIDiffPost(w, r)
default:
http.Error(w, fmt.Sprintf("invalid HTTP method %s", r.Method), http.StatusBadRequest)
}
}
func loadDiffRuns(store shared.Datastore, q url.Values) (shared.TestRuns, error) {
// nolint:nestif // TODO: Fix nestif lint error
if runIDs, err := shared.ParseRunIDsParam(q); err != nil {
return nil, err
} else if len(runIDs) > 0 {
runs, err := runIDs.LoadTestRuns(store)
// If all errors are NoSuchEntity, we don't treat it as an error.
// If err is nil, the type conversion will fail.
var multiError *shared.MultiError
if errors.As(err, &multiError) {
all404s := true
for _, err := range multiError.Errors() {
if !errors.Is(err, shared.ErrNoSuchEntity) {
all404s = false
break
}
}
if all404s {
return nil, nil
}
}
if err != nil {
return nil, err
}
return runs, nil
}
// NOTE: We use the same params as /results, but also support
// 'before' and 'after' and 'filter'.
runFilter, err := shared.ParseTestRunFilterParams(q)
if err != nil {
return nil, err
}
if beforeAndAfter, err := shared.ParseBeforeAndAfterParams(q); err != nil {
return nil, err
} else if len(beforeAndAfter) > 0 {
runFilter.Products = beforeAndAfter
}
runsByProduct, err := LoadTestRunsForFilters(store, runFilter)
if err != nil {
return nil, err
}
return runsByProduct.AllRuns(), nil
}
func handleAPIDiffGet(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
store := shared.NewAppEngineDatastore(ctx, true)
q := r.URL.Query()
diffFilter, paths, err := shared.ParseDiffFilterParams(q)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
runs, err := loadDiffRuns(store, q)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if runs == nil {
http.NotFound(w, r)
return
}
if len(runs) != 2 {
http.Error(w, fmt.Sprintf("Diffing requires exactly 2 runs, but found %v", len(runs)), http.StatusBadRequest)
return
}
diffAPI := shared.NewDiffAPI(ctx)
diff, err := diffAPI.GetRunsDiff(runs[0], runs[1], diffFilter, paths)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var bytes []byte
if bytes, err = json.Marshal(diff); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
_, err = w.Write(bytes)
// nolint:godox // TODO: Golangci-lint found that we previously ignored the error.
// We should investigate if we should return a HTTP error or not. In the meantime, we log the error.
if err != nil {
logger := shared.GetLogger(r.Context())
logger.Warningf("Failed to write data in api/diff GET handler: %s", err.Error())
}
}
// handleAPIDiffPost handles POST requests to /api/diff, which allows the caller to produce the diff of an arbitrary
// run result JSON blob against a historical production run.
func handleAPIDiffPost(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
params, err := url.ParseQuery(r.URL.RawQuery)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
specBefore := params.Get("before")
if specBefore == "" {
http.Error(w, "before param missing", http.StatusBadRequest)
return
}
var beforeJSON shared.ResultsSummary
if beforeJSON, err = shared.FetchRunResultsJSONForParam(ctx, r, specBefore); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} else if beforeJSON == nil {
http.Error(w, specBefore+" not found", http.StatusNotFound)
return
}
var body []byte
if body, err = io.ReadAll(r.Body); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var afterJSON shared.ResultsSummary
if err := json.Unmarshal(body, &afterJSON); err != nil {
http.Error(w, "Failed to parse JSON: "+err.Error(), http.StatusBadRequest)
return
}
var filter shared.DiffFilterParam
var paths mapset.Set
if filter, paths, err = shared.ParseDiffFilterParams(params); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
diffJSON := shared.GetResultsDiff(beforeJSON, afterJSON, filter, paths, nil)
var bytes []byte
if bytes, err = json.Marshal(diffJSON); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
_, err = w.Write(bytes)
if err != nil {
logger := shared.GetLogger(r.Context())
logger.Warningf("Failed to write data in api/diff POST handler: %s", err.Error())
}
}
================================================
FILE: api/ghactions/notify.go
================================================
// Copyright 2024 The WPT Dashboard Project. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package ghactions
import (
"context"
"fmt"
"net/http"
"regexp"
"strconv"
mapset "github.com/deckarep/golang-set"
"github.com/gobwas/glob"
"github.com/google/go-github/v84/github"
uc "github.com/web-platform-tests/wpt.fyi/api/receiver/client"
"github.com/web-platform-tests/wpt.fyi/shared"
)
const uploaderName = "github-actions"
var (
prHeadRegex = regexp.MustCompile(`\baffected-tests$`)
prBaseRegex = regexp.MustCompile(`\baffected-tests-without-changes$`)
epochBranchesRegex = regexp.MustCompile("^epochs/.*")
)
func notifyHandler(w http.ResponseWriter, r *http.Request) {
rawRunID := r.FormValue("run_id")
var runID int64
var err error
if runID, err = strconv.ParseInt(rawRunID, 0, 0); err != nil {
http.Error(w, fmt.Sprintf("Invalid run id: %s", rawRunID), http.StatusBadRequest)
return
}
owner := r.FormValue("owner")
repo := r.FormValue("repo")
if owner != shared.WPTRepoOwner || repo != shared.WPTRepoName {
http.Error(w, fmt.Sprintf("Invalid repo: %s/%s", owner, repo), http.StatusBadRequest)
return
}
artifactName := r.FormValue("artifact_name")
artifactNameGlob, err := glob.Compile(artifactName)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid artifact name: %s", artifactName), http.StatusBadRequest)
return
}
ctx := r.Context()
aeAPI := shared.NewAppEngineAPI(ctx)
log := shared.GetLogger(ctx)
ghClient, err := aeAPI.GetGitHubClient()
if err != nil {
log.Errorf("Failed to get GitHub client: %s", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
processed, err := processBuild(
ctx,
aeAPI,
ghClient,
owner,
repo,
runID,
artifactNameGlob,
)
if err != nil {
log.Errorf("%v", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if processed {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "GitHub Actions workflow run artifacts retrieved successfully")
} else {
w.WriteHeader(http.StatusNoContent)
fmt.Fprintln(w, "Notification of workflow run artifacts was ignored")
}
}
func processBuild(
ctx context.Context,
aeAPI shared.AppEngineAPI,
ghClient *github.Client,
owner string,
repo string,
runID int64,
artifactNameGlob glob.Glob,
) (bool, error) {
log := shared.GetLogger(ctx)
workflowRun, _, err := ghClient.Actions.GetWorkflowRunByID(ctx, owner, repo, runID)
if err != nil {
return false, err
}
// nolint:exhaustruct // TODO: Fix exhaustruct lint error.
opts := &github.ListOptions{PerPage: 100}
archiveURLs := []string{}
var labels mapset.Set
for {
artifacts, resp, err := ghClient.Actions.ListWorkflowRunArtifacts(ctx, owner, repo, runID, opts)
if e
gitextract_pmdwueda/
├── .github/
│ ├── actions/
│ │ └── make-in-docker/
│ │ └── action.yml
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yml
│ ├── codeql.yml
│ ├── deploy.yml
│ └── docker-update.yml
├── .gitignore
├── .golangci.yaml
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── ISSUE_TEMPLATE/
│ ├── checks.md
│ ├── prod-deployment.md
│ ├── screenshots.md
│ └── search.md
├── ISSUE_TEMPLATE.md
├── LICENSE
├── Makefile
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── api/
│ ├── CORS_list.go
│ ├── README.md
│ ├── azure/
│ │ ├── api.go
│ │ ├── mock_azure/
│ │ │ └── api_mock.go
│ │ ├── notify.go
│ │ ├── routes.go
│ │ ├── webhook.go
│ │ └── webhook_test.go
│ ├── bsf_handler.go
│ ├── bsf_handler_test.go
│ ├── checks/
│ │ ├── README.md
│ │ ├── api.go
│ │ ├── jwt.go
│ │ ├── mock_checks/
│ │ │ └── api_mock.go
│ │ ├── routes.go
│ │ ├── runs.go
│ │ ├── suites.go
│ │ ├── suites_medium_test.go
│ │ ├── summaries/
│ │ │ ├── actions.go
│ │ │ ├── actions_test.go
│ │ │ ├── compile.go
│ │ │ ├── compile_test.go
│ │ │ ├── completed.go
│ │ │ ├── pending.go
│ │ │ ├── regressed.go
│ │ │ └── templates/
│ │ │ ├── _file_an_issue.md
│ │ │ ├── _pr_and_master_specs.md
│ │ │ ├── _pr_runs_links.md
│ │ │ ├── _successfully_scraped.md
│ │ │ ├── completed.md
│ │ │ ├── pending.md
│ │ │ └── regressed.md
│ │ ├── update.go
│ │ ├── update_medium_test.go
│ │ ├── update_test.go
│ │ ├── webhook.go
│ │ └── webhook_test.go
│ ├── diff.go
│ ├── ghactions/
│ │ ├── notify.go
│ │ ├── notify_test.go
│ │ └── routes.go
│ ├── labels.go
│ ├── labels_medium_test.go
│ ├── manifest/
│ │ ├── api.go
│ │ ├── mock_manifest/
│ │ │ └── api_mock.go
│ │ ├── util.go
│ │ └── util_test.go
│ ├── manifest.go
│ ├── manifest_test.go
│ ├── metadata_cache.go
│ ├── metadata_handler.go
│ ├── metadata_handler_test.go
│ ├── pending_test_runs.go
│ ├── pending_test_runs_medium_test.go
│ ├── query/
│ │ ├── README.md
│ │ ├── atoms.go
│ │ ├── atoms_test.go
│ │ ├── cache/
│ │ │ ├── README.md
│ │ │ ├── backfill/
│ │ │ │ ├── backfill.go
│ │ │ │ ├── backfill_medium_test.go
│ │ │ │ ├── backfill_test.go
│ │ │ │ └── mock_backfill/
│ │ │ │ └── backfill_mock.go
│ │ │ ├── index/
│ │ │ │ ├── aggregator.go
│ │ │ │ ├── filter.go
│ │ │ │ ├── index.go
│ │ │ │ ├── index_filter_test.go
│ │ │ │ ├── index_medium_test.go
│ │ │ │ ├── index_mock.go
│ │ │ │ ├── index_test.go
│ │ │ │ ├── results.go
│ │ │ │ ├── results_test.go
│ │ │ │ ├── tests.go
│ │ │ │ └── tests_test.go
│ │ │ ├── lru/
│ │ │ │ ├── lru.go
│ │ │ │ └── lru_test.go
│ │ │ ├── monitor/
│ │ │ │ ├── monitor.go
│ │ │ │ ├── monitor_mock.go
│ │ │ │ └── monitor_test.go
│ │ │ ├── poll/
│ │ │ │ ├── poll.go
│ │ │ │ └── poll_test.go
│ │ │ └── query/
│ │ │ ├── query.go
│ │ │ └── query_test.go
│ │ ├── concrete_query.go
│ │ ├── metadata_cache.go
│ │ ├── query.go
│ │ ├── query_test.go
│ │ ├── routes.go
│ │ ├── search.go
│ │ ├── search_medium_test.go
│ │ ├── search_test.go
│ │ ├── test/
│ │ │ └── types.go
│ │ ├── util.go
│ │ └── web_features_manifest_cache.go
│ ├── receiver/
│ │ ├── api.go
│ │ ├── api_cloud_test.go
│ │ ├── api_medium_test.go
│ │ ├── azure.go
│ │ ├── azure_test.go
│ │ ├── client/
│ │ │ ├── client.go
│ │ │ └── client_test.go
│ │ ├── create_run.go
│ │ ├── create_run_test.go
│ │ ├── gcs.go
│ │ ├── handlers.go
│ │ ├── mock_receiver/
│ │ │ └── api_mock.go
│ │ ├── receive_results.go
│ │ ├── receive_results_test.go
│ │ ├── routes.go
│ │ ├── update_pending_run.go
│ │ └── update_pending_run_test.go
│ ├── results_redirect_handler.go
│ ├── routes.go
│ ├── screenshot/
│ │ ├── cache.go
│ │ ├── model.go
│ │ ├── model_medium_test.go
│ │ └── routes.go
│ ├── screenshot_redirect_handler.go
│ ├── shas.go
│ ├── shas_medium_test.go
│ ├── taskcluster/
│ │ ├── mock_taskcluster/
│ │ │ └── webhook_mock.go
│ │ ├── routes.go
│ │ ├── webhook.go
│ │ └── webhook_test.go
│ ├── test_history.go
│ ├── test_history_test.go
│ ├── test_run.go
│ ├── test_run_medium_test.go
│ ├── test_runs.go
│ ├── test_runs_medium_test.go
│ ├── user.go
│ ├── versions.go
│ └── versions_medium_test.go
├── docs/
│ ├── admin.md
│ ├── api.md
│ ├── app-engine.md
│ ├── cache.md
│ ├── docker.md
│ ├── gcs.md
│ ├── triaging.md
│ ├── ui.md
│ └── upgrading-go.md
├── git/
│ └── hooks/
│ ├── README.md
│ └── pre-push
├── go.mod
├── go.sum
├── results-processor/
│ ├── .gcloudignore
│ ├── .gitignore
│ ├── .python-version
│ ├── Dockerfile
│ ├── README.md
│ ├── app.staging.yaml
│ ├── app.yaml
│ ├── config.py
│ ├── gsutil.py
│ ├── main.py
│ ├── mypy.ini
│ ├── processor.py
│ ├── processor_test.py
│ ├── requirements.in
│ ├── requirements.txt
│ ├── test_server.py
│ ├── test_util.py
│ ├── tox.ini
│ ├── wptreport.py
│ ├── wptreport_test.py
│ ├── wptscreenshot.py
│ └── wptscreenshot_test.py
├── scripts/
│ ├── README.md
│ ├── check_chromium_revision.py
│ ├── process_test_history.py
│ └── update_chromium_revision.py
├── shared/
│ ├── appengine.go
│ ├── appengine_test.go
│ ├── browsers.go
│ ├── browsers_test.go
│ ├── cache.go
│ ├── cache_test.go
│ ├── datastore.go
│ ├── datastore_cached.go
│ ├── datastore_cloud.go
│ ├── datastore_medium_test.go
│ ├── errors.go
│ ├── errors_test.go
│ ├── fetch_bsf.go
│ ├── fetch_bsf_test.go
│ ├── fetch_runs.go
│ ├── github_oauth.go
│ ├── logger.go
│ ├── manifest.go
│ ├── manifest_test.go
│ ├── metadata.go
│ ├── metadata_test.go
│ ├── metadata_util.go
│ ├── metadata_util_test.go
│ ├── metrics/
│ │ ├── models.go
│ │ └── models_test.go
│ ├── models.go
│ ├── models_test.go
│ ├── params.go
│ ├── params_test.go
│ ├── product_spec.go
│ ├── request_caching.go
│ ├── request_caching_test.go
│ ├── routing.go
│ ├── run_diff.go
│ ├── run_diff_test.go
│ ├── secret_manager.go
│ ├── secret_manager_cloud.go
│ ├── secret_manager_cloud_cloud_test.go
│ ├── sharedtest/
│ │ ├── README.md
│ │ ├── appengine_mock.go
│ │ ├── cache_mock.go
│ │ ├── datastore_mock.go
│ │ ├── fetch_bsf_mock.go
│ │ ├── github_oauth_mock.go
│ │ ├── io.go
│ │ ├── metadata_util_mock.go
│ │ ├── run_diff_mock.go
│ │ ├── test_run_query_mock.go
│ │ ├── triage_metadata_mock.go
│ │ └── util.go
│ ├── statuses.go
│ ├── statuses_test.go
│ ├── tag_test.go
│ ├── test_run_filter.go
│ ├── test_run_filter_test.go
│ ├── test_run_query.go
│ ├── test_run_query_medium_test.go
│ ├── triage_metadata.go
│ ├── triage_metadata_test.go
│ ├── util.go
│ ├── util_test.go
│ ├── web_features.go
│ ├── web_features_manifest_github_download.go
│ ├── web_features_manifest_github_download_test.go
│ ├── web_features_manifest_util.go
│ ├── web_features_manifest_util_test.go
│ └── web_features_test.go
├── util/
│ ├── __init__.py
│ ├── add_production_run.py
│ ├── cleanup-versions.sh
│ ├── commands.sh
│ ├── crontab-example
│ ├── deploy-comment.sh
│ ├── deploy-production.sh
│ ├── deploy-staging.sh
│ ├── deploy.sh
│ ├── docker-dev/
│ │ ├── dev_data.sh
│ │ ├── run.sh
│ │ └── web_server.sh
│ ├── generate_testrun_index.py
│ ├── gs-cors.json
│ ├── logging.sh
│ ├── populate_dev_data.go
│ ├── pull_run_into_static.py
│ ├── server-watch.sh
│ ├── tools.go
│ └── wct.sh
├── webapp/
│ ├── .gitignore
│ ├── README.md
│ ├── about_handler.go
│ ├── about_handler_medium_test.go
│ ├── admin_handler.go
│ ├── admin_handler_test.go
│ ├── analyzer_handler.go
│ ├── components/
│ │ ├── browser-picker.js
│ │ ├── channel-picker.js
│ │ ├── compat-2021.js
│ │ ├── display-logo.js
│ │ ├── github-login.js
│ │ ├── info-banner.js
│ │ ├── interop-dashboard.js
│ │ ├── interop-data-manager.js
│ │ ├── interop-data.js
│ │ ├── interop-feature-chart.js
│ │ ├── interop-summary.js
│ │ ├── interop.js
│ │ ├── loading-state.js
│ │ ├── ohm.js
│ │ ├── path.js
│ │ ├── pluralize.js
│ │ ├── product-builder.js
│ │ ├── product-info.js
│ │ ├── reftest-analyzer.js
│ │ ├── results-navigation.js
│ │ ├── self-navigator.js
│ │ ├── test/
│ │ │ ├── fixtures/
│ │ │ │ ├── interop.json
│ │ │ │ └── passrates.json
│ │ │ ├── interop-data.html
│ │ │ ├── loading-state.html
│ │ │ ├── path.html
│ │ │ ├── product-builder.html
│ │ │ ├── product-info.html
│ │ │ ├── reftest-analyzer.html
│ │ │ ├── test-file-results-table.html
│ │ │ ├── test-file-results.html
│ │ │ ├── test-run.html
│ │ │ ├── test-runs-query-builder.html
│ │ │ ├── test-runs-query.html
│ │ │ ├── test-runs.html
│ │ │ ├── test-search.html
│ │ │ ├── test-utils.html
│ │ │ ├── util/
│ │ │ │ └── helpers.js
│ │ │ ├── wpt-amend-metadata.html
│ │ │ ├── wpt-app.html
│ │ │ ├── wpt-flags.html
│ │ │ ├── wpt-metadata.html
│ │ │ ├── wpt-permalinks.html
│ │ │ └── wpt-results.html
│ │ ├── test-file-results-table.js
│ │ ├── test-file-results.js
│ │ ├── test-info.js
│ │ ├── test-results-history-timeline.js
│ │ ├── test-run.js
│ │ ├── test-runs-query-builder.js
│ │ ├── test-runs-query.js
│ │ ├── test-runs.js
│ │ ├── test-search.js
│ │ ├── utils.js
│ │ ├── wpt-amend-metadata.js
│ │ ├── wpt-bsf.js
│ │ ├── wpt-colors.js
│ │ ├── wpt-flags.js
│ │ ├── wpt-header.js
│ │ ├── wpt-insights.js
│ │ ├── wpt-metadata.js
│ │ ├── wpt-permalinks.js
│ │ ├── wpt-processor.js
│ │ └── wpt-runs.js
│ ├── components_handler.go
│ ├── components_handler_test.go
│ ├── dynamic-components/
│ │ ├── templates/
│ │ │ └── wpt-env-flags.js
│ │ └── wpt-env-flags.js
│ ├── dynamic_components_handler.go
│ ├── eslint.config.mjs
│ ├── flags_handler.go
│ ├── insights_handler.go
│ ├── interop_handler.go
│ ├── interop_handler_test.go
│ ├── login.go
│ ├── login_test.go
│ ├── package.json
│ ├── processor.go
│ ├── routes.go
│ ├── static/
│ │ ├── common.css
│ │ ├── interop-2021-experimental.csv
│ │ ├── interop-2021-stable.csv
│ │ ├── interop-2022-experimental.csv
│ │ ├── interop-2022-stable.csv
│ │ ├── interop-2023-experimental.csv
│ │ ├── interop-2023-stable.csv
│ │ ├── interop-2024-experimental.csv
│ │ ├── interop-2024-mobile-experimental.csv
│ │ ├── interop-2024-stable.csv
│ │ ├── interop-2025-experimental.csv
│ │ ├── interop-2025-mobile-experimental.csv
│ │ ├── interop-2025-stable.csv
│ │ ├── interop-data.json
│ │ ├── robots.txt
│ │ └── wptd-metrics/
│ │ └── 0-0/
│ │ ├── chrome-failures.json
│ │ ├── edge-failures.json
│ │ ├── firefox-failures.json
│ │ ├── pass-rates.json
│ │ └── safari-failures.json
│ ├── template.go
│ ├── templates/
│ │ ├── _ga.html
│ │ ├── _head_common.html
│ │ ├── _test_run_query_params.html
│ │ ├── _test_run_ui_query_params.html
│ │ ├── about.html
│ │ ├── admin_flags.html
│ │ ├── admin_upload.html
│ │ ├── analyzer.html
│ │ ├── compat-2021.html
│ │ ├── flags.html
│ │ ├── index.html
│ │ ├── insights.html
│ │ ├── interop.html
│ │ ├── processor.html
│ │ └── test-runs.html
│ ├── test_results_handler.go
│ ├── test_results_handler_medium_test.go
│ ├── test_runs_handler.go
│ ├── views/
│ │ ├── wpt-404.js
│ │ ├── wpt-app.js
│ │ └── wpt-results.js
│ ├── wct.conf.json
│ └── web/
│ ├── .gcloudignore
│ ├── Dockerfile
│ ├── app.staging.yaml
│ ├── app.yaml
│ ├── dispatch.yaml
│ ├── index.yaml
│ ├── main.go
│ ├── nginx.conf
│ ├── queue.yaml
│ └── routes_test.go
└── webdriver/
├── README.md
├── appserver.js
├── builder_test.go
├── chrome.go
├── datastore.js
├── dev-data.js
├── file_results_test.go
├── firefox.go
├── label_test.go
├── package.json
├── path-test.js
├── path_test.go
├── product_test.go
├── search_test.go
├── test_runs_test.go
├── util.js
├── webapp_server.go
├── webdriver.go
└── webdriver.js
Showing preview only (282K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3169 symbols across 283 files)
FILE: api/azure/api.go
constant PipelinesAppID (line 20) | PipelinesAppID = int64(9426)
type BuildArtifacts (line 25) | type BuildArtifacts struct
type BuildArtifact (line 31) | type BuildArtifact struct
type ArtifactResource (line 38) | type ArtifactResource struct
type Build (line 46) | type Build struct
method IsMasterBranch (line 58) | func (a *Build) IsMasterBranch() bool {
type BuildTriggerInfo (line 52) | type BuildTriggerInfo struct
type API (line 63) | type API interface
type apiImpl (line 69) | type apiImpl struct
method GetBuildURL (line 81) | func (a apiImpl) GetBuildURL(owner, repo string, buildID int64) string {
method GetAzureArtifactsURL (line 87) | func (a apiImpl) GetAzureArtifactsURL(owner, repo string, buildID int6...
method GetBuild (line 95) | func (a apiImpl) GetBuild(owner, repo string, buildID int64) (*Build, ...
function NewAPI (line 75) | func NewAPI(ctx context.Context) API {
FILE: api/azure/mock_azure/api_mock.go
type MockAPI (line 20) | type MockAPI struct
method EXPECT (line 39) | func (m *MockAPI) EXPECT() *MockAPIMockRecorder {
method GetAzureArtifactsURL (line 44) | func (m *MockAPI) GetAzureArtifactsURL(owner, repo string, buildID int...
method GetBuild (line 58) | func (m *MockAPI) GetBuild(owner, repo string, buildID int64) (*azure....
method GetBuildURL (line 73) | func (m *MockAPI) GetBuildURL(owner, repo string, buildID int64) string {
type MockAPIMockRecorder (line 27) | type MockAPIMockRecorder struct
method GetAzureArtifactsURL (line 52) | func (mr *MockAPIMockRecorder) GetAzureArtifactsURL(owner, repo, build...
method GetBuild (line 67) | func (mr *MockAPIMockRecorder) GetBuild(owner, repo, buildID any) *gom...
method GetBuildURL (line 81) | func (mr *MockAPIMockRecorder) GetBuildURL(owner, repo, buildID any) *...
function NewMockAPI (line 32) | func NewMockAPI(ctrl *gomock.Controller) *MockAPI {
FILE: api/azure/notify.go
function notifyHandler (line 16) | func notifyHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/azure/routes.go
function RegisterRoutes (line 10) | func RegisterRoutes() {
FILE: api/azure/webhook.go
constant uploaderName (line 20) | uploaderName = "azure"
function processBuild (line 32) | func processBuild(
FILE: api/azure/webhook_test.go
constant artifactsJSON (line 16) | artifactsJSON = `{
function TestParses (line 45) | func TestParses(t *testing.T) {
function TestArtifactRegexes (line 56) | func TestArtifactRegexes(t *testing.T) {
function TestEpochBranchesRegex (line 78) | func TestEpochBranchesRegex(t *testing.T) {
FILE: api/bsf_handler.go
type BSFHandler (line 16) | type BSFHandler struct
method ServeHTTP (line 33) | func (b BSFHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
function apiBSFHandler (line 21) | func apiBSFHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/bsf_handler_test.go
function TestBSFHandler_Success (line 22) | func TestBSFHandler_Success(t *testing.T) {
function TestBSFHandler_Success_WithParams (line 48) | func TestBSFHandler_Success_WithParams(t *testing.T) {
FILE: api/checks/api.go
constant wptfyiCheckAppID (line 21) | wptfyiCheckAppID = int64(23318)
constant wptfyiStagingCheckAppID (line 22) | wptfyiStagingCheckAppID = int64(19965)
constant wptRepoInstallationID (line 24) | wptRepoInstallationID = int64(577173)
constant wptRepoStagingInstallationID (line 25) | wptRepoStagingInstallationID = int64(449270)
constant wptRepoID (line 27) | wptRepoID = int64(3618133)
constant checksForAllUsersFeature (line 28) | checksForAllUsersFeature = "checksAllUsers"
type API (line 32) | type API interface
type checksAPIImpl (line 43) | type checksAPIImpl struct
method ScheduleResultsProcessing (line 60) | func (s checksAPIImpl) ScheduleResultsProcessing(sha string, product s...
method GetSuitesForSHA (line 76) | func (s checksAPIImpl) GetSuitesForSHA(sha string) ([]shared.CheckSuit...
method IgnoreFailure (line 85) | func (s checksAPIImpl) IgnoreFailure(
method CancelRun (line 124) | func (s checksAPIImpl) CancelRun(
method CreateWPTCheckSuite (line 165) | func (s checksAPIImpl) CreateWPTCheckSuite(appID, installationID int64...
method GetWPTRepoAppInstallationIDs (line 200) | func (s checksAPIImpl) GetWPTRepoAppInstallationIDs() (appID, installa...
function NewAPI (line 51) | func NewAPI(ctx context.Context) API {
FILE: api/checks/jwt.go
function getGitHubClient (line 24) | func getGitHubClient(ctx context.Context, appID, installationID int64) (...
function getJWTClient (line 36) | func getJWTClient(ctx context.Context, appID, installation int64) (*http...
function getSignedJWT (line 86) | func getSignedJWT(ctx context.Context, appID int64) (string, error) {
FILE: api/checks/mock_checks/api_mock.go
type MockAPI (line 25) | type MockAPI struct
method EXPECT (line 44) | func (m *MockAPI) EXPECT() *MockAPIMockRecorder {
method CancelRun (line 49) | func (m *MockAPI) CancelRun(sender, owner, repo string, run *github.Ch...
method Context (line 63) | func (m *MockAPI) Context() context.Context {
method CreateWPTCheckSuite (line 77) | func (m *MockAPI) CreateWPTCheckSuite(appID, installationID int64, sha...
method GetGitHubClient (line 97) | func (m *MockAPI) GetGitHubClient() (*github.Client, error) {
method GetHTTPClient (line 112) | func (m *MockAPI) GetHTTPClient() *http.Client {
method GetHTTPClientWithTimeout (line 126) | func (m *MockAPI) GetHTTPClientWithTimeout(arg0 time.Duration) *http.C...
method GetHostname (line 140) | func (m *MockAPI) GetHostname() string {
method GetResultsURL (line 154) | func (m *MockAPI) GetResultsURL(filter shared.TestRunFilter) *url.URL {
method GetResultsUploadURL (line 168) | func (m *MockAPI) GetResultsUploadURL() *url.URL {
method GetRunsURL (line 182) | func (m *MockAPI) GetRunsURL(filter shared.TestRunFilter) *url.URL {
method GetServiceHostname (line 196) | func (m *MockAPI) GetServiceHostname(service string) string {
method GetSuitesForSHA (line 210) | func (m *MockAPI) GetSuitesForSHA(sha string) ([]shared.CheckSuite, er...
method GetUploader (line 225) | func (m *MockAPI) GetUploader(uploader string) (shared.Uploader, error) {
method GetVersion (line 240) | func (m *MockAPI) GetVersion() string {
method GetVersionedHostname (line 254) | func (m *MockAPI) GetVersionedHostname() string {
method GetWPTRepoAppInstallationIDs (line 268) | func (m *MockAPI) GetWPTRepoAppInstallationIDs() (int64, int64) {
method IgnoreFailure (line 283) | func (m *MockAPI) IgnoreFailure(sender, owner, repo string, run *githu...
method IsFeatureEnabled (line 297) | func (m *MockAPI) IsFeatureEnabled(featureName string) bool {
method ScheduleResultsProcessing (line 311) | func (m *MockAPI) ScheduleResultsProcessing(sha string, browser shared...
method ScheduleTask (line 325) | func (m *MockAPI) ScheduleTask(queueName, taskName, target string, par...
type MockAPIMockRecorder (line 32) | type MockAPIMockRecorder struct
method CancelRun (line 57) | func (mr *MockAPIMockRecorder) CancelRun(sender, owner, repo, run, ins...
method Context (line 71) | func (mr *MockAPIMockRecorder) Context() *gomock.Call {
method CreateWPTCheckSuite (line 90) | func (mr *MockAPIMockRecorder) CreateWPTCheckSuite(appID, installation...
method GetGitHubClient (line 106) | func (mr *MockAPIMockRecorder) GetGitHubClient() *gomock.Call {
method GetHTTPClient (line 120) | func (mr *MockAPIMockRecorder) GetHTTPClient() *gomock.Call {
method GetHTTPClientWithTimeout (line 134) | func (mr *MockAPIMockRecorder) GetHTTPClientWithTimeout(arg0 any) *gom...
method GetHostname (line 148) | func (mr *MockAPIMockRecorder) GetHostname() *gomock.Call {
method GetResultsURL (line 162) | func (mr *MockAPIMockRecorder) GetResultsURL(filter any) *gomock.Call {
method GetResultsUploadURL (line 176) | func (mr *MockAPIMockRecorder) GetResultsUploadURL() *gomock.Call {
method GetRunsURL (line 190) | func (mr *MockAPIMockRecorder) GetRunsURL(filter any) *gomock.Call {
method GetServiceHostname (line 204) | func (mr *MockAPIMockRecorder) GetServiceHostname(service any) *gomock...
method GetSuitesForSHA (line 219) | func (mr *MockAPIMockRecorder) GetSuitesForSHA(sha any) *gomock.Call {
method GetUploader (line 234) | func (mr *MockAPIMockRecorder) GetUploader(uploader any) *gomock.Call {
method GetVersion (line 248) | func (mr *MockAPIMockRecorder) GetVersion() *gomock.Call {
method GetVersionedHostname (line 262) | func (mr *MockAPIMockRecorder) GetVersionedHostname() *gomock.Call {
method GetWPTRepoAppInstallationIDs (line 277) | func (mr *MockAPIMockRecorder) GetWPTRepoAppInstallationIDs() *gomock....
method IgnoreFailure (line 291) | func (mr *MockAPIMockRecorder) IgnoreFailure(sender, owner, repo, run,...
method IsFeatureEnabled (line 305) | func (mr *MockAPIMockRecorder) IsFeatureEnabled(featureName any) *gomo...
method ScheduleResultsProcessing (line 319) | func (mr *MockAPIMockRecorder) ScheduleResultsProcessing(sha, browser ...
method ScheduleTask (line 334) | func (mr *MockAPIMockRecorder) ScheduleTask(queueName, taskName, targe...
function NewMockAPI (line 37) | func NewMockAPI(ctrl *gomock.Controller) *MockAPI {
FILE: api/checks/routes.go
function RegisterRoutes (line 10) | func RegisterRoutes() {
FILE: api/checks/runs.go
function updateCheckRunSummary (line 17) | func updateCheckRunSummary(ctx context.Context, summary summaries.Summar...
function getExistingCheckRuns (line 93) | func getExistingCheckRuns(ctx context.Context, suite shared.CheckSuite) ...
function updateExistingCheckRunSummary (line 137) | func updateExistingCheckRunSummary(
FILE: api/checks/suites.go
function getOrCreateCheckSuite (line 13) | func getOrCreateCheckSuite(
FILE: api/checks/suites_medium_test.go
function TestGetOrCreateCheckSuite (line 17) | func TestGetOrCreateCheckSuite(t *testing.T) {
FILE: api/checks/summaries/actions.go
function RecomputeAction (line 12) | func RecomputeAction() *github.CheckRunAction {
function IgnoreAction (line 22) | func IgnoreAction() *github.CheckRunAction {
function CancelAction (line 31) | func CancelAction() *github.CheckRunAction {
FILE: api/checks/summaries/actions_test.go
function TestActionCharacterLimits (line 17) | func TestActionCharacterLimits(t *testing.T) {
FILE: api/checks/summaries/compile.go
function init (line 27) | func init() {
function escapeMD (line 39) | func escapeMD(s string) string {
type Summary (line 44) | type Summary interface
type CheckState (line 56) | type CheckState struct
method Name (line 72) | func (c CheckState) Name() string {
method Title (line 87) | func (c CheckState) Title() string {
method GetCheckState (line 93) | func (c CheckState) GetCheckState() CheckState {
method FileIssueURL (line 98) | func (c CheckState) FileIssueURL() *url.URL {
function compile (line 110) | func compile(i interface{}, t string) (string, error) {
FILE: api/checks/summaries/compile_test.go
function TestGetSummary_Completed (line 23) | func TestGetSummary_Completed(t *testing.T) {
function TestGetSummary_Pending (line 82) | func TestGetSummary_Pending(t *testing.T) {
function TestGetSummary_Regressed (line 97) | func TestGetSummary_Regressed(t *testing.T) {
function printOutput (line 158) | func printOutput(s string) {
FILE: api/checks/summaries/completed.go
type ResultsComparison (line 14) | type ResultsComparison struct
type Completed (line 23) | type Completed struct
method GetCheckState (line 32) | func (c Completed) GetCheckState() CheckState {
method GetSummary (line 37) | func (c Completed) GetSummary() (string, error) {
method GetActions (line 42) | func (c Completed) GetActions() []*github.CheckRunAction {
FILE: api/checks/summaries/pending.go
type Pending (line 10) | type Pending struct
method GetCheckState (line 17) | func (p Pending) GetCheckState() CheckState {
method GetSummary (line 22) | func (p Pending) GetSummary() (string, error) {
method GetActions (line 27) | func (p Pending) GetActions() []*github.CheckRunAction {
FILE: api/checks/summaries/regressed.go
type BeforeAndAfter (line 14) | type BeforeAndAfter
method Add (line 17) | func (bna BeforeAndAfter) Add(p string, before, after shared.TestSumma...
type TestBeforeAndAfter (line 34) | type TestBeforeAndAfter struct
type Regressed (line 42) | type Regressed struct
method GetCheckState (line 51) | func (r Regressed) GetCheckState() CheckState {
method GetSummary (line 56) | func (r Regressed) GetSummary() (string, error) {
method GetActions (line 61) | func (r Regressed) GetActions() []*github.CheckRunAction {
FILE: api/checks/update.go
constant CheckProcessingQueue (line 25) | CheckProcessingQueue = "check-processing"
constant failChecksOnRegressionFeature (line 27) | failChecksOnRegressionFeature = "failChecksOnRegression"
constant onlyChangesAsRegressionsFeature (line 28) | onlyChangesAsRegressionsFeature = "onlyChangesAsRegressions"
function updateCheckHandler (line 31) | func updateCheckHandler(w http.ResponseWriter, r *http.Request) {
function loadRunsToCompare (line 123) | func loadRunsToCompare(ctx context.Context, filter shared.TestRunFilter) (
function loadPRRun (line 166) | func loadPRRun(ctx context.Context, filter shared.TestRunFilter, extraLa...
function loadMasterRunBefore (line 192) | func loadMasterRunBefore(
function getDiffSummary (line 216) | func getDiffSummary(
type pathKeys (line 344) | type pathKeys
method Len (line 346) | func (e pathKeys) Len() int { return len(e) }
method Swap (line 347) | func (e pathKeys) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
method Less (line 348) | func (e pathKeys) Less(i, j int) bool {
function collapseSummary (line 353) | func collapseSummary(diff shared.RunDiff, limit int) summaries.BeforeAnd...
function collapsePaths (line 374) | func collapsePaths(keys []string, limit int) mapset.Set { // nolint:iret...
FILE: api/checks/update_medium_test.go
function TestLoadRunsToCompare_master (line 19) | func TestLoadRunsToCompare_master(t *testing.T) {
function TestLoadRunsToCompare_pr_base_first (line 56) | func TestLoadRunsToCompare_pr_base_first(t *testing.T) {
function TestLoadRunsToCompare_pr_head_first (line 94) | func TestLoadRunsToCompare_pr_head_first(t *testing.T) {
FILE: api/checks/update_test.go
function TestGetDiffSummary_Regressed (line 19) | func TestGetDiffSummary_Regressed(t *testing.T) {
function TestGetDiffSummary_Completed (line 58) | func TestGetDiffSummary_Completed(t *testing.T) {
function getBeforeAndAfterRuns (line 88) | func getBeforeAndAfterRuns() (before, after shared.TestRun) {
function TestCollapseSummary_Nesting (line 98) | func TestCollapseSummary_Nesting(t *testing.T) {
function TestCollapseSummary_ManyFiles (line 134) | func TestCollapseSummary_ManyFiles(t *testing.T) {
FILE: api/checks/webhook.go
constant requestedAction (line 18) | requestedAction = "requested"
constant rerequestedAction (line 19) | rerequestedAction = "rerequested"
type webhookGithubEvent (line 22) | type webhookGithubEvent
constant eventCheckSuite (line 25) | eventCheckSuite webhookGithubEvent = "check_suite"
constant eventCheckRun (line 26) | eventCheckRun webhookGithubEvent = "check_run"
constant eventPullRequest (line 27) | eventPullRequest webhookGithubEvent = "pull_request"
function isWPTFYIApp (line 32) | func isWPTFYIApp(appID int64) bool {
function checkWebhookHandler (line 40) | func checkWebhookHandler(w http.ResponseWriter, r *http.Request) {
function handleCheckSuiteEvent (line 111) | func handleCheckSuiteEvent(api API, payload []byte) (bool, error) {
function handleCheckRunEvent (line 183) | func handleCheckRunEvent(
function handlePullRequestEvent (line 282) | func handlePullRequestEvent(api API, payload []byte) (bool, error) {
function scheduleProcessingForExistingRuns (line 317) | func scheduleProcessingForExistingRuns(ctx context.Context, sha string, ...
function createCheckRun (line 341) | func createCheckRun(ctx context.Context, suite shared.CheckSuite, opts g...
function checksEnabledForUser (line 378) | func checksEnabledForUser(api API, login string) bool {
FILE: api/checks/webhook_test.go
function TestHandleCheckRunEvent_InvalidApp (line 21) | func TestHandleCheckRunEvent_InvalidApp(t *testing.T) {
function TestHandleCheckRunEvent_Created_Completed (line 45) | func TestHandleCheckRunEvent_Created_Completed(t *testing.T) {
function TestHandleCheckRunEvent_Created_Pending_ChecksNotEnabledForUser (line 62) | func TestHandleCheckRunEvent_Created_Pending_ChecksNotEnabledForUser(t *...
function TestHandleCheckRunEvent_Created_Pending (line 79) | func TestHandleCheckRunEvent_Created_Pending(t *testing.T) {
function TestHandleCheckRunEvent_ActionRequested_Ignore (line 97) | func TestHandleCheckRunEvent_ActionRequested_Ignore(t *testing.T) {
function TestHandleCheckRunEvent_ActionRequested_Recompute (line 142) | func TestHandleCheckRunEvent_ActionRequested_Recompute(t *testing.T) {
function TestHandleCheckRunEvent_ActionRequested_Cancel (line 187) | func TestHandleCheckRunEvent_ActionRequested_Cancel(t *testing.T) {
function getCheckRunCreatedEvent (line 209) | func getCheckRunCreatedEvent(status, sender, sha string) github.CheckRun...
function TestHandlePullRequestEvent_ChecksNotEnabledForUser (line 231) | func TestHandlePullRequestEvent_ChecksNotEnabledForUser(t *testing.T) {
function TestHandlePullRequestEvent_ChecksEnabledForUser (line 248) | func TestHandlePullRequestEvent_ChecksEnabledForUser(t *testing.T) {
function getOpenedPREvent (line 267) | func getOpenedPREvent(user, sha string) github.PullRequestEvent {
FILE: api/diff.go
function apiDiffHandler (line 20) | func apiDiffHandler(w http.ResponseWriter, r *http.Request) {
function loadDiffRuns (line 31) | func loadDiffRuns(store shared.Datastore, q url.Values) (shared.TestRuns...
function handleAPIDiffGet (line 79) | func handleAPIDiffGet(w http.ResponseWriter, r *http.Request) {
function handleAPIDiffPost (line 134) | func handleAPIDiffPost(w http.ResponseWriter, r *http.Request) {
FILE: api/ghactions/notify.go
constant uploaderName (line 22) | uploaderName = "github-actions"
function notifyHandler (line 30) | func notifyHandler(w http.ResponseWriter, r *http.Request) {
function processBuild (line 95) | func processBuild(
function chooseLabels (line 176) | func chooseLabels( // nolint:ireturn // TODO: Fix ireturn lint error
FILE: api/ghactions/notify_test.go
function PointerTo (line 16) | func PointerTo[T any](v T) *T {
function TestArtifactRegexes (line 20) | func TestArtifactRegexes(t *testing.T) {
function TestEpochBranchesRegex (line 29) | func TestEpochBranchesRegex(t *testing.T) {
function TestChooseLabels (line 39) | func TestChooseLabels(t *testing.T) {
FILE: api/ghactions/routes.go
function RegisterRoutes (line 10) | func RegisterRoutes() {
FILE: api/labels.go
type LabelsHandler (line 19) | type LabelsHandler struct
method ServeHTTP (line 37) | func (h LabelsHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques...
function apiLabelsHandler (line 24) | func apiLabelsHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/labels_medium_test.go
function TestLabelsHandler (line 21) | func TestLabelsHandler(t *testing.T) {
function parseLabelsResponse (line 40) | func parseLabelsResponse(t *testing.T, w *httptest.ResponseRecorder) []s...
FILE: api/manifest.go
function apiManifestHandler (line 19) | func apiManifestHandler(w http.ResponseWriter, r *http.Request) {
function getManifest (line 47) | func getManifest(log shared.Logger, manifestAPI manifest.API, sha string...
function manifestCacheKey (line 116) | func manifestCacheKey(sha string) string {
function readByKey (line 120) | func readByKey(readable shared.Readable, key string) ([]byte, error) {
function writeByKey (line 130) | func writeByKey(writable shared.ReadWritable, key string, body []byte) e...
FILE: api/manifest/api.go
type API (line 25) | type API interface
type apiImpl (line 30) | type apiImpl struct
method GetManifestForSHA (line 44) | func (a apiImpl) GetManifestForSHA(sha string) (fetchedSHA string, man...
method NewRedis (line 129) | func (a apiImpl) NewRedis(duration time.Duration) shared.ReadWritable {
function NewAPI (line 36) | func NewAPI(ctx context.Context) API {
function getGitHubReleaseAssetForSHA (line 60) | func getGitHubReleaseAssetForSHA(aeAPI shared.AppEngineAPI, sha string) (
FILE: api/manifest/mock_manifest/api_mock.go
type MockAPI (line 21) | type MockAPI struct
method EXPECT (line 40) | func (m *MockAPI) EXPECT() *MockAPIMockRecorder {
method GetManifestForSHA (line 45) | func (m *MockAPI) GetManifestForSHA(arg0 string) (string, []byte, erro...
method NewRedis (line 61) | func (m *MockAPI) NewRedis(duration time.Duration) shared.ReadWritable {
type MockAPIMockRecorder (line 28) | type MockAPIMockRecorder struct
method GetManifestForSHA (line 55) | func (mr *MockAPIMockRecorder) GetManifestForSHA(arg0 any) *gomock.Call {
method NewRedis (line 69) | func (mr *MockAPIMockRecorder) NewRedis(duration any) *gomock.Call {
function NewMockAPI (line 33) | func NewMockAPI(ctrl *gomock.Controller) *MockAPI {
FILE: api/manifest/util.go
function Filter (line 15) | func Filter(body []byte, paths []string) (result []byte, err error) {
FILE: api/manifest/util_test.go
function TestFilter (line 15) | func TestFilter(t *testing.T) {
FILE: api/manifest_test.go
function TestGetGitHubReleaseAsset_Caches (line 25) | func TestGetGitHubReleaseAsset_Caches(t *testing.T) {
function getManifestPayload (line 106) | func getManifestPayload(data string) []byte {
FILE: api/metadata_cache.go
constant metadataCacheKey (line 17) | metadataCacheKey = "WPT-METADATA"
constant metadataCacheExpiry (line 18) | metadataCacheExpiry = time.Minute * 10
type webappMetadataFetcher (line 20) | type webappMetadataFetcher struct
method Fetch (line 27) | func (f webappMetadataFetcher) Fetch() (sha *string, res map[string][]...
function getMetadataFromRedis (line 60) | func getMetadataFromRedis(cache shared.ObjectCache) (sha *string, res ma...
function fillMetadataToRedis (line 82) | func fillMetadataToRedis(cache shared.ObjectCache, sha string, metadataB...
FILE: api/metadata_handler.go
type MetadataHandler (line 20) | type MetadataHandler struct
method ServeHTTP (line 198) | func (h MetadataHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ...
function apiMetadataHandler (line 26) | func apiMetadataHandler(w http.ResponseWriter, r *http.Request) {
function apiMetadataTriageHandler (line 50) | func apiMetadataTriageHandler(w http.ResponseWriter, r *http.Request) {
function handleMetadataTriage (line 91) | func handleMetadataTriage(
function filterMetadata (line 277) | func filterMetadata(linkQuery query.AbstractLink, metadata shared.Metada...
function apiPendingMetadataHandler (line 293) | func apiPendingMetadataHandler(w http.ResponseWriter, r *http.Request) {
function handlePendingMetadata (line 306) | func handlePendingMetadata(
FILE: api/metadata_handler_test.go
function TestHandleMetadataTriage_Success (line 24) | func TestHandleMetadataTriage_Success(t *testing.T) {
function TestHandleMetadataTriage_FailToCachePr (line 60) | func TestHandleMetadataTriage_FailToCachePr(t *testing.T) {
function TestHandleMetadataTriage_FailToCacheMetadata (line 93) | func TestHandleMetadataTriage_FailToCacheMetadata(t *testing.T) {
function TestHandleMetadataTriage_InvalidURL (line 129) | func TestHandleMetadataTriage_InvalidURL(t *testing.T) {
function TestHandleMetadataTriage_NonSimpleRequests (line 158) | func TestHandleMetadataTriage_NonSimpleRequests(t *testing.T) {
function TestHandleMetadataTriage_WrongContentType (line 185) | func TestHandleMetadataTriage_WrongContentType(t *testing.T) {
function TestHandleMetadataTriage_InvalidBody (line 205) | func TestHandleMetadataTriage_InvalidBody(t *testing.T) {
function TestHandleMetadataTriage_InvalidProduct (line 216) | func TestHandleMetadataTriage_InvalidProduct(t *testing.T) {
function TestMetadataHanlder_GET_Success (line 240) | func TestMetadataHanlder_GET_Success(t *testing.T) {
function TestMetadataHanlder_GET_MissingProducts (line 269) | func TestMetadataHanlder_GET_MissingProducts(t *testing.T) {
function TestMetadataHandler_POST_Success (line 279) | func TestMetadataHandler_POST_Success(t *testing.T) {
function TestMetadataHandler_POST_MissingProducts (line 319) | func TestMetadataHandler_POST_MissingProducts(t *testing.T) {
function TestMetadataHandler_POST_NotLink (line 336) | func TestMetadataHandler_POST_NotLink(t *testing.T) {
function TestMetadataHandler_POST_NotJustLink (line 353) | func TestMetadataHandler_POST_NotJustLink(t *testing.T) {
function TestFilterMetadata (line 373) | func TestFilterMetadata(t *testing.T) {
function getMetadataTestData (line 397) | func getMetadataTestData() map[string][]byte {
function TestPendingMetadataHandler_Success (line 419) | func TestPendingMetadataHandler_Success(t *testing.T) {
function TestPendingMetadataHandler_EmptyObjectCache (line 501) | func TestPendingMetadataHandler_EmptyObjectCache(t *testing.T) {
function TestPendingMetadataHandler_Fail (line 531) | func TestPendingMetadataHandler_Fail(t *testing.T) {
FILE: api/pending_test_runs.go
function apiPendingTestRunsHandler (line 20) | func apiPendingTestRunsHandler(w http.ResponseWriter, r *http.Request) {
function emit (line 66) | func emit(ctx context.Context, w http.ResponseWriter, i interface{}) {
FILE: api/pending_test_runs_medium_test.go
function createPendingRun (line 21) | func createPendingRun(ctx context.Context, run *shared.PendingTestRun) e...
function TestAPIPendingTestHandler (line 29) | func TestAPIPendingTestHandler(t *testing.T) {
function TestAPIPendingTestHandler_invalidFilter (line 127) | func TestAPIPendingTestHandler_invalidFilter(t *testing.T) {
FILE: api/query/atoms.go
type AbstractQuery (line 50) | type AbstractQuery interface
type RunQuery (line 57) | type RunQuery struct
method UnmarshalJSON (line 556) | func (rq *RunQuery) UnmarshalJSON(b []byte) error {
type True (line 63) | type True struct
method BindToRuns (line 67) | func (t True) BindToRuns(_ ...shared.TestRun) ConcreteQuery {
type False (line 72) | type False struct
method BindToRuns (line 76) | func (f False) BindToRuns(_ ...shared.TestRun) ConcreteQuery {
type TestNamePattern (line 81) | type TestNamePattern struct
method BindToRuns (line 87) | func (tnp TestNamePattern) BindToRuns(_ ...shared.TestRun) ConcreteQue...
method UnmarshalJSON (line 584) | func (tnp *TestNamePattern) UnmarshalJSON(b []byte) error {
type SubtestNamePattern (line 92) | type SubtestNamePattern struct
method BindToRuns (line 98) | func (tnp SubtestNamePattern) BindToRuns(_ ...shared.TestRun) Concrete...
method UnmarshalJSON (line 605) | func (tnp *SubtestNamePattern) UnmarshalJSON(b []byte) error {
type TestPath (line 104) | type TestPath struct
method BindToRuns (line 110) | func (tp TestPath) BindToRuns(_ ...shared.TestRun) ConcreteQuery {
method UnmarshalJSON (line 625) | func (tp *TestPath) UnmarshalJSON(b []byte) error {
type AbstractExists (line 116) | type AbstractExists struct
method BindToRuns (line 123) | func (e AbstractExists) BindToRuns(runs ...shared.TestRun) ConcreteQue...
method UnmarshalJSON (line 800) | func (e *AbstractExists) UnmarshalJSON(b []byte) error {
type AbstractAll (line 151) | type AbstractAll struct
method BindToRuns (line 158) | func (e AbstractAll) BindToRuns(runs ...shared.TestRun) ConcreteQuery {
method UnmarshalJSON (line 826) | func (e *AbstractAll) UnmarshalJSON(b []byte) error {
type AbstractNone (line 180) | type AbstractNone struct
method BindToRuns (line 186) | func (e AbstractNone) BindToRuns(runs ...shared.TestRun) ConcreteQuery {
method UnmarshalJSON (line 852) | func (e *AbstractNone) UnmarshalJSON(b []byte) error {
type AbstractSequential (line 195) | type AbstractSequential struct
method BindToRuns (line 202) | func (e AbstractSequential) BindToRuns(runs ...shared.TestRun) Concret...
method UnmarshalJSON (line 878) | func (e *AbstractSequential) UnmarshalJSON(b []byte) error {
type AbstractCount (line 220) | type AbstractCount struct
method BindToRuns (line 228) | func (c AbstractCount) BindToRuns(runs ...shared.TestRun) ConcreteQuery {
method UnmarshalJSON (line 904) | func (c *AbstractCount) UnmarshalJSON(b []byte) (err error) {
type AbstractMoreThan (line 242) | type AbstractMoreThan struct
method BindToRuns (line 249) | func (m AbstractMoreThan) BindToRuns(runs ...shared.TestRun) ConcreteQ...
method UnmarshalJSON (line 961) | func (m *AbstractMoreThan) UnmarshalJSON(b []byte) (err error) {
type AbstractLessThan (line 257) | type AbstractLessThan struct
method BindToRuns (line 264) | func (l AbstractLessThan) BindToRuns(runs ...shared.TestRun) ConcreteQ...
method UnmarshalJSON (line 932) | func (l *AbstractLessThan) UnmarshalJSON(b []byte) error {
type AbstractLink (line 272) | type AbstractLink struct
method BindToRuns (line 281) | func (l AbstractLink) BindToRuns(runs ...shared.TestRun) ConcreteQuery {
method UnmarshalJSON (line 989) | func (l *AbstractLink) UnmarshalJSON(b []byte) error {
type AbstractTriaged (line 297) | type AbstractTriaged struct
method BindToRuns (line 305) | func (t AbstractTriaged) BindToRuns(runs ...shared.TestRun) ConcreteQu...
method UnmarshalJSON (line 1057) | func (t *AbstractTriaged) UnmarshalJSON(b []byte) error {
type AbstractTestLabel (line 340) | type AbstractTestLabel struct
method BindToRuns (line 347) | func (t AbstractTestLabel) BindToRuns(_ ...shared.TestRun) ConcreteQue...
method UnmarshalJSON (line 1010) | func (t *AbstractTestLabel) UnmarshalJSON(b []byte) error {
type webFeaturesManifestFetcher (line 369) | type webFeaturesManifestFetcher interface
type AbstractTestWebFeature (line 375) | type AbstractTestWebFeature struct
method BindToRuns (line 382) | func (t AbstractTestWebFeature) BindToRuns(_ ...shared.TestRun) Concre...
type MetadataQuality (line 393) | type MetadataQuality
method BindToRuns (line 411) | func (q MetadataQuality) BindToRuns(_ ...shared.TestRun) ConcreteQuery {
method UnmarshalJSON (line 1089) | func (q *MetadataQuality) UnmarshalJSON(b []byte) (err error) {
constant MetadataQualityUnknown (line 397) | MetadataQualityUnknown MetadataQuality = iota
constant MetadataQualityDifferent (line 400) | MetadataQualityDifferent
constant MetadataQualityTentative (line 403) | MetadataQualityTentative
constant MetadataQualityOptional (line 406) | MetadataQualityOptional
type TestStatusEq (line 418) | type TestStatusEq struct
method BindToRuns (line 434) | func (tse TestStatusEq) BindToRuns(runs ...shared.TestRun) ConcreteQue...
method UnmarshalJSON (line 647) | func (tse *TestStatusEq) UnmarshalJSON(b []byte) error {
type TestStatusNeq (line 426) | type TestStatusNeq struct
method BindToRuns (line 459) | func (tsn TestStatusNeq) BindToRuns(runs ...shared.TestRun) ConcreteQu...
method UnmarshalJSON (line 687) | func (tsn *TestStatusNeq) UnmarshalJSON(b []byte) error {
type AbstractNot (line 482) | type AbstractNot struct
method BindToRuns (line 488) | func (n AbstractNot) BindToRuns(runs ...shared.TestRun) ConcreteQuery {
method UnmarshalJSON (line 729) | func (n *AbstractNot) UnmarshalJSON(b []byte) error {
type AbstractOr (line 493) | type AbstractOr struct
method BindToRuns (line 499) | func (o AbstractOr) BindToRuns(runs ...shared.TestRun) ConcreteQuery {
method UnmarshalJSON (line 748) | func (o *AbstractOr) UnmarshalJSON(b []byte) error {
type AbstractAnd (line 524) | type AbstractAnd struct
method BindToRuns (line 530) | func (a AbstractAnd) BindToRuns(runs ...shared.TestRun) ConcreteQuery {
method UnmarshalJSON (line 774) | func (a *AbstractAnd) UnmarshalJSON(b []byte) error {
type TestWebFeatureAtom (line 1030) | type TestWebFeatureAtom struct
method UnmarshalJSON (line 1036) | func (t *TestWebFeatureAtom) UnmarshalJSON(b []byte) error {
function MetadataQualityFromString (line 1109) | func MetadataQualityFromString(quality string) (MetadataQuality, error) {
function unmarshalQ (line 1123) | func unmarshalQ(b []byte) (AbstractQuery, error) {
FILE: api/query/atoms_test.go
function TestStructuredQuery_empty (line 19) | func TestStructuredQuery_empty(t *testing.T) {
function TestStructuredQuery_missingRunIDs (line 25) | func TestStructuredQuery_missingRunIDs(t *testing.T) {
function TestStructuredQuery_missingQuery (line 35) | func TestStructuredQuery_missingQuery(t *testing.T) {
function TestStructuredQuery_emptyRunIDs (line 44) | func TestStructuredQuery_emptyRunIDs(t *testing.T) {
function TestStructuredQuery_emptyBrowserName (line 55) | func TestStructuredQuery_emptyBrowserName(t *testing.T) {
function TestStructuredQuery_missingStatus (line 67) | func TestStructuredQuery_missingStatus(t *testing.T) {
function TestStructuredQuery_badStatus (line 78) | func TestStructuredQuery_badStatus(t *testing.T) {
function TestStructuredQuery_unknownStatus (line 89) | func TestStructuredQuery_unknownStatus(t *testing.T) {
function TestStructuredQuery_missingPattern (line 106) | func TestStructuredQuery_missingPattern(t *testing.T) {
function TestStructuredQuery_emptyPattern (line 115) | func TestStructuredQuery_emptyPattern(t *testing.T) {
function TestStructuredQuery_pattern (line 127) | func TestStructuredQuery_pattern(t *testing.T) {
function TestStructuredQuery_subtest (line 139) | func TestStructuredQuery_subtest(t *testing.T) {
function TestStructuredQuery_path (line 151) | func TestStructuredQuery_path(t *testing.T) {
function TestStructuredQuery_legacyBrowserName (line 163) | func TestStructuredQuery_legacyBrowserName(t *testing.T) {
function TestStructuredQuery_status (line 179) | func TestStructuredQuery_status(t *testing.T) {
function TestStructuredQuery_statusNeq (line 195) | func TestStructuredQuery_statusNeq(t *testing.T) {
function TestStructuredQuery_statusUnsupportedAbstractNot (line 211) | func TestStructuredQuery_statusUnsupportedAbstractNot(t *testing.T) {
function TestStructuredQuery_not (line 223) | func TestStructuredQuery_not(t *testing.T) {
function TestStructuredQuery_or (line 237) | func TestStructuredQuery_or(t *testing.T) {
function TestStructuredQuery_and (line 252) | func TestStructuredQuery_and(t *testing.T) {
function TestStructuredQuery_exists (line 267) | func TestStructuredQuery_exists(t *testing.T) {
function TestStructuredQuery_all (line 282) | func TestStructuredQuery_all(t *testing.T) {
function TestStructuredQuery_none (line 299) | func TestStructuredQuery_none(t *testing.T) {
function TestStructuredQuery_sequential (line 316) | func TestStructuredQuery_sequential(t *testing.T) {
function TestStructuredQuery_count (line 348) | func TestStructuredQuery_count(t *testing.T) {
function TestStructuredQuery_moreThan (line 376) | func TestStructuredQuery_moreThan(t *testing.T) {
function TestStructuredQuery_lessThan (line 401) | func TestStructuredQuery_lessThan(t *testing.T) {
function TestStructuredQuery_link (line 426) | func TestStructuredQuery_link(t *testing.T) {
function TestStructuredQuery_triaged (line 445) | func TestStructuredQuery_triaged(t *testing.T) {
function TestStructuredQuery_triagedEmptyProduct (line 465) | func TestStructuredQuery_triagedEmptyProduct(t *testing.T) {
function TestStructuredQuery_testlabel (line 484) | func TestStructuredQuery_testlabel(t *testing.T) {
function TestStructuredQuery_combinedTestlabel (line 503) | func TestStructuredQuery_combinedTestlabel(t *testing.T) {
function TestStructuredQuery_andTestLabels (line 519) | func TestStructuredQuery_andTestLabels(t *testing.T) {
function TestStructuredQuery_testfeature (line 534) | func TestStructuredQuery_testfeature(t *testing.T) {
function TestStructuredQuery_andTestFeatures (line 556) | func TestStructuredQuery_andTestFeatures(t *testing.T) {
function TestStructuredQuery_isDifferent (line 589) | func TestStructuredQuery_isDifferent(t *testing.T) {
function TestStructuredQuery_isTentative (line 608) | func TestStructuredQuery_isTentative(t *testing.T) {
function TestStructuredQuery_isOptional (line 627) | func TestStructuredQuery_isOptional(t *testing.T) {
function TestStructuredQuery_combinedlink (line 646) | func TestStructuredQuery_combinedlink(t *testing.T) {
function TestStructuredQuery_combinednotlink (line 662) | func TestStructuredQuery_combinednotlink(t *testing.T) {
function TestStructuredQuery_existsSimple (line 682) | func TestStructuredQuery_existsSimple(t *testing.T) {
function TestStructuredQuery_existsWithAnd (line 700) | func TestStructuredQuery_existsWithAnd(t *testing.T) {
function TestStructuredQuery_nested (line 714) | func TestStructuredQuery_nested(t *testing.T) {
function TestStructuredQuery_bindPattern (line 751) | func TestStructuredQuery_bindPattern(t *testing.T) {
function TestStructuredQuery_bindBrowserStatusNoRuns (line 759) | func TestStructuredQuery_bindBrowserStatusNoRuns(t *testing.T) {
function TestStructuredQuery_bindBrowserStatusSingleRun (line 767) | func TestStructuredQuery_bindBrowserStatusSingleRun(t *testing.T) {
function TestStructuredQuery_bindBrowserStatusSingleRunNeq (line 791) | func TestStructuredQuery_bindBrowserStatusSingleRunNeq(t *testing.T) {
function TestStructuredQuery_bindStatusSomeRuns (line 815) | func TestStructuredQuery_bindStatusSomeRuns(t *testing.T) {
function TestStructuredQuery_bindBrowserStatusSomeRuns (line 845) | func TestStructuredQuery_bindBrowserStatusSomeRuns(t *testing.T) {
function TestStructuredQuery_bindExists (line 881) | func TestStructuredQuery_bindExists(t *testing.T) {
function TestStructuredQuery_bindExistsWithTwoProducts (line 943) | func TestStructuredQuery_bindExistsWithTwoProducts(t *testing.T) {
function TestStructuredQuery_bindSequential (line 996) | func TestStructuredQuery_bindSequential(t *testing.T) {
function TestStructuredQuery_bindCount (line 1029) | func TestStructuredQuery_bindCount(t *testing.T) {
function TestStructuredQuery_bindLink (line 1057) | func TestStructuredQuery_bindLink(t *testing.T) {
function TestStructuredQuery_bindTriaged (line 1096) | func TestStructuredQuery_bindTriaged(t *testing.T) {
function TestStructuredQuery_bindTriagedNilProduct (line 1142) | func TestStructuredQuery_bindTriagedNilProduct(t *testing.T) {
function TestStructuredQuery_bindTestLabel (line 1189) | func TestStructuredQuery_bindTestLabel(t *testing.T) {
type testWebFeaturesManifestFetcher (line 1224) | type testWebFeaturesManifestFetcher struct
method Fetch (line 1229) | func (t testWebFeaturesManifestFetcher) Fetch() (shared.WebFeaturesDat...
function TestStructuredQuery_bindTestWebFeature (line 1233) | func TestStructuredQuery_bindTestWebFeature(t *testing.T) {
function TestStructuredQuery_bindIs (line 1272) | func TestStructuredQuery_bindIs(t *testing.T) {
function TestStructuredQuery_bindAnd (line 1292) | func TestStructuredQuery_bindAnd(t *testing.T) {
function TestStructuredQuery_bindOr (line 1326) | func TestStructuredQuery_bindOr(t *testing.T) {
function TestStructuredQuery_bindNot (line 1360) | func TestStructuredQuery_bindNot(t *testing.T) {
function TestStructuredQuery_bindAndReduce (line 1384) | func TestStructuredQuery_bindAndReduce(t *testing.T) {
function TestStructuredQuery_bindAndReduceToTrue (line 1408) | func TestStructuredQuery_bindAndReduceToTrue(t *testing.T) {
function TestStructuredQuery_bindOrReduce (line 1433) | func TestStructuredQuery_bindOrReduce(t *testing.T) {
function TestStructuredQuery_bindComplex (line 1458) | func TestStructuredQuery_bindComplex(t *testing.T) {
function getMetadataTestData (line 1508) | func getMetadataTestData() map[string][]byte {
FILE: api/query/cache/backfill/backfill.go
type backfillIndex (line 22) | type backfillIndex struct
method EvictRuns (line 61) | func (i *backfillIndex) EvictRuns(percent float64) (int, error) {
method Bind (line 74) | func (*backfillIndex) Bind([]shared.TestRun, query.ConcreteQuery) (que...
type backfillMonitor (line 28) | type backfillMonitor struct
method Stop (line 67) | func (m *backfillMonitor) Stop() error {
constant bytesPerRun (line 37) | bytesPerRun = uint64(6.5e+7)
function GetDatastore (line 44) | func GetDatastore(projectID string, gcpCredentialsFile *string, _ shared...
function FillIndex (line 84) | func FillIndex(
function startBackfillMonitor (line 119) | func startBackfillMonitor(store shared.Datastore, logger shared.Logger, ...
FILE: api/query/cache/backfill/backfill_medium_test.go
type countingIndex (line 23) | type countingIndex struct
method IngestRun (line 31) | func (i *countingIndex) IngestRun(r shared.TestRun) error {
method EvictRuns (line 41) | func (i *countingIndex) EvictRuns(percent float64) (int, error) {
method Bind (line 51) | func (*countingIndex) Bind([]shared.TestRun, query.ConcreteQuery) (que...
function TestStopImmediately (line 55) | func TestStopImmediately(t *testing.T) {
function TestIngestSomeRuns (line 83) | func TestIngestSomeRuns(t *testing.T) {
FILE: api/query/cache/backfill/backfill_test.go
function TestNilIndex (line 19) | func TestNilIndex(t *testing.T) {
function TestFetchErr (line 27) | func TestFetchErr(t *testing.T) {
FILE: api/query/cache/backfill/mock_backfill/backfill_mock.go
type MockRunFetcher (line 14) | type MockRunFetcher struct
method EXPECT (line 32) | func (m *MockRunFetcher) EXPECT() *MockRunFetcherMockRecorder {
method FetchRuns (line 37) | func (m *MockRunFetcher) FetchRuns(arg0 int) (shared.TestRunsByProduct...
type MockRunFetcherMockRecorder (line 20) | type MockRunFetcherMockRecorder struct
method FetchRuns (line 46) | func (mr *MockRunFetcherMockRecorder) FetchRuns(arg0 interface{}) *gom...
function NewMockRunFetcher (line 25) | func NewMockRunFetcher(ctrl *gomock.Controller) *MockRunFetcher {
FILE: api/query/cache/index/aggregator.go
type aggregator (line 12) | type aggregator interface
type indexAggregator (line 17) | type indexAggregator struct
method Add (line 26) | func (a *indexAggregator) Add(t TestID) error {
method Done (line 112) | func (a *indexAggregator) Done() []shared.SearchResult {
function newIndexAggregator (line 122) | func newIndexAggregator(idx index, runIDs []RunID, opts query.Aggregatio...
FILE: api/query/cache/index/filter.go
type True (line 33) | type True struct
method Filter (line 156) | func (True) Filter(_ TestID) bool {
type False (line 38) | type False struct
method Filter (line 161) | func (False) Filter(_ TestID) bool {
type TestNamePattern (line 43) | type TestNamePattern struct
method Filter (line 166) | func (tnp TestNamePattern) Filter(t TestID) bool {
type SubtestNamePattern (line 49) | type SubtestNamePattern struct
method Filter (line 179) | func (tnp SubtestNamePattern) Filter(t TestID) bool {
type TestPath (line 55) | type TestPath struct
method Filter (line 192) | func (tp TestPath) Filter(t TestID) bool {
type runTestStatusEq (line 62) | type runTestStatusEq struct
method Filter (line 202) | func (rtse runTestStatusEq) Filter(t TestID) bool {
type runTestStatusNeq (line 69) | type runTestStatusNeq struct
method Filter (line 207) | func (rtsn runTestStatusNeq) Filter(t TestID) bool {
type Count (line 75) | type Count struct
method Filter (line 212) | func (c Count) Filter(t TestID) bool {
type LessThan (line 82) | type LessThan
method Filter (line 225) | func (c LessThan) Filter(t TestID) bool {
type MoreThan (line 85) | type MoreThan
method Filter (line 238) | func (c MoreThan) Filter(t TestID) bool {
type Link (line 88) | type Link struct
method Filter (line 251) | func (l Link) Filter(t TestID) bool {
type Triaged (line 95) | type Triaged struct
method Filter (line 288) | func (tr Triaged) Filter(t TestID) bool {
type TestLabel (line 101) | type TestLabel struct
method Filter (line 330) | func (tl TestLabel) Filter(t TestID) bool {
type TestWebFeature (line 108) | type TestWebFeature struct
method Filter (line 356) | func (twf TestWebFeature) Filter(t TestID) bool {
type MetadataQuality (line 115) | type MetadataQuality struct
method Filter (line 370) | func (q MetadataQuality) Filter(t TestID) bool {
type And (line 121) | type And struct
method Filter (line 412) | func (a And) Filter(t TestID) bool {
type Or (line 127) | type Or struct
method Filter (line 424) | func (o Or) Filter(t TestID) bool {
type Not (line 133) | type Not struct
method Filter (line 436) | func (n Not) Filter(t TestID) bool {
type ShardedFilter (line 140) | type ShardedFilter
method Execute (line 520) | func (fs ShardedFilter) Execute(runs []shared.TestRun, opts query.Aggr...
type filter (line 142) | type filter interface
type index (line 147) | type index struct
method idx (line 153) | func (i index) idx() index { return i }
function newFilter (line 441) | func newFilter(idx index, q query.ConcreteQuery) (filter, error) {
function syncRunFilter (line 554) | func syncRunFilter(rus []RunID, f filter, opts query.AggregationOpts, re...
function filters (line 573) | func filters(idx index, qs []query.ConcreteQuery) ([]filter, error) {
FILE: api/query/cache/index/index.go
function ErrRunExists (line 43) | func ErrRunExists() error {
function ErrRunLoading (line 50) | func ErrRunLoading() error {
type Index (line 55) | type Index interface
type ProxyIndex (line 81) | type ProxyIndex struct
method Run (line 87) | func (i *ProxyIndex) Run(id RunID) (shared.TestRun, error) {
method Runs (line 93) | func (i *ProxyIndex) Runs(ids []RunID) ([]shared.TestRun, error) {
method IngestRun (line 99) | func (i *ProxyIndex) IngestRun(r shared.TestRun) error {
method EvictRuns (line 105) | func (i *ProxyIndex) EvictRuns(percent float64) (int, error) {
method SetIngestChan (line 111) | func (i *ProxyIndex) SetIngestChan(c chan bool) {
function NewProxyIndex (line 116) | func NewProxyIndex(idx Index) ProxyIndex {
type ReportLoader (line 122) | type ReportLoader interface
type shardedWPTIndex (line 128) | type shardedWPTIndex struct
method Run (line 157) | func (i *shardedWPTIndex) Run(id RunID) (shared.TestRun, error) {
method Runs (line 161) | func (i *shardedWPTIndex) Runs(ids []RunID) ([]shared.TestRun, error) {
method IngestRun (line 165) | func (i *shardedWPTIndex) IngestRun(r shared.TestRun) error {
method EvictRuns (line 260) | func (i *shardedWPTIndex) EvictRuns(percent float64) (int, error) {
method Bind (line 265) | func (i *shardedWPTIndex) Bind(runs []shared.TestRun, q query.Concrete...
method SetIngestChan (line 293) | func (i *shardedWPTIndex) SetIngestChan(c chan bool) {
method syncGetRun (line 362) | func (i *shardedWPTIndex) syncGetRun(id RunID) (shared.TestRun, error) {
method syncGetRuns (line 374) | func (i *shardedWPTIndex) syncGetRuns(ids []RunID) ([]shared.TestRun, ...
method syncMarkInProgress (line 391) | func (i *shardedWPTIndex) syncMarkInProgress(run shared.TestRun) error {
method syncClearInProgress (line 409) | func (i *shardedWPTIndex) syncClearInProgress(run shared.TestRun) error {
method syncStoreRun (line 423) | func (i *shardedWPTIndex) syncStoreRun(run shared.TestRun, data []map[...
method syncEvictRuns (line 452) | func (i *shardedWPTIndex) syncEvictRuns(percent float64) (int, error) {
method syncExtractRuns (line 487) | func (i *shardedWPTIndex) syncExtractRuns(ids []RunID) ([]index, error) {
type wptIndex (line 141) | type wptIndex struct
type testData (line 148) | type testData struct
type HTTPReportLoader (line 155) | type HTTPReportLoader struct
method Load (line 299) | func (l HTTPReportLoader) Load(run shared.TestRun) (*metrics.TestResul...
function NewShardedWPTIndex (line 333) | func NewShardedWPTIndex(loader ReportLoader, numShards int) (Index, erro...
function NewReportLoader (line 358) | func NewReportLoader() ReportLoader {
function syncStoreRunOnShard (line 439) | func syncStoreRunOnShard(shard *wptIndex, id RunID, shardData map[TestID...
function syncDeleteResultsFromShard (line 480) | func syncDeleteResultsFromShard(shard *wptIndex, id RunID) error {
function syncMakeIndex (line 507) | func syncMakeIndex(shard *wptIndex, ids []RunID) (index, error) {
function newWPTIndex (line 528) | func newWPTIndex(tests Tests) *wptIndex {
FILE: api/query/cache/index/index_filter_test.go
constant testNumShards (line 21) | testNumShards = 16
type testRunData (line 23) | type testRunData struct
function mockTestRuns (line 28) | func mockTestRuns(loader *MockReportLoader, idx Index, data []testRunDat...
function planAndExecute (line 38) | func planAndExecute(t *testing.T, runs []shared.TestRun, idx Index, q qu...
function resultSet (line 49) | func resultSet(t *testing.T, srs []shared.SearchResult) mapset.Set {
function TestBindFail_NoRuns (line 64) | func TestBindFail_NoRuns(t *testing.T) {
function TestBindFail_NoQuery (line 75) | func TestBindFail_NoQuery(t *testing.T) {
function TestBindFail_MissingRun (line 86) | func TestBindFail_MissingRun(t *testing.T) {
function TestBindExecute_TestNamePattern (line 98) | func TestBindExecute_TestNamePattern(t *testing.T) {
function TestBindExecute_TestNamePattern_CaseInsensitive (line 145) | func TestBindExecute_TestNamePattern_CaseInsensitive(t *testing.T) {
function TestBindExecute_SubtestNamePattern (line 180) | func TestBindExecute_SubtestNamePattern(t *testing.T) {
function TestBindExecute_SubtestNamePattern_CaseInsensitive (line 259) | func TestBindExecute_SubtestNamePattern_CaseInsensitive(t *testing.T) {
function TestBindExecute_TestPath (line 319) | func TestBindExecute_TestPath(t *testing.T) {
function TestBindExecute_TestStatus (line 367) | func TestBindExecute_TestStatus(t *testing.T) {
function TestBindExecute_TestStatus_PreconditionFailed (line 522) | func TestBindExecute_TestStatus_PreconditionFailed(t *testing.T) {
function TestBindExecute_Link (line 659) | func TestBindExecute_Link(t *testing.T) {
function TestBindExecute_LinkWithWildcards (line 714) | func TestBindExecute_LinkWithWildcards(t *testing.T) {
function TestBindExecute_Triaged (line 771) | func TestBindExecute_Triaged(t *testing.T) {
function TestBindExecute_TriagedWildcards (line 827) | func TestBindExecute_TriagedWildcards(t *testing.T) {
function TestBindExecute_QueryAndTestLabel (line 883) | func TestBindExecute_QueryAndTestLabel(t *testing.T) {
function TestBindExecute_QueryOrTestLabel (line 940) | func TestBindExecute_QueryOrTestLabel(t *testing.T) {
function TestBindExecute_TestLabel (line 1010) | func TestBindExecute_TestLabel(t *testing.T) {
function TestBindExecute_LabelWithWildcards (line 1066) | func TestBindExecute_LabelWithWildcards(t *testing.T) {
function TestBindExecute_TestWebFeature (line 1126) | func TestBindExecute_TestWebFeature(t *testing.T) {
function TestBindExecute_TestWebFeature_PreservesCase (line 1182) | func TestBindExecute_TestWebFeature_PreservesCase(t *testing.T) {
function TestBindExecute_IsDifferent (line 1237) | func TestBindExecute_IsDifferent(t *testing.T) {
function TestBindExecute_IsTentative (line 1306) | func TestBindExecute_IsTentative(t *testing.T) {
function TestBindExecute_IsOptional (line 1384) | func TestBindExecute_IsOptional(t *testing.T) {
function TestBindExecute_MoreThan (line 1432) | func TestBindExecute_MoreThan(t *testing.T) {
function TestBindExecute_LessThan (line 1507) | func TestBindExecute_LessThan(t *testing.T) {
function TestBindExecute_LinkNoMatchingPattern (line 1582) | func TestBindExecute_LinkNoMatchingPattern(t *testing.T) {
function TestBindExecute_NotLink (line 1623) | func TestBindExecute_NotLink(t *testing.T) {
function TestBindExecute_HandleHarness (line 1677) | func TestBindExecute_HandleHarness(t *testing.T) {
FILE: api/query/cache/index/index_medium_test.go
constant testEvictionNumResults (line 21) | testEvictionNumResults = 10000
constant testEvictionMinBytes (line 24) | testEvictionMinBytes = testEvictionNumResults * 5
function TestEvictAnyRunRelievesMemoryPressure (line 27) | func TestEvictAnyRunRelievesMemoryPressure(t *testing.T) {
FILE: api/query/cache/index/index_mock.go
type MockIndex (line 17) | type MockIndex struct
method EXPECT (line 35) | func (m *MockIndex) EXPECT() *MockIndexMockRecorder {
method Bind (line 40) | func (m *MockIndex) Bind(arg0 []shared.TestRun, arg1 query.ConcreteQue...
method Run (line 53) | func (m *MockIndex) Run(arg0 RunID) (shared.TestRun, error) {
method Runs (line 68) | func (m *MockIndex) Runs(arg0 []RunID) ([]shared.TestRun, error) {
method IngestRun (line 81) | func (m *MockIndex) IngestRun(arg0 shared.TestRun) error {
method EvictRuns (line 93) | func (m *MockIndex) EvictRuns(arg0 float64) (int, error) {
method SetIngestChan (line 106) | func (m *MockIndex) SetIngestChan(arg0 chan bool) {
type MockIndexMockRecorder (line 23) | type MockIndexMockRecorder struct
method Bind (line 48) | func (mr *MockIndexMockRecorder) Bind(arg0, arg1 interface{}) *gomock....
method Run (line 62) | func (mr *MockIndexMockRecorder) Run(arg0 interface{}) *gomock.Call {
method Runs (line 76) | func (mr *MockIndexMockRecorder) Runs(arg0 interface{}) *gomock.Call {
method IngestRun (line 88) | func (mr *MockIndexMockRecorder) IngestRun(arg0 interface{}) *gomock.C...
method EvictRuns (line 101) | func (mr *MockIndexMockRecorder) EvictRuns(arg0 interface{}) *gomock.C...
method SetIngestChan (line 111) | func (mr *MockIndexMockRecorder) SetIngestChan(arg0 interface{}) *gomo...
function NewMockIndex (line 28) | func NewMockIndex(ctrl *gomock.Controller) *MockIndex {
type MockReportLoader (line 116) | type MockReportLoader struct
method EXPECT (line 134) | func (m *MockReportLoader) EXPECT() *MockReportLoaderMockRecorder {
method Load (line 139) | func (m *MockReportLoader) Load(arg0 shared.TestRun) (*metrics.TestRes...
type MockReportLoaderMockRecorder (line 122) | type MockReportLoaderMockRecorder struct
method Load (line 147) | func (mr *MockReportLoaderMockRecorder) Load(arg0 interface{}) *gomock...
function NewMockReportLoader (line 127) | func NewMockReportLoader(ctrl *gomock.Controller) *MockReportLoader {
FILE: api/query/cache/index/index_test.go
function TestInvalidNumShards (line 24) | func TestInvalidNumShards(t *testing.T) {
function TestEvictEmpty (line 33) | func TestEvictEmpty(t *testing.T) {
function TestIngestRun_zeroID (line 43) | func TestIngestRun_zeroID(t *testing.T) {
function TestIngestRun_double (line 52) | func TestIngestRun_double(t *testing.T) {
function TestIngestRun_concurrent (line 68) | func TestIngestRun_concurrent(t *testing.T) {
function TestIngestRun_loaderError (line 106) | func TestIngestRun_loaderError(t *testing.T) {
function TestEvictNonEmpty (line 121) | func TestEvictNonEmpty(t *testing.T) {
function TestEvictMultiple (line 157) | func TestEvictMultiple(t *testing.T) {
function TestSync (line 242) | func TestSync(t *testing.T) {
function makeRun (line 375) | func makeRun(id int64) shared.TestRun {
FILE: api/query/cache/index/results.go
type RunID (line 16) | type RunID
type ResultID (line 21) | type ResultID
type Results (line 25) | type Results interface
type RunResults (line 40) | type RunResults interface
type resultsMap (line 48) | type resultsMap struct
method Add (line 68) | func (rs *resultsMap) Add(ru RunID, rr RunResults) error {
method Delete (line 77) | func (rs *resultsMap) Delete(ru RunID) error {
method ForRun (line 89) | func (rs *resultsMap) ForRun(ru RunID) RunResults {
type runResultsMap (line 52) | type runResultsMap struct
method Add (line 99) | func (rrs *runResultsMap) Add(re ResultID, t TestID) {
method GetResult (line 103) | func (rrs *runResultsMap) GetResult(t TestID) ResultID {
function NewResults (line 58) | func NewResults() Results {
function NewRunResults (line 64) | func NewRunResults() RunResults {
FILE: api/query/cache/index/results_test.go
function TestForRun_fail (line 16) | func TestForRun_fail(t *testing.T) {
function TestAdd_fail (line 22) | func TestAdd_fail(t *testing.T) {
function TestAddForRunGetResult (line 32) | func TestAddForRunGetResult(t *testing.T) {
FILE: api/query/cache/index/tests.go
type TestID (line 14) | type TestID struct
type Tests (line 20) | type Tests interface
type testsMap (line 32) | type testsMap struct
method Add (line 47) | func (ts *testsMap) Add(t TestID, name string, subName *string) {
method GetName (line 51) | func (ts *testsMap) GetName(id TestID) (string, *string, error) {
method Range (line 60) | func (ts *testsMap) Range(f func(TestID) bool) {
type testName (line 36) | type testName struct
function NewTests (line 43) | func NewTests() Tests {
function computeTestID (line 68) | func computeTestID(name string, subPtr *string) (TestID, error) {
FILE: api/query/cache/index/tests_test.go
function TestGetName_fail (line 15) | func TestGetName_fail(t *testing.T) {
function TestAddGetName (line 21) | func TestAddGetName(t *testing.T) {
FILE: api/query/cache/lru/lru.go
type LRU (line 17) | type LRU interface
type lru (line 29) | type lru struct
method Access (line 46) | func (l *lru) Access(v int64) {
method EvictLRU (line 50) | func (l *lru) EvictLRU(percent float64) []int64 {
method syncAccess (line 69) | func (l *lru) syncAccess(v int64) {
method syncEvictLRU (line 76) | func (l *lru) syncEvictLRU(num int) []int64 {
type lruEntry (line 34) | type lruEntry struct
type lruEntries (line 39) | type lruEntries
method Len (line 42) | func (s lruEntries) Len() int { return len(s) }
method Swap (line 43) | func (s lruEntries) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
method Less (line 44) | func (s lruEntries) Less(i, j int) bool { return (s[i].Time).Before(s[...
function NewLRU (line 62) | func NewLRU() LRU {
FILE: api/query/cache/lru/lru_test.go
function TestLRUEmpty (line 18) | func TestLRUEmpty(t *testing.T) {
function TestSimple (line 24) | func TestSimple(t *testing.T) {
function TestRoundUpToOne (line 32) | func TestRoundUpToOne(t *testing.T) {
function TestRoundDown (line 40) | func TestRoundDown(t *testing.T) {
function TestRoundWayDown (line 48) | func TestRoundWayDown(t *testing.T) {
function TestRepeatAccess (line 56) | func TestRepeatAccess(t *testing.T) {
function TestConcurrency (line 67) | func TestConcurrency(t *testing.T) {
FILE: api/query/cache/monitor/monitor.go
type Runtime (line 26) | type Runtime interface
type Monitor (line 32) | type Monitor interface
type ProxyMonitor (line 50) | type ProxyMonitor struct
method Start (line 55) | func (m *ProxyMonitor) Start() error {
method Stop (line 60) | func (m *ProxyMonitor) Stop() error {
method SetInterval (line 66) | func (m *ProxyMonitor) SetInterval(i time.Duration) error {
method SetMaxHeapBytes (line 72) | func (m *ProxyMonitor) SetMaxHeapBytes(b uint64) error {
method SetEvictionPercent (line 79) | func (m *ProxyMonitor) SetEvictionPercent(percent float64) error {
function NewProxyMonitor (line 84) | func NewProxyMonitor(m Monitor) ProxyMonitor {
type GoRuntime (line 89) | type GoRuntime struct
method GetHeapBytes (line 92) | func (r GoRuntime) GetHeapBytes() uint64 {
type indexMonitor (line 99) | type indexMonitor struct
method Start (line 114) | func (m *indexMonitor) Start() error {
method Stop (line 153) | func (m *indexMonitor) Stop() error {
method SetInterval (line 165) | func (m *indexMonitor) SetInterval(interval time.Duration) error {
method SetMaxHeapBytes (line 173) | func (m *indexMonitor) SetMaxHeapBytes(maxHeapBytes uint64) error {
method SetEvictionPercent (line 181) | func (m *indexMonitor) SetEvictionPercent(percent float64) error {
method start (line 193) | func (m *indexMonitor) start() error {
method check (line 204) | func (m *indexMonitor) check() {
function NewIndexMonitor (line 218) | func NewIndexMonitor(
FILE: api/query/cache/monitor/monitor_mock.go
type MockRuntime (line 14) | type MockRuntime struct
method EXPECT (line 32) | func (m *MockRuntime) EXPECT() *MockRuntimeMockRecorder {
method GetHeapBytes (line 37) | func (m *MockRuntime) GetHeapBytes() uint64 {
type MockRuntimeMockRecorder (line 20) | type MockRuntimeMockRecorder struct
method GetHeapBytes (line 44) | func (mr *MockRuntimeMockRecorder) GetHeapBytes() *gomock.Call {
function NewMockRuntime (line 25) | func NewMockRuntime(ctrl *gomock.Controller) *MockRuntime {
type MockMonitor (line 49) | type MockMonitor struct
method EXPECT (line 67) | func (m *MockMonitor) EXPECT() *MockMonitorMockRecorder {
method Start (line 72) | func (m *MockMonitor) Start() error {
method Stop (line 84) | func (m *MockMonitor) Stop() error {
method SetInterval (line 96) | func (m *MockMonitor) SetInterval(arg0 time.Duration) error {
method SetMaxHeapBytes (line 108) | func (m *MockMonitor) SetMaxHeapBytes(arg0 uint64) error {
type MockMonitorMockRecorder (line 55) | type MockMonitorMockRecorder struct
method Start (line 79) | func (mr *MockMonitorMockRecorder) Start() *gomock.Call {
method Stop (line 91) | func (mr *MockMonitorMockRecorder) Stop() *gomock.Call {
method SetInterval (line 103) | func (mr *MockMonitorMockRecorder) SetInterval(arg0 interface{}) *gomo...
method SetMaxHeapBytes (line 115) | func (mr *MockMonitorMockRecorder) SetMaxHeapBytes(arg0 interface{}) *...
function NewMockMonitor (line 60) | func NewMockMonitor(ctrl *gomock.Controller) *MockMonitor {
FILE: api/query/cache/monitor/monitor_test.go
constant testMaxHeapBytes (line 21) | testMaxHeapBytes uint64 = 10
function getTestHarness (line 23) | func getTestHarness(t *testing.T) (*gomock.Controller, *index.MockIndex,...
function TestStopErr (line 32) | func TestStopErr(t *testing.T) {
function TestStartStop (line 40) | func TestStartStop(t *testing.T) {
function TestDoubleStart (line 55) | func TestDoubleStart(t *testing.T) {
function TestOOM (line 78) | func TestOOM(t *testing.T) {
type syncingIndex (line 94) | type syncingIndex struct
method SetIngestChan (line 102) | func (i *syncingIndex) SetIngestChan(c chan bool) {
method IngestRun (line 106) | func (i *syncingIndex) IngestRun(r shared.TestRun) error {
function TestIngestTriggered (line 116) | func TestIngestTriggered(t *testing.T) {
FILE: api/query/cache/poll/poll.go
function KeepRunsUpdated (line 23) | func KeepRunsUpdated(store shared.Datastore, logger shared.Logger, inter...
function wait (line 88) | func wait(start time.Time, total time.Duration) {
function StartMetadataPollingService (line 97) | func StartMetadataPollingService(ctx context.Context, logger shared.Logg...
function keepMetadataUpdated (line 119) | func keepMetadataUpdated(client *http.Client, logger shared.Logger) {
function cleanOrphanedPendingMetadata (line 134) | func cleanOrphanedPendingMetadata(
function StartWebFeaturesManifestPollingService (line 192) | func StartWebFeaturesManifestPollingService(ctx context.Context, logger ...
type webFeaturesGetter (line 213) | type webFeaturesGetter interface
function keepWebFeaturesManifestUpdated (line 219) | func keepWebFeaturesManifestUpdated(
FILE: api/query/cache/poll/poll_test.go
type testWebFeaturesGetter (line 20) | type testWebFeaturesGetter struct
method Get (line 25) | func (g testWebFeaturesGetter) Get(_ context.Context) (shared.WebFeatu...
function TestKeepWebFeaturesManifestUpdated (line 29) | func TestKeepWebFeaturesManifestUpdated(t *testing.T) {
FILE: api/query/cache/query/query.go
function PrepareUserQuery (line 18) | func PrepareUserQuery(runIDs []int64, q query.ConcreteQuery) query.Concr...
FILE: api/query/cache/query/query_test.go
function TestPrepareUserQuery_basic (line 16) | func TestPrepareUserQuery_basic(t *testing.T) {
function TestPrepareUserQuery_and (line 30) | func TestPrepareUserQuery_and(t *testing.T) {
FILE: api/query/concrete_query.go
constant averageNumberOfSubtests (line 12) | averageNumberOfSubtests = int(1655263 / 34236)
type AggregationOpts (line 16) | type AggregationOpts struct
type Binder (line 26) | type Binder interface
type Plan (line 36) | type Plan interface
type ConcreteQuery (line 43) | type ConcreteQuery interface
type Count (line 49) | type Count struct
method Size (line 160) | func (c Count) Size() int { return size(c.Args) }
type MoreThan (line 56) | type MoreThan struct
type LessThan (line 62) | type LessThan struct
type Link (line 67) | type Link struct
method Size (line 145) | func (Link) Size() int { return 1 }
type Triaged (line 73) | type Triaged struct
method Size (line 149) | func (Triaged) Size() int { return 1 }
type TestLabel (line 79) | type TestLabel struct
method Size (line 153) | func (TestLabel) Size() int { return 1 }
type TestWebFeature (line 85) | type TestWebFeature struct
method Size (line 157) | func (TestWebFeature) Size() int { return 1 }
type RunTestStatusEq (line 94) | type RunTestStatusEq struct
method Size (line 137) | func (RunTestStatusEq) Size() int { return 1 }
type RunTestStatusNeq (line 103) | type RunTestStatusNeq struct
method Size (line 141) | func (RunTestStatusNeq) Size() int { return 1 }
type Or (line 109) | type Or struct
method Size (line 169) | func (o Or) Size() int { return size(o.Args) }
type And (line 114) | type And struct
method Size (line 173) | func (a And) Size() int { return size(a.Args) }
type Not (line 119) | type Not struct
method Size (line 176) | func (n Not) Size() int { return 1 + n.Arg.Size() }
method Size (line 125) | func (TestNamePattern) Size() int { return 1 }
method Size (line 129) | func (SubtestNamePattern) Size() int { return averageNumberOfSubtests }
method Size (line 133) | func (TestPath) Size() int { return 1 }
method Size (line 163) | func (q MetadataQuality) Size() int {
method Size (line 179) | func (True) Size() int { return 0 }
method Size (line 182) | func (False) Size() int { return 0 }
function size (line 184) | func size(qs []ConcreteQuery) int {
FILE: api/query/metadata_cache.go
type searchcacheMetadataFetcher (line 17) | type searchcacheMetadataFetcher struct
method Fetch (line 19) | func (f searchcacheMetadataFetcher) Fetch() (sha *string, res map[stri...
FILE: api/query/query.go
type SummaryResult (line 22) | type SummaryResult struct
type summary (line 30) | type summary
type queryHandler (line 32) | type queryHandler struct
method processInput (line 40) | func (qh queryHandler) processInput(w http.ResponseWriter, r *http.Req...
method validateSummaryVersions (line 70) | func (qh queryHandler) validateSummaryVersions(v url.Values, logger sh...
method summaryIsValid (line 92) | func (qh queryHandler) summaryIsValid(summaryURL string) bool {
method getRunsAndFilters (line 97) | func (qh queryHandler) getRunsAndFilters(in shared.QueryFilter) (share...
method loadSummaries (line 132) | func (qh queryHandler) loadSummaries(testRuns shared.TestRuns) ([]summ...
method loadSummary (line 166) | func (qh queryHandler) loadSummary(testRun shared.TestRun) ([]byte, er...
function getSummaryFileRedisKey (line 175) | func getSummaryFileRedisKey(testRun shared.TestRun) string {
function isRequestCacheable (line 179) | func isRequestCacheable(r *http.Request) bool {
FILE: api/query/query_test.go
function TestGetRedisKey (line 22) | func TestGetRedisKey(t *testing.T) {
function TestLoadSummaries_success (line 28) | func TestLoadSummaries_success(t *testing.T) {
function TestLoadSummaries_fail (line 78) | func TestLoadSummaries_fail(t *testing.T) {
function TestSummaryIsValid_v1 (line 118) | func TestSummaryIsValid_v1(t *testing.T) {
function TestSummaryIsValid_v2 (line 125) | func TestSummaryIsValid_v2(t *testing.T) {
function TestGetRunsAndFilters_default (line 131) | func TestGetRunsAndFilters_default(t *testing.T) {
function TestGetRunsAndFilters_specificRunIDs (line 183) | func TestGetRunsAndFilters_specificRunIDs(t *testing.T) {
function TestIsRequestCacheable_getNotCacheable (line 236) | func TestIsRequestCacheable_getNotCacheable(t *testing.T) {
function TestIsRequestCacheable_getCacheable (line 240) | func TestIsRequestCacheable_getCacheable(t *testing.T) {
function TestIsRequestCacheable_postNotCacheable (line 244) | func TestIsRequestCacheable_postNotCacheable(t *testing.T) {
function TestIsRequestCacheable_postCacheable (line 248) | func TestIsRequestCacheable_postCacheable(t *testing.T) {
FILE: api/query/routes.go
function RegisterRoutes (line 10) | func RegisterRoutes() {
FILE: api/query/search.go
type byName (line 24) | type byName
method Len (line 26) | func (r byName) Len() int { return len(r) }
method Swap (line 27) | func (r byName) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
method Less (line 28) | func (r byName) Less(i, j int) bool { return r[i].Test < r[j].Test }
type searchHandler (line 30) | type searchHandler struct
method ServeHTTP (line 49) | func (sh searchHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque...
type unstructuredSearchHandler (line 34) | type unstructuredSearchHandler struct
method ServeHTTP (line 209) | func (sh unstructuredSearchHandler) ServeHTTP(w http.ResponseWriter, r...
type structuredSearchHandler (line 38) | type structuredSearchHandler struct
method ServeHTTP (line 72) | func (sh structuredSearchHandler) ServeHTTP(w http.ResponseWriter, r *...
method useSearchcache (line 164) | func (sh structuredSearchHandler) useSearchcache(_ http.ResponseWriter...
function apiSearchHandler (line 44) | func apiSearchHandler(w http.ResponseWriter, r *http.Request) {
function prepareSearchResponse (line 228) | func prepareSearchResponse(
FILE: api/query/search_medium_test.go
type shouldCache (line 27) | type shouldCache struct
method ShouldCache (line 35) | func (sc *shouldCache) ShouldCache(ctx context.Context, statusCode int...
function NewShouldCache (line 42) | func NewShouldCache(t *testing.T, expected bool, delegate func(context.C...
function TestUnstructuredSearchHandler (line 46) | func TestUnstructuredSearchHandler(t *testing.T) {
function TestStructuredSearchHandler_equivalentToUnstructured (line 189) | func TestStructuredSearchHandler_equivalentToUnstructured(t *testing.T) {
function TestUnstructuredSearchHandler_doNotCacheEmptyResult (line 339) | func TestUnstructuredSearchHandler_doNotCacheEmptyResult(t *testing.T) {
function TestStructuredSearchHandler_doNotCacheEmptyResult (line 434) | func TestStructuredSearchHandler_doNotCacheEmptyResult(t *testing.T) {
FILE: api/query/search_test.go
function doTestIC (line 25) | func doTestIC(t *testing.T, p, q string) {
function testIC (line 117) | func testIC(t *testing.T, str string, upperQ bool) {
function TestPrepareSearchResponse_qUC (line 130) | func TestPrepareSearchResponse_qUC(t *testing.T) {
function TestPrepareSearchResponse_pUC (line 134) | func TestPrepareSearchResponse_pUC(t *testing.T) {
function TestStructuredSearchHandler_success (line 138) | func TestStructuredSearchHandler_success(t *testing.T) {
function TestStructuredSearchHandler_failure (line 200) | func TestStructuredSearchHandler_failure(t *testing.T) {
FILE: api/query/test/types.go
type MockWriteCloser (line 16) | type MockWriteCloser struct
method Write (line 24) | func (mwc *MockWriteCloser) Write(p []byte) (n int, err error) {
method Close (line 34) | func (mwc *MockWriteCloser) Close() error {
function NewMockWriteCloser (line 41) | func NewMockWriteCloser(t *testing.T) *MockWriteCloser {
type MockReadCloser (line 51) | type MockReadCloser struct
method Read (line 59) | func (mrc *MockReadCloser) Read(p []byte) (n int, err error) {
method Close (line 66) | func (mrc *MockReadCloser) Close() error {
method IsClosed (line 84) | func (mrc *MockReadCloser) IsClosed() bool {
function NewMockReadCloser (line 74) | func NewMockReadCloser(t *testing.T, data []byte) *MockReadCloser {
FILE: api/query/util.go
function canonicalizeStr (line 5) | func canonicalizeStr(str string) string {
FILE: api/query/web_features_manifest_cache.go
function SetWebFeaturesDataCache (line 16) | func SetWebFeaturesDataCache(newData shared.WebFeaturesData) {
function GetWebFeaturesDataCache (line 23) | func GetWebFeaturesDataCache() shared.WebFeaturesData {
type searchcacheWebFeaturesManifestFetcher (line 34) | type searchcacheWebFeaturesManifestFetcher struct
method Fetch (line 36) | func (f searchcacheWebFeaturesManifestFetcher) Fetch() (shared.WebFeat...
FILE: api/receiver/api.go
function AuthenticateUploader (line 28) | func AuthenticateUploader(aeAPI shared.AppEngineAPI, r *http.Request) st...
type API (line 42) | type API interface
type apiImpl (line 57) | type apiImpl struct
method AddTestRun (line 84) | func (a apiImpl) AddTestRun(testRun *shared.TestRun) (shared.Key, erro...
method IsAdmin (line 99) | func (a apiImpl) IsAdmin(r *http.Request) bool {
method UpdatePendingTestRun (line 120) | func (a apiImpl) UpdatePendingTestRun(newRun shared.PendingTestRun) er...
method UploadToGCS (line 172) | func (a *apiImpl) UploadToGCS(gcsPath string, f io.Reader, gzipped boo...
method ScheduleResultsTask (line 204) | func (a apiImpl) ScheduleResultsTask(
function NewAPI (line 69) | func NewAPI(ctx context.Context) API {
FILE: api/receiver/api_cloud_test.go
function TestAuthenticateUploader (line 23) | func TestAuthenticateUploader(t *testing.T) {
FILE: api/receiver/api_medium_test.go
type mockGcs (line 29) | type mockGcs struct
method NewWriter (line 48) | func (m *mockGcs) NewWriter(bucketName, fileName, contentType, content...
type mockGcsWriter (line 35) | type mockGcsWriter struct
method Close (line 43) | func (m *mockGcsWriter) Close() error {
function TestIsAdmin_failsToConstructACL (line 54) | func TestIsAdmin_failsToConstructACL(t *testing.T) {
function TestIsAdmin_mockACL (line 73) | func TestIsAdmin_mockACL(t *testing.T) {
function TestUploadToGCS (line 114) | func TestUploadToGCS(t *testing.T) {
function TestUploadToGCS_handlesErrors (line 127) | func TestUploadToGCS_handlesErrors(t *testing.T) {
function TestScheduleResultsTask (line 146) | func TestScheduleResultsTask(t *testing.T) {
function TestAddTestRun (line 182) | func TestAddTestRun(t *testing.T) {
function TestUpdatePendingTestRun (line 207) | func TestUpdatePendingTestRun(t *testing.T) {
FILE: api/receiver/azure.go
function getAzureArtifactName (line 17) | func getAzureArtifactName(url string) string {
FILE: api/receiver/azure_test.go
function TestGetAzureArtifactName (line 15) | func TestGetAzureArtifactName(t *testing.T) {
FILE: api/receiver/client/client.go
constant UploadTimeout (line 22) | UploadTimeout = time.Minute
type Client (line 25) | type Client interface
function NewClient (line 38) | func NewClient(aeAPI shared.AppEngineAPI) Client {
type client (line 44) | type client struct
method CreateRun (line 49) | func (c client) CreateRun(
FILE: api/receiver/client/client_test.go
function TestCreateRun (line 20) | func TestCreateRun(t *testing.T) {
FILE: api/receiver/create_run.go
constant InternalUsername (line 22) | InternalUsername = "_processor"
function HandleResultsCreate (line 25) | func HandleResultsCreate(a API, s checks.API, w http.ResponseWriter, r *...
FILE: api/receiver/create_run_test.go
function TestHandleResultsCreate (line 26) | func TestHandleResultsCreate(t *testing.T) {
function TestHandleResultsCreate_NoTimestamps (line 98) | func TestHandleResultsCreate_NoTimestamps(t *testing.T) {
function TestHandleResultsCreate_BadRevision (line 155) | func TestHandleResultsCreate_BadRevision(t *testing.T) {
function TestHandleResultsCreate_NoBasicAuth (line 195) | func TestHandleResultsCreate_NoBasicAuth(t *testing.T) {
function TestHandleResultsCreate_WrongUser (line 209) | func TestHandleResultsCreate_WrongUser(t *testing.T) {
function TestHandleResultsCreate_WrongPassword (line 225) | func TestHandleResultsCreate_WrongPassword(t *testing.T) {
FILE: api/receiver/gcs.go
type gcs (line 16) | type gcs interface
type gcsImpl (line 20) | type gcsImpl struct
method NewWriter (line 25) | func (g *gcsImpl) NewWriter(bucketName, fileName, contentType, content...
FILE: api/receiver/handlers.go
function apiResultsUploadHandler (line 13) | func apiResultsUploadHandler(w http.ResponseWriter, r *http.Request) {
function apiResultsCreateHandler (line 25) | func apiResultsCreateHandler(w http.ResponseWriter, r *http.Request) {
function apiPendingTestRunUpdateHandler (line 38) | func apiPendingTestRunUpdateHandler(w http.ResponseWriter, r *http.Reque...
FILE: api/receiver/mock_receiver/api_mock.go
type MockAPI (line 26) | type MockAPI struct
method EXPECT (line 45) | func (m *MockAPI) EXPECT() *MockAPIMockRecorder {
method AddTestRun (line 50) | func (m *MockAPI) AddTestRun(testRun *shared.TestRun) (shared.Key, err...
method Context (line 65) | func (m *MockAPI) Context() context.Context {
method GetGitHubClient (line 79) | func (m *MockAPI) GetGitHubClient() (*github.Client, error) {
method GetHTTPClient (line 94) | func (m *MockAPI) GetHTTPClient() *http.Client {
method GetHTTPClientWithTimeout (line 108) | func (m *MockAPI) GetHTTPClientWithTimeout(arg0 time.Duration) *http.C...
method GetHostname (line 122) | func (m *MockAPI) GetHostname() string {
method GetResultsURL (line 136) | func (m *MockAPI) GetResultsURL(filter shared.TestRunFilter) *url.URL {
method GetResultsUploadURL (line 150) | func (m *MockAPI) GetResultsUploadURL() *url.URL {
method GetRunsURL (line 164) | func (m *MockAPI) GetRunsURL(filter shared.TestRunFilter) *url.URL {
method GetServiceHostname (line 178) | func (m *MockAPI) GetServiceHostname(service string) string {
method GetUploader (line 192) | func (m *MockAPI) GetUploader(uploader string) (shared.Uploader, error) {
method GetVersion (line 207) | func (m *MockAPI) GetVersion() string {
method GetVersionedHostname (line 221) | func (m *MockAPI) GetVersionedHostname() string {
method IsAdmin (line 235) | func (m *MockAPI) IsAdmin(arg0 *http.Request) bool {
method IsFeatureEnabled (line 249) | func (m *MockAPI) IsFeatureEnabled(featureName string) bool {
method ScheduleResultsTask (line 263) | func (m *MockAPI) ScheduleResultsTask(uploader string, results, screen...
method ScheduleTask (line 278) | func (m *MockAPI) ScheduleTask(queueName, taskName, target string, par...
method UpdatePendingTestRun (line 293) | func (m *MockAPI) UpdatePendingTestRun(pendingRun shared.PendingTestRu...
method UploadToGCS (line 307) | func (m *MockAPI) UploadToGCS(gcsPath string, f io.Reader, gzipped boo...
type MockAPIMockRecorder (line 33) | type MockAPIMockRecorder struct
method AddTestRun (line 59) | func (mr *MockAPIMockRecorder) AddTestRun(testRun any) *gomock.Call {
method Context (line 73) | func (mr *MockAPIMockRecorder) Context() *gomock.Call {
method GetGitHubClient (line 88) | func (mr *MockAPIMockRecorder) GetGitHubClient() *gomock.Call {
method GetHTTPClient (line 102) | func (mr *MockAPIMockRecorder) GetHTTPClient() *gomock.Call {
method GetHTTPClientWithTimeout (line 116) | func (mr *MockAPIMockRecorder) GetHTTPClientWithTimeout(arg0 any) *gom...
method GetHostname (line 130) | func (mr *MockAPIMockRecorder) GetHostname() *gomock.Call {
method GetResultsURL (line 144) | func (mr *MockAPIMockRecorder) GetResultsURL(filter any) *gomock.Call {
method GetResultsUploadURL (line 158) | func (mr *MockAPIMockRecorder) GetResultsUploadURL() *gomock.Call {
method GetRunsURL (line 172) | func (mr *MockAPIMockRecorder) GetRunsURL(filter any) *gomock.Call {
method GetServiceHostname (line 186) | func (mr *MockAPIMockRecorder) GetServiceHostname(service any) *gomock...
method GetUploader (line 201) | func (mr *MockAPIMockRecorder) GetUploader(uploader any) *gomock.Call {
method GetVersion (line 215) | func (mr *MockAPIMockRecorder) GetVersion() *gomock.Call {
method GetVersionedHostname (line 229) | func (mr *MockAPIMockRecorder) GetVersionedHostname() *gomock.Call {
method IsAdmin (line 243) | func (mr *MockAPIMockRecorder) IsAdmin(arg0 any) *gomock.Call {
method IsFeatureEnabled (line 257) | func (mr *MockAPIMockRecorder) IsFeatureEnabled(featureName any) *gomo...
method ScheduleResultsTask (line 272) | func (mr *MockAPIMockRecorder) ScheduleResultsTask(uploader, results, ...
method ScheduleTask (line 287) | func (mr *MockAPIMockRecorder) ScheduleTask(queueName, taskName, targe...
method UpdatePendingTestRun (line 301) | func (mr *MockAPIMockRecorder) UpdatePendingTestRun(pendingRun any) *g...
method UploadToGCS (line 315) | func (mr *MockAPIMockRecorder) UploadToGCS(gcsPath, f, gzipped any) *g...
function NewMockAPI (line 38) | func NewMockAPI(ctrl *gomock.Controller) *MockAPI {
FILE: api/receiver/receive_results.go
constant BufferBucket (line 18) | BufferBucket = "wptd-results-buffer"
constant ResultsQueue (line 21) | ResultsQueue = "results-arrival"
constant ResultsTarget (line 24) | ResultsTarget = "/api/results/process"
function HandleResultsUpload (line 27) | func HandleResultsUpload(a API, w http.ResponseWriter, r *http.Request) {
function saveToGCS (line 113) | func saveToGCS(a API, uploader string, resultFiles, screenshotFiles []*m...
FILE: api/receiver/receive_results_test.go
type regexMatcher (line 32) | type regexMatcher struct
method Matches (line 36) | func (r *regexMatcher) Matches(x interface{}) bool {
method String (line 44) | func (r *regexMatcher) String() string {
function matchRegex (line 48) | func matchRegex(r string) *regexMatcher {
function TestHandleResultsUpload_not_admin (line 63) | func TestHandleResultsUpload_not_admin(t *testing.T) {
function TestHandleResultsUpload_http_basic_auth_invalid (line 76) | func TestHandleResultsUpload_http_basic_auth_invalid(t *testing.T) {
function TestHandleResultsUpload_extra_params (line 93) | func TestHandleResultsUpload_extra_params(t *testing.T) {
function TestHandleResultsUpload_azure (line 132) | func TestHandleResultsUpload_azure(t *testing.T) {
function TestHandleResultsUpload_archive (line 164) | func TestHandleResultsUpload_archive(t *testing.T) {
function TestHandleResultsUpload_archive_as_results (line 196) | func TestHandleResultsUpload_archive_as_results(t *testing.T) {
function TestHandleResultsUpload_url (line 228) | func TestHandleResultsUpload_url(t *testing.T) {
function TestHandleResultsUpload_file (line 260) | func TestHandleResultsUpload_file(t *testing.T) {
function TestHandleResultsUpload_fail_uploading (line 296) | func TestHandleResultsUpload_fail_uploading(t *testing.T) {
function TestHandleResultsUpload_empty_payload (line 322) | func TestHandleResultsUpload_empty_payload(t *testing.T) {
FILE: api/receiver/routes.go
function RegisterRoutes (line 10) | func RegisterRoutes() {
FILE: api/receiver/update_pending_run.go
function HandleUpdatePendingTestRun (line 19) | func HandleUpdatePendingTestRun(a API, w http.ResponseWriter, r *http.Re...
FILE: api/receiver/update_pending_run_test.go
function TestApiPendingTestRunUpdateHandler (line 25) | func TestApiPendingTestRunUpdateHandler(t *testing.T) {
FILE: api/results_redirect_handler.go
function apiResultsRedirectHandler (line 24) | func apiResultsRedirectHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/routes.go
function RegisterRoutes (line 10) | func RegisterRoutes() {
FILE: api/screenshot/cache.go
function parseParams (line 21) | func parseParams(r *http.Request) (browser, browserVersion, os, osVersio...
function getHashesHandler (line 30) | func getHashesHandler(w http.ResponseWriter, r *http.Request) {
function uploadScreenshotHandler (line 54) | func uploadScreenshotHandler(w http.ResponseWriter, r *http.Request) {
function storeScreenshot (line 123) | func storeScreenshot(
FILE: api/screenshot/model.go
constant MaxItemsInResponse (line 21) | MaxItemsInResponse = 10000
type Screenshot (line 33) | type Screenshot struct
method Hash (line 57) | func (s *Screenshot) Hash() string {
method Key (line 65) | func (s *Screenshot) Key() string {
method SetHashFromFile (line 70) | func (s *Screenshot) SetHashFromFile(f io.Reader, hashMethod string) e...
method Store (line 93) | func (s *Screenshot) Store(ds shared.Datastore) error {
function NewScreenshot (line 44) | func NewScreenshot(labels ...string) *Screenshot {
function RecentScreenshotHashes (line 117) | func RecentScreenshotHashes(
FILE: api/screenshot/model_medium_test.go
function TestNewScreenshot (line 22) | func TestNewScreenshot(t *testing.T) {
function TestKeyAndHash (line 27) | func TestKeyAndHash(t *testing.T) {
function TestSetHashFromFile (line 36) | func TestSetHashFromFile(t *testing.T) {
function TestSetHashFromFile_error (line 44) | func TestSetHashFromFile_error(t *testing.T) {
function TestStore (line 50) | func TestStore(t *testing.T) {
function TestRecentScreenshotHashes_filtering (line 106) | func TestRecentScreenshotHashes_filtering(t *testing.T) {
function TestRecentScreenshotHashes_ordering (line 159) | func TestRecentScreenshotHashes_ordering(t *testing.T) {
FILE: api/screenshot/routes.go
function RegisterRoutes (line 10) | func RegisterRoutes() {
FILE: api/screenshot_redirect_handler.go
function apiScreenshotRedirectHandler (line 20) | func apiScreenshotRedirectHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/shas.go
type SHAsHandler (line 18) | type SHAsHandler struct
method ServeHTTP (line 36) | func (h SHAsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
function apiSHAsHandler (line 23) | func apiSHAsHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/shas_medium_test.go
function TestApiSHAsHandler (line 18) | func TestApiSHAsHandler(t *testing.T) {
FILE: api/taskcluster/mock_taskcluster/webhook_mock.go
type MockAPI (line 21) | type MockAPI struct
method EXPECT (line 40) | func (m *MockAPI) EXPECT() *MockAPIMockRecorder {
method GetTaskGroupInfo (line 45) | func (m *MockAPI) GetTaskGroupInfo(arg0, arg1 string) (*taskcluster.Ta...
method ListCheckRuns (line 60) | func (m *MockAPI) ListCheckRuns(owner, repo string, checkSuiteID int64...
type MockAPIMockRecorder (line 28) | type MockAPIMockRecorder struct
method GetTaskGroupInfo (line 54) | func (mr *MockAPIMockRecorder) GetTaskGroupInfo(arg0, arg1 any) *gomoc...
method ListCheckRuns (line 69) | func (mr *MockAPIMockRecorder) ListCheckRuns(owner, repo, checkSuiteID...
function NewMockAPI (line 33) | func NewMockAPI(ctrl *gomock.Controller) *MockAPI {
FILE: api/taskcluster/routes.go
function RegisterRoutes (line 10) | func RegisterRoutes() {
FILE: api/taskcluster/webhook.go
constant AppID (line 28) | AppID = int64(40788)
constant uploaderName (line 30) | uploaderName = "taskcluster"
constant completedState (line 31) | completedState = "completed"
type TaskInfo (line 50) | type TaskInfo struct
type TaskGroupInfo (line 58) | type TaskGroupInfo struct
type EventInfo (line 65) | type EventInfo struct
type API (line 75) | type API interface
type apiImpl (line 80) | type apiImpl struct
method GetTaskGroupInfo (line 441) | func (api apiImpl) GetTaskGroupInfo(rootURL string, groupID string) (*...
method ListCheckRuns (line 472) | func (api apiImpl) ListCheckRuns(owner string, repo string, checkSuite...
function GetStatusEventInfo (line 86) | func GetStatusEventInfo(status StatusEventPayload, log shared.Logger, ap...
function GetCheckSuiteEventInfo (line 120) | func GetCheckSuiteEventInfo(checkSuite github.CheckSuiteEvent, log share...
function tcStatusWebhookHandler (line 212) | func tcStatusWebhookHandler(w http.ResponseWriter, r *http.Request) {
type StatusEventPayload (line 343) | type StatusEventPayload struct
method IsCompleted (line 348) | func (s StatusEventPayload) IsCompleted() bool {
method IsTaskcluster (line 353) | func (s StatusEventPayload) IsTaskcluster() bool {
method IsOnMaster (line 359) | func (s StatusEventPayload) IsOnMaster() bool {
function processTaskclusterBuild (line 369) | func processTaskclusterBuild(aeAPI shared.AppEngineAPI, event EventInfo,...
function ShouldProcessStatus (line 406) | func ShouldProcessStatus(log shared.Logger, status *StatusEventPayload) ...
function ParseTaskclusterURL (line 422) | func ParseTaskclusterURL(targetURL string) (rootURL, taskGroupID, taskID...
type ArtifactURLs (line 512) | type ArtifactURLs struct
function ExtractArtifactURLs (line 519) | func ExtractArtifactURLs(rootURL string, log shared.Logger, group *TaskG...
function CreateAllRuns (line 588) | func CreateAllRuns(
FILE: api/taskcluster/webhook_test.go
type branchInfos (line 31) | type branchInfos
function strPtr (line 33) | func strPtr(s string) *string {
function TestShouldProcessStatus_states (line 37) | func TestShouldProcessStatus_states(t *testing.T) {
function TestShouldProcessStatus_notTaskcluster (line 57) | func TestShouldProcessStatus_notTaskcluster(t *testing.T) {
function TestShouldProcessStatus_notOnMaster (line 65) | func TestShouldProcessStatus_notOnMaster(t *testing.T) {
function TestIsOnMaster (line 73) | func TestIsOnMaster(t *testing.T) {
function TestParseTaskclusterURL (line 98) | func TestParseTaskclusterURL(t *testing.T) {
function TestExtractArtifactURLs_all_success_master (line 125) | func TestExtractArtifactURLs_all_success_master(t *testing.T) {
function TestExtractArtifactURLs_all_success_pr (line 185) | func TestExtractArtifactURLs_all_success_pr(t *testing.T) {
function TestExtractArtifactURLs_with_failures (line 234) | func TestExtractArtifactURLs_with_failures(t *testing.T) {
function TestCreateAllRuns_success (line 252) | func TestCreateAllRuns_success(t *testing.T) {
function TestCreateAllRuns_one_error (line 310) | func TestCreateAllRuns_one_error(t *testing.T) {
function TestCreateAllRuns_all_errors (line 353) | func TestCreateAllRuns_all_errors(t *testing.T) {
function TestCreateAllRuns_pr_labels_exclude_master (line 387) | func TestCreateAllRuns_pr_labels_exclude_master(t *testing.T) {
function TestTaskNameRegex (line 429) | func TestTaskNameRegex(t *testing.T) {
function TestGetStatusEventInfo_target_url (line 443) | func TestGetStatusEventInfo_target_url(t *testing.T) {
function TestGetStatusEventInfo_sha (line 473) | func TestGetStatusEventInfo_sha(t *testing.T) {
function TestGetStatusEventInfo_master (line 496) | func TestGetStatusEventInfo_master(t *testing.T) {
function TestGetStatusEventInfo_sender (line 528) | func TestGetStatusEventInfo_sender(t *testing.T) {
function TestGetStatusEventInfo_group (line 553) | func TestGetStatusEventInfo_group(t *testing.T) {
function TestGetCheckSuiteEventInfo_sourceRepo (line 576) | func TestGetCheckSuiteEventInfo_sourceRepo(t *testing.T) {
function TestGetCheckSuiteEventInfo_sha (line 618) | func TestGetCheckSuiteEventInfo_sha(t *testing.T) {
function TestGetCheckSuiteEventInfo_master (line 654) | func TestGetCheckSuiteEventInfo_master(t *testing.T) {
function TestGetCheckSuiteEventInfo_sender (line 691) | func TestGetCheckSuiteEventInfo_sender(t *testing.T) {
function TestGetCheckSuiteEventInfo_checkRuns (line 730) | func TestGetCheckSuiteEventInfo_checkRuns(t *testing.T) {
function TestGetCheckSuiteEventInfo_checkRunsEmpty (line 796) | func TestGetCheckSuiteEventInfo_checkRunsEmpty(t *testing.T) {
function TestGetCheckSuiteEventInfo_checkRunsFailed (line 818) | func TestGetCheckSuiteEventInfo_checkRunsFailed(t *testing.T) {
FILE: api/test_history.go
type Subtest (line 14) | type Subtest
type Browser (line 17) | type Browser
type RequestBody (line 20) | type RequestBody struct
function testHistoryHandler (line 25) | func testHistoryHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/test_history_test.go
function TestHistoryHandler (line 22) | func TestHistoryHandler(t *testing.T) {
function parseHistoryResponse (line 69) | func parseHistoryResponse(t *testing.T, w *httptest.ResponseRecorder) ma...
FILE: api/test_run.go
function apiTestRunHandler (line 20) | func apiTestRunHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/test_run_medium_test.go
function TestGetTestRunByID (line 18) | func TestGetTestRunByID(t *testing.T) {
FILE: api/test_runs.go
constant nextPageTokenHeaderName (line 17) | nextPageTokenHeaderName = "wpt-next-page"
constant paginationTokenFeatureFlagName (line 18) | paginationTokenFeatureFlagName = "paginationTokens"
function apiTestRunsHandler (line 24) | func apiTestRunsHandler(w http.ResponseWriter, r *http.Request) {
function LoadTestRunKeysForFilters (line 114) | func LoadTestRunKeysForFilters(store shared.Datastore, filters shared.Te...
function LoadTestRunsForFilters (line 154) | func LoadTestRunsForFilters(
function getPRCommits (line 166) | func getPRCommits(aeAPI shared.AppEngineAPI, pr int) shared.SHAs {
FILE: api/test_runs_medium_test.go
function TestGetTestRuns_VersionPrefix (line 21) | func TestGetTestRuns_VersionPrefix(t *testing.T) {
function TestGetTestRuns_RunIDs (line 94) | func TestGetTestRuns_RunIDs(t *testing.T) {
function TestGetTestRuns_SHA (line 143) | func TestGetTestRuns_SHA(t *testing.T) {
function TestGetTestRuns_Pagination (line 217) | func TestGetTestRuns_Pagination(t *testing.T) {
FILE: api/user.go
type loginSuccessResponse (line 14) | type loginSuccessResponse struct
type loginFailureResponse (line 18) | type loginFailureResponse struct
function apiUserHandler (line 22) | func apiUserHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/versions.go
type VersionsHandler (line 19) | type VersionsHandler struct
method ServeHTTP (line 38) | func (h VersionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ...
function apiVersionsHandler (line 24) | func apiVersionsHandler(w http.ResponseWriter, r *http.Request) {
FILE: api/versions_medium_test.go
function TestApiVersionsHandler (line 17) | func TestApiVersionsHandler(t *testing.T) {
FILE: results-processor/config.py
function _is_prod (line 4) | def _is_prod() -> bool:
function raw_results_bucket (line 8) | def raw_results_bucket() -> str:
function results_bucket (line 15) | def results_bucket() -> str:
function project_baseurl (line 22) | def project_baseurl() -> str:
FILE: results-processor/gsutil.py
function _call (line 13) | def _call(command: List[str]) -> None:
function split_gcs_path (line 18) | def split_gcs_path(gcs_path: str) -> Tuple[str, str]:
function gs_to_public_url (line 27) | def gs_to_public_url(gs_url: str) -> str:
function copy (line 33) | def copy(
FILE: results-processor/main.py
function _atomic_write (line 36) | def _atomic_write(path: str, content: str) -> None:
function _serial_task (line 48) | def _serial_task(func: F) -> F:
function _internal_only (line 65) | def _internal_only(func: F) -> F:
function liveness_check (line 79) | def liveness_check() -> ResponseReturnValue:
function readiness_check (line 98) | def readiness_check() -> ResponseReturnValue:
function task_handler (line 113) | def task_handler() -> ResponseReturnValue:
FILE: results-processor/processor.py
class Processor (line 32) | class Processor(object):
method __init__ (line 40) | def __init__(self) -> None:
method __enter__ (line 55) | def __enter__(self) -> Self:
method __exit__ (line 60) | def __exit__(
method datastore (line 70) | def datastore(self) -> datastore.Client:
method auth (line 77) | def auth(self) -> Tuple[str, str]:
method raw_results_gs_url (line 86) | def raw_results_gs_url(self) -> str:
method raw_results_url (line 91) | def raw_results_url(self) -> str:
method results_gs_url (line 95) | def results_gs_url(self) -> str:
method results_url (line 100) | def results_url(self) -> str:
method check_existing_run (line 103) | def check_existing_run(self) -> bool:
method known_extension (line 120) | def known_extension(path: str) -> Optional[str]:
method _secret (line 128) | def _secret(self, token_name: str) -> str:
method _github_token (line 136) | def _github_token(self) -> str:
method _download_gcs (line 139) | def _download_gcs(self, gcs: str) -> str:
method _download_http (line 148) | def _download_http(self, url: str) -> Optional[str]:
method _download_single (line 191) | def _download_single(self, uri: str) -> Optional[str]:
method _download_archive (line 196) | def _download_archive(self, archive_url: str) -> None:
method download (line 212) | def download(
method load_report (line 235) | def load_report(self) -> None:
method upload_raw (line 240) | def upload_raw(self) -> None:
method upload_split (line 247) | def upload_split(self) -> None:
method create_run (line 271) | def create_run(
method update_status (line 297) | def update_status(
method run_hooks (line 338) | def run_hooks(self, tasks: List[Callable[[Self], None]]) -> None:
function _upload_screenshots (line 356) | def _upload_screenshots(processor: Processor) -> None:
function process_report (line 365) | def process_report(task_id: Optional[str], params: MultiDict[str, str]) ...
FILE: results-processor/processor_test.py
class ProcessorTest (line 17) | class ProcessorTest(unittest.TestCase):
method fake_download (line 18) | def fake_download(self, expected_path, response):
method test_known_extension (line 26) | def test_known_extension(self):
method test_download (line 40) | def test_download(self):
method test_download_azure (line 54) | def test_download_azure(self):
method test_download_azure_errors (line 72) | def test_download_azure_errors(self):
method test_download_github (line 88) | def test_download_github(self):
method test_download_numberless (line 103) | def test_download_numberless(self):
class MockProcessorTest (line 119) | class MockProcessorTest(unittest.TestCase):
method test_params_plumbing_success (line 121) | def test_params_plumbing_success(self, MockProcessor):
method test_params_plumbing_error (line 159) | def test_params_plumbing_error(self, MockProcessor):
method test_params_plumbing_empty (line 185) | def test_params_plumbing_empty(self, MockProcessor):
method test_params_plumbing_duplicate (line 205) | def test_params_plumbing_duplicate(self, MockProcessor):
class ProcessorDownloadServerTest (line 227) | class ProcessorDownloadServerTest(unittest.TestCase):
method setUp (line 232) | def setUp(self):
method tearDown (line 235) | def tearDown(self):
method test_download_single (line 239) | def test_download_single(self):
method test_download (line 247) | def test_download(self):
method test_download_content_disposition (line 265) | def test_download_content_disposition(self):
class ProcessorAPIServerTest (line 273) | class ProcessorAPIServerTest(unittest.TestCase):
method setUp (line 278) | def setUp(self):
method tearDown (line 281) | def tearDown(self):
method test_update_status (line 285) | def test_update_status(self):
method test_create_run (line 307) | def test_create_run(self):
FILE: results-processor/test_server.py
function screenshots_upload (line 22) | def screenshots_upload():
function slow (line 32) | def slow():
function download_attachment (line 38) | def download_attachment():
function download_json (line 45) | def download_json():
function echo_status (line 50) | def echo_status(run_id):
function echo_create (line 62) | def echo_create():
FILE: results-processor/test_util.py
function start_server (line 12) | def start_server(capture):
FILE: results-processor/wptreport.py
class RunInfo (line 64) | class RunInfo(TypedDict, total=False):
class SubtestResult (line 73) | class SubtestResult(TypedDict, total=False):
class TestResult (line 78) | class TestResult(TypedDict, total=False):
class RawWPTReport (line 84) | class RawWPTReport(TypedDict, total=False):
class TestRunMetadata (line 91) | class TestRunMetadata(TypedDict):
class WPTReportError (line 106) | class WPTReportError(Exception):
method __init__ (line 108) | def __init__(self, message: str,
method __str__ (line 113) | def __str__(self) -> str:
class InvalidJSONError (line 120) | class InvalidJSONError(WPTReportError):
method __init__ (line 121) | def __init__(self) -> None:
class MissingMetadataError (line 125) | class MissingMetadataError(WPTReportError):
method __init__ (line 126) | def __init__(self, key: str) -> None:
class InsufficientDataError (line 133) | class InsufficientDataError(WPTReportError):
method __init__ (line 134) | def __init__(self) -> None:
class ConflictingDataError (line 138) | class ConflictingDataError(WPTReportError):
method __init__ (line 139) | def __init__(self, key: str) -> None:
class BufferedHashsum (line 145) | class BufferedHashsum(object):
method __init__ (line 148) | def __init__(self,
method hash_file (line 155) | def hash_file(self, fileobj: IO[bytes]) -> None:
method hashsum (line 173) | def hashsum(self) -> str:
class WPTReport (line 178) | class WPTReport(object):
method __init__ (line 181) | def __init__(self) -> None:
method _add_chunk (line 189) | def _add_chunk(self, chunk: RawWPTReport) -> None:
method load_file (line 254) | def load_file(self, filename: str) -> None:
method load_json (line 267) | def load_json(self, fileobj: IO[bytes]) -> None:
method load_gzip_json (line 295) | def load_gzip_json(self, fileobj: IO[bytes]) -> None:
method update_metadata (line 305) | def update_metadata(
method write_json (line 327) | def write_json(fileobj: IO[bytes], payload: Any) -> None:
method write_gzip_json (line 342) | def write_gzip_json(filepath: str, payload: Any) -> None:
method results (line 357) | def results(self) -> List[TestResult]:
method run_info (line 362) | def run_info(self) -> RunInfo:
method hashsum (line 366) | def hashsum(self) -> str:
method summarize (line 370) | def summarize(self) -> Dict[str, Dict[str, Any]]:
method each_result (line 402) | def each_result(self) -> Iterator[Any]:
method write_summary (line 410) | def write_summary(self, filepath: str) -> None:
method write_result_directory (line 418) | def write_result_directory(self, directory: str) -> None:
method product_id (line 432) | def product_id(self, separator: str = '-', sanitize: bool = False) -> ...
method populate_upload_directory (line 458) | def populate_upload_directory(self,
method sha_product_path (line 484) | def sha_product_path(self) -> str:
method sha_summary_path (line 494) | def sha_summary_path(self) -> str:
method test_run_metadata (line 499) | def test_run_metadata(self) -> TestRunMetadata:
method normalize_version (line 537) | def normalize_version(self) -> None:
method finalize (line 543) | def finalize(self) -> None:
method serialize_gzip (line 560) | def serialize_gzip(self, filepath: str) -> None:
function _channel_to_labels (line 569) | def _channel_to_labels(browser: str, channel: str) -> Set[str]:
function prepare_labels (line 611) | def prepare_labels(report: WPTReport,
function normalize_product (line 655) | def normalize_product(report: WPTReport) -> Set[str]:
function create_test_run (line 681) | def create_test_run(
function main (line 733) | def main() -> None:
FILE: results-processor/wptreport_test.py
class WPTReportTest (line 24) | class WPTReportTest(unittest.TestCase):
method setUp (line 25) | def setUp(self):
method tearDown (line 28) | def tearDown(self):
method test_write_json (line 31) | def test_write_json(self):
method test_write_gzip_json (line 40) | def test_write_gzip_json(self):
method test_load_json (line 55) | def test_load_json(self):
method test_load_json_empty_report (line 67) | def test_load_json_empty_report(self):
method test_load_json_invalid_json (line 76) | def test_load_json_invalid_json(self):
method test_load_json_multiple_chunks (line 85) | def test_load_json_multiple_chunks(self):
method test_load_json_multiple_chunks_metadata (line 104) | def test_load_json_multiple_chunks_metadata(self):
method test_load_json_multiple_chunks_conflicting_data (line 146) | def test_load_json_multiple_chunks_conflicting_data(self):
method test_load_json_multiple_chunks_ignored_conflicting_data (line 182) | def test_load_json_multiple_chunks_ignored_conflicting_data(self):
method test_load_gzip_json (line 215) | def test_load_gzip_json(self):
method test_summarize (line 237) | def test_summarize(self):
method test_summarize_zero_results (line 265) | def test_summarize_zero_results(self):
method test_summarize_duplicate_results (line 270) | def test_summarize_duplicate_results(self):
method test_summarize_whitespaces (line 297) | def test_summarize_whitespaces(self):
method test_each_result (line 318) | def test_each_result(self):
method test_populate_upload_directory (line 369) | def test_populate_upload_directory(self):
method test_update_metadata (line 412) | def test_update_metadata(self):
method test_test_run_metadata (line 429) | def test_test_run_metadata(self):
method test_test_run_metadata_missing_required_fields (line 447) | def test_test_run_metadata_missing_required_fields(self):
method test_test_run_metadata_optional_fields (line 458) | def test_test_run_metadata_optional_fields(self):
method test_product_id (line 482) | def test_product_id(self):
method test_product_id_sanitize (line 498) | def test_product_id_sanitize(self):
method test_sha_product_path (line 511) | def test_sha_product_path(self):
method test_sha_summary_path (line 526) | def test_sha_summary_path(self):
method test_normalize_version (line 541) | def test_normalize_version(self):
method test_normalize_version_missing_version (line 549) | def test_normalize_version_missing_version(self):
class HelpersTest (line 557) | class HelpersTest(unittest.TestCase):
method test_prepare_labels_from_empty_str (line 558) | def test_prepare_labels_from_empty_str(self):
method test_prepare_labels_from_custom_labels (line 566) | def test_prepare_labels_from_custom_labels(self):
method test_prepare_labels_from_experimental_label (line 574) | def test_prepare_labels_from_experimental_label(self):
method test_prepare_labels_from_stable_label (line 582) | def test_prepare_labels_from_stable_label(self):
method test_prepare_labels_from_browser_channel (line 590) | def test_prepare_labels_from_browser_channel(self):
method test_normalize_product_edge (line 648) | def test_normalize_product_edge(self):
method test_normalize_product_edgechromium (line 664) | def test_normalize_product_edgechromium(self):
method test_normalize_product_webkitgtk_minibrowser (line 680) | def test_normalize_product_webkitgtk_minibrowser(self):
method test_normalize_product_wpewebkit_minibrowser (line 696) | def test_normalize_product_wpewebkit_minibrowser(self):
method test_normalize_product_noop (line 712) | def test_normalize_product_noop(self):
FILE: results-processor/wptscreenshot.py
function _initialize (line 36) | def _initialize(api: str,
function _upload (line 47) | def _upload(images: List[str]) -> None:
class WPTScreenshot (line 67) | class WPTScreenshot(object):
method __init__ (line 74) | def __init__(self, filename: str,
method __enter__ (line 106) | def __enter__(self) -> Self:
method __exit__ (line 119) | def __exit__(
method process (line 132) | def process(self) -> None:
FILE: results-processor/wptscreenshot_test.py
class WPTScreenshotTest (line 15) | class WPTScreenshotTest(unittest.TestCase):
method setUp (line 16) | def setUp(self):
method tearDown (line 29) | def tearDown(self):
method _batch_sizes (line 37) | def _batch_sizes(self, err_text):
method test_basic (line 43) | def test_basic(self):
method test_gzip (line 55) | def test_gzip(self):
method test_invalid_encoding (line 68) | def test_invalid_encoding(self):
method test_invalid_gzip (line 80) | def test_invalid_gzip(self):
method test_multiple_batches (line 92) | def test_multiple_batches(self):
method test_errors (line 106) | def test_errors(self):
FILE: scripts/check_chromium_revision.py
function trigger_ci_tests (line 35) | def trigger_ci_tests() -> str | None:
function get_token (line 57) | def get_token() -> str | None:
function get_start_revision (line 62) | def get_start_revision() -> int:
function check_new_chromium_revision (line 74) | def check_new_chromium_revision() -> str:
function main (line 148) | def main(args, _) -> None:
FILE: scripts/process_test_history.py
class TestHistoryEntry (line 51) | class TestHistoryEntry(ndb.Model):
class MostRecentHistoryProcessed (line 60) | class MostRecentHistoryProcessed(ndb.Model):
class TestRun (line 64) | class TestRun(ndb.Model):
class MetadataDict (line 79) | class MetadataDict(TypedDict):
function _build_new_test_history_entry (line 95) | def _build_new_test_history_entry(
function create_entity_if_needed (line 111) | def create_entity_if_needed(
function process_single_run (line 147) | def process_single_run(run_metadata: MetadataDict) -> None:
function get_previous_statuses (line 239) | def get_previous_statuses(browser_name: str) -> Any:
function update_previous_statuses (line 248) | def update_previous_statuses(
function _populate_previous_statuses (line 270) | def _populate_previous_statuses(browser_name: str) -> dict:
function should_process_run (line 295) | def should_process_run(run_metadata: MetadataDict) -> bool:
function process_runs (line 303) | def process_runs(
function get_aligned_run_info (line 351) | def get_aligned_run_info(
function update_recent_processed_date (line 410) | def update_recent_processed_date(
function set_history_start_date (line 419) | def set_history_start_date(new_date: str) -> None:
class NoRecentDateError (line 441) | class NoRecentDateError(Exception):
class DatastorePopulatedError (line 448) | class DatastorePopulatedError(Exception):
function get_processing_start_date (line 455) | def get_processing_start_date() -> MostRecentHistoryProcessed:
function check_if_db_empty (line 467) | def check_if_db_empty() -> None:
function delete_history_entities (line 483) | def delete_history_entities():
function main (line 496) | def main(args=None, topic=None) -> str:
FILE: scripts/update_chromium_revision.py
function all_passing_checks (line 28) | def all_passing_checks(repo_owner: str, repo_name: str, pr_number: str) ...
function update_pr_body (line 44) | def update_pr_body(
function get_new_revision (line 68) | def get_new_revision() -> str:
function update_chromium_revision (line 75) | def update_chromium_revision(new_revision) -> None:
function get_github_api_headers (line 84) | def get_github_api_headers():
function get_token (line 92) | def get_token() -> str:
function get_sha (line 97) | def get_sha(repo_owner: str, repo_name: str, pr_number: str) -> str:
function main (line 107) | def main(args, _):
FILE: shared/appengine.go
type clientsImpl (line 33) | type clientsImpl struct
method Init (line 51) | func (c *clientsImpl) Init(ctx context.Context) (err error) {
method Close (line 115) | func (c *clientsImpl) Close() {
type AppEngineAPI (line 165) | type AppEngineAPI interface
function init (line 228) | func init() {
function isDevAppserver (line 254) | func isDevAppserver() bool {
function NewAppEngineAPI (line 259) | func NewAppEngineAPI(ctx context.Context) AppEngineAPI {
type appEngineAPIImpl (line 266) | type appEngineAPIImpl struct
method Context (line 271) | func (a appEngineAPIImpl) Context() context.Context {
method GetHTTPClient (line 275) | func (a appEngineAPIImpl) GetHTTPClient() *http.Client {
method GetHTTPClientWithTimeout (line 280) | func (a appEngineAPIImpl) GetHTTPClientWithTimeout(timeout time.Durati...
method GetGitHubClient (line 284) | func (a *appEngineAPIImpl) GetGitHubClient() (*github.Client, error) {
method IsFeatureEnabled (line 295) | func (a appEngineAPIImpl) IsFeatureEnabled(featureName string) bool {
method GetUploader (line 300) | func (a appEngineAPIImpl) GetUploader(uploader string) (Uploader, erro...
method GetHostname (line 305) | func (a appEngineAPIImpl) GetHostname() string {
method GetVersion (line 316) | func (a appEngineAPIImpl) GetVersion() string {
method GetVersionedHostname (line 323) | func (a appEngineAPIImpl) GetVersionedHostname() string {
method GetServiceHostname (line 330) | func (a appEngineAPIImpl) GetServiceHostname(service string) string {
method GetResultsURL (line 337) | func (a appEngineAPIImpl) GetResultsURL(filter TestRunFilter) *url.URL {
method GetRunsURL (line 341) | func (a appEngineAPIImpl) GetRunsURL(filter TestRunFilter) *url.URL {
method GetResultsUploadURL (line 345) | func (a appEngineAPIImpl) GetResultsUploadURL() *url.URL {
method ScheduleTask (line 350) | func (a appEngineAPIImpl) ScheduleTask(queueName, taskName, target str...
function getURL (line 375) | func getURL(host, path string, filter TestRunFilter) *url.URL {
function createTaskRequest (line 381) | func createTaskRequest(queueName, taskName, target string, params url.Va...
FILE: shared/appengine_test.go
function TestCreateTaskRequest (line 17) | func TestCreateTaskRequest(t *testing.T) {
FILE: shared/browsers.go
function init (line 22) | func init() {
function GetDefaultBrowserNames (line 34) | func GetDefaultBrowserNames() []string {
function IsBrowserName (line 43) | func IsBrowserName(name string) bool {
function IsStableBrowserName (line 50) | func IsStableBrowserName(name string) bool {
FILE: shared/browsers_test.go
function TestGetDefaultBrowserNames (line 17) | func TestGetDefaultBrowserNames(t *testing.T) {
function TestIsBrowserName (line 41) | func TestIsBrowserName(t *testing.T) {
function TestIsBrowserName_DefaultBrowsers (line 65) | func TestIsBrowserName_DefaultBrowsers(t *testing.T) {
FILE: shared/cache.go
type Readable (line 35) | type Readable interface
type ReadWritable (line 42) | type ReadWritable interface
type httpReadable (line 49) | type httpReadable struct
method NewReadCloser (line 53) | func (hr httpReadable) NewReadCloser(iURL interface{}) (io.ReadCloser,...
function NewHTTPReadable (line 73) | func NewHTTPReadable(ctx context.Context) Readable {
type compositeReadWriteCloser (line 77) | type compositeReadWriteCloser struct
method Read (line 84) | func (crwc compositeReadWriteCloser) Read(p []byte) (n int, err error) {
method Write (line 88) | func (crwc compositeReadWriteCloser) Write(p []byte) (n int, err error) {
method Close (line 92) | func (crwc compositeReadWriteCloser) Close() error {
type gzipReadWritable (line 99) | type gzipReadWritable struct
method NewReadCloser (line 103) | func (gz gzipReadWritable) NewReadCloser(iID interface{}) (io.ReadClos...
method NewWriteCloser (line 126) | func (gz gzipReadWritable) NewWriteCloser(iID interface{}) (io.WriteCl...
function NewGZReadWritable (line 147) | func NewGZReadWritable(delegate ReadWritable) ReadWritable {
type redisReadWritable (line 151) | type redisReadWritable struct
method NewReadCloser (line 164) | func (mc redisReadWritable) NewReadCloser(iKey interface{}) (io.ReadCl...
method NewWriteCloser (line 189) | func (mc redisReadWritable) NewWriteCloser(iKey interface{}) (io.Write...
type redisWriteCloser (line 156) | type redisWriteCloser struct
method Write (line 197) | func (mw *redisWriteCloser) Write(p []byte) (n int, err error) {
method Close (line 205) | func (mw *redisWriteCloser) Close() error {
function NewRedisReadWritable (line 220) | func NewRedisReadWritable(ctx context.Context, expiry time.Duration) Rea...
type CachedStore (line 227) | type CachedStore interface
type byteCachedStore (line 231) | type byteCachedStore struct
method Get (line 237) | func (cs byteCachedStore) Get(cacheID, storeID, iValue interface{}) er...
function NewByteCachedStore (line 311) | func NewByteCachedStore(ctx context.Context, cache ReadWritable, store R...
type ObjectStore (line 316) | type ObjectStore interface
type ObjectCache (line 322) | type ObjectCache interface
type jsonObjectCache (line 327) | type jsonObjectCache struct
method Get (line 332) | func (oc jsonObjectCache) Get(id, value interface{}) error {
method Put (line 353) | func (oc jsonObjectCache) Put(id, value interface{}) error {
function NewJSONObjectCache (line 382) | func NewJSONObjectCache(ctx context.Context, delegate ReadWritable) Obje...
type objectCachedStore (line 386) | type objectCachedStore struct
method Get (line 392) | func (cs objectCachedStore) Get(cacheID, storeID, value interface{}) e...
function NewObjectCachedStore (line 421) | func NewObjectCachedStore(ctx context.Context, cache ObjectCache, store ...
function FlushCache (line 426) | func FlushCache() error {
function DeleteCache (line 439) | func DeleteCache(key string) error {
type RedisSet (line 452) | type RedisSet interface
type redisSetReadWritable (line 464) | type redisSetReadWritable struct
method Add (line 471) | func (ms redisSetReadWritable) Add(key string, value string) error {
method Remove (line 483) | func (ms redisSetReadWritable) Remove(key string, value string) error {
method GetAll (line 495) | func (ms redisSetReadWritable) GetAll(key string) ([]string, error) {
function NewRedisSet (line 467) | func NewRedisSet() RedisSet {
FILE: shared/cache_test.go
function TestGet_cacheHit (line 19) | func TestGet_cacheHit(t *testing.T) {
function TestGet_cacheMiss (line 39) | func TestGet_cacheMiss(t *testing.T) {
function TestGet_missing (line 64) | func TestGet_missing(t *testing.T) {
FILE: shared/datastore.go
constant MaxKeysPerLookup (line 23) | MaxKeysPerLookup = 1000
type Key (line 26) | type Key interface
type Iterator (line 33) | type Iterator interface
type Query (line 38) | type Query interface
type Datastore (line 51) | type Datastore interface
function GetFeatureFlags (line 78) | func GetFeatureFlags(ds Datastore) (flags []Flag, err error) {
function IsFeatureEnabled (line 89) | func IsFeatureEnabled(ds Datastore, flagName string) bool {
function SetFeature (line 99) | func SetFeature(ds Datastore, flag Flag) error {
function GetSecret (line 107) | func GetSecret(ds Datastore, tokenName string) (string, error) {
FILE: shared/datastore_cached.go
type cachedDatastore (line 16) | type cachedDatastore struct
method Get (line 21) | func (d cachedDatastore) Get(k Key, dst interface{}) error {
method GetMulti (line 33) | func (d cachedDatastore) GetMulti(keys []Key, dst interface{}) error {
type testRunObjectStore (line 57) | type testRunObjectStore struct
method Get (line 61) | func (d testRunObjectStore) Get(id, dst interface{}) error {
FILE: shared/datastore_cloud.go
type cloudKey (line 15) | type cloudKey struct
method IntID (line 19) | func (k cloudKey) IntID() int64 {
method StringID (line 23) | func (k cloudKey) StringID() string {
method Kind (line 27) | func (k cloudKey) Kind() string {
function NewAppEngineDatastore (line 37) | func NewAppEngineDatastore(ctx context.Context, cached bool) Datastore {
function NewCloudDatastore (line 50) | func NewCloudDatastore(ctx context.Context, client *datastore.Client) Da...
type cloudDatastore (line 57) | type cloudDatastore struct
method TestRunQuery (line 62) | func (d cloudDatastore) TestRunQuery() TestRunQuery {
method Context (line 66) | func (d cloudDatastore) Context() context.Context {
method Done (line 70) | func (d cloudDatastore) Done() interface{} {
method NewQuery (line 74) | func (d cloudDatastore) NewQuery(typeName string) Query {
method NewIDKey (line 80) | func (d cloudDatastore) NewIDKey(typeName string, id int64) Key {
method NewIncompleteKey (line 86) | func (d cloudDatastore) NewIncompleteKey(typeName string) Key {
method ReserveID (line 92) | func (d cloudDatastore) ReserveID(typeName string) (Key, error) {
method NewNameKey (line 104) | func (d cloudDatastore) NewNameKey(typeName string, name string) Key {
method GetAll (line 110) | func (d cloudDatastore) GetAll(q Query, dst interface{}) ([]Key, error) {
method Get (line 119) | func (d cloudDatastore) Get(k Key, dst interface{}) error {
method GetMulti (line 128) | func (d cloudDatastore) GetMulti(keys []Key, dst interface{}) error {
method Put (line 148) | func (d cloudDatastore) Put(key Key, src interface{}) (Key, error) {
method PutMulti (line 153) | func (d cloudDatastore) PutMulti(keys []Key, src interface{}) ([]Key, ...
method Insert (line 167) | func (d cloudDatastore) Insert(key Key, src interface{}) error {
method Update (line 182) | func (d cloudDatastore) Update(key Key, dst interface{}, mutator func(...
type cloudQuery (line 196) | type cloudQuery struct
method Filter (line 200) | func (q cloudQuery) Filter(filterStr string, value interface{}) Query {
method Project (line 204) | func (q cloudQuery) Project(fields ...string) Query {
method Offset (line 208) | func (q cloudQuery) Offset(offset int) Query {
method Limit (line 212) | func (q cloudQuery) Limit(limit int) Query {
method Order (line 216) | func (q cloudQuery) Order(order string) Query {
method KeysOnly (line 220) | func (q cloudQuery) KeysOnly() Query {
method Distinct (line 224) | func (q cloudQuery) Distinct() Query {
method Run (line 228) | func (q cloudQuery) Run(store Datastore) Iterator {
type cloudIterator (line 235) | type cloudIterator struct
method Next (line 239) | func (i cloudIterator) Next(dst interface{}) (Key, error) {
FILE: shared/datastore_medium_test.go
function TestIsFeatureEnabled (line 13) | func TestIsFeatureEnabled(t *testing.T) {
function TestGetSecret (line 35) | func TestGetSecret(t *testing.T) {
FILE: shared/errors.go
type MultiError (line 14) | type MultiError struct
method Error (line 47) | func (e MultiError) Error() string {
method Count (line 60) | func (e MultiError) Count() int {
method Errors (line 65) | func (e MultiError) Errors() []error {
function NewMultiErrorFromChan (line 25) | func NewMultiErrorFromChan(errors chan error, when string) error {
function NewMultiError (line 40) | func NewMultiError(errors []error, when string) error {
FILE: shared/errors_test.go
function TestNewMultiErrorFromChan_non_empty (line 16) | func TestNewMultiErrorFromChan_non_empty(t *testing.T) {
function TestNewMultiErrorFromChan_nil (line 29) | func TestNewMultiErrorFromChan_nil(t *testing.T) {
function TestNewMultiError_non_empty (line 45) | func TestNewMultiError_non_empty(t *testing.T) {
function TestNewMultiError_nil (line 55) | func TestNewMultiError_nil(t *testing.T) {
FILE: shared/fetch_bsf.go
constant experimentalBSFURL (line 19) | experimentalBSFURL = "https://raw.githubusercontent.com/web-platform-tes...
constant stableBSFURL (line 22) | stableBSFURL = "https://raw.githubusercontent.com/web-platform-tests/res...
type BSFData (line 26) | type BSFData struct
function FilterandExtractBSFData (line 42) | func FilterandExtractBSFData(rawBSFdata [][]string, from *time.Time, to ...
type FetchBSF (line 94) | type FetchBSF interface
type fetchBSF (line 98) | type fetchBSF struct
method Fetch (line 101) | func (f fetchBSF) Fetch(isExperimental bool) ([][]string, error) {
function NewFetchBSF (line 128) | func NewFetchBSF() FetchBSF {
FILE: shared/fetch_bsf_test.go
function TestFilterandExtractBSFData_WithoutFilter (line 15) | func TestFilterandExtractBSFData_WithoutFilter(t *testing.T) {
function TestFilterandExtractBSFData_WithFilter (line 30) | func TestFilterandExtractBSFData_WithFilter(t *testing.T) {
function TestFilterandExtractBSFData_EmptyData (line 54) | func TestFilterandExtractBSFData_EmptyData(t *testing.T) {
FILE: shared/fetch_runs.go
function FetchLatestRuns (line 18) | func FetchLatestRuns(wptdHost string) (TestRuns, error) {
function FetchRuns (line 24) | func FetchRuns(wptdHost string, filter TestRunFilter) (TestRuns, error) {
function FetchJSON (line 35) | func FetchJSON(url string, value interface{}) error {
FILE: shared/github_oauth.go
function init (line 22) | func init() {
type User (line 28) | type User struct
type GitHubAccessControl (line 34) | type GitHubAccessControl interface
type githubAccessControlImpl (line 40) | type githubAccessControlImpl struct
method isValidAccessToken (line 137) | func (gaci githubAccessControlImpl) isValidAccessToken() (bool, error) {
method IsValidWPTMember (line 146) | func (gaci githubAccessControlImpl) IsValidWPTMember() (bool, error) {
method IsValidAdmin (line 158) | func (gaci githubAccessControlImpl) IsValidAdmin() (bool, error) {
type GitHubOAuth (line 55) | type GitHubOAuth interface
type githubOAuthImpl (line 65) | type githubOAuthImpl struct
method Datastore (line 72) | func (g *githubOAuthImpl) Datastore() Datastore {
method Context (line 76) | func (g *githubOAuthImpl) Context() context.Context {
method GetAccessToken (line 80) | func (g *githubOAuthImpl) GetAccessToken() string {
method SetRedirectURL (line 84) | func (g *githubOAuthImpl) SetRedirectURL(url string) {
method GetAuthCodeURL (line 88) | func (g *githubOAuthImpl) GetAuthCodeURL(state string, opts ...oauth2....
method NewClient (line 92) | func (g *githubOAuthImpl) NewClient(oauthCode string) (*github.Client,...
method GetUser (line 105) | func (g *githubOAuthImpl) GetUser(client *github.Client) (*github.User...
function NewGitHubOAuth (line 116) | func NewGitHubOAuth(ctx context.Context) (GitHubOAuth, error) {
function NewGitHubAccessControl (line 178) | func NewGitHubAccessControl(ctx context.Context, ds Datastore, botClient...
function NewGitHubAccessControlFromRequest (line 201) | func NewGitHubAccessControlFromRequest(aeAPI AppEngineAPI, ds Datastore,...
function NewSecureCookie (line 216) | func NewSecureCookie(store Datastore) (*securecookie.SecureCookie, error) {
function GetUserFromCookie (line 234) | func GetUserFromCookie(ctx context.Context, ds Datastore, r *http.Reques...
function NewGitHubClientFromToken (line 259) | func NewGitHubClientFromToken(ctx context.Context, token string) *github...
function getOAuthClientIDSecret (line 266) | func getOAuthClientIDSecret(store Datastore) (clientID, clientSecret str...
FILE: shared/logger.go
type Logger (line 16) | type Logger interface
type LoggerCtxKey (line 24) | type LoggerCtxKey struct
function DefaultLoggerCtxKey (line 30) | func DefaultLoggerCtxKey() LoggerCtxKey {
function withLogger (line 35) | func withLogger(ctx context.Context, logger Logger) context.Context {
type nilLogger (line 39) | type nilLogger struct
method Debugf (line 43) | func (l nilLogger) Debugf(format string, args ...interface{}) {}
method Errorf (line 45) | func (l nilLogger) Errorf(format string, args ...interface{}) {}
method Infof (line 47) | func (l nilLogger) Infof(format string, args ...interface{}) {}
method Warningf (line 49) | func (l nilLogger) Warningf(format string, args ...interface{}) {}
function NewNilLogger (line 52) | func NewNilLogger() Logger {
type gcLogger (line 56) | type gcLogger struct
method log (line 62) | func (gcl *gcLogger) log(severity gclog.Severity, format string, param...
method Debugf (line 76) | func (gcl *gcLogger) Debugf(format string, params ...interface{}) {
method Infof (line 80) | func (gcl *gcLogger) Infof(format string, params ...interface{}) {
method Warningf (line 84) | func (gcl *gcLogger) Warningf(format string, params ...interface{}) {
method Errorf (line 88) | func (gcl *gcLogger) Errorf(format string, params ...interface{}) {
type responseWriter (line 92) | type responseWriter struct
method Header (line 97) | func (w *responseWriter) Header() http.Header {
method Write (line 101) | func (w *responseWriter) Write(b []byte) (int, error) {
method WriteHeader (line 111) | func (w *responseWriter) WriteHeader(statusCode int) {
function HandleWithLogging (line 119) | func HandleWithLogging(h http.HandlerFunc) http.HandlerFunc {
function withLocalLogger (line 130) | func withLocalLogger(h http.HandlerFunc, w http.ResponseWriter, r *http....
function withGCLogger (line 136) | func withGCLogger(h http.HandlerFunc, w http.ResponseWriter, r *http.Req...
function GetLogger (line 169) | func GetLogger(ctx context.Context) Logger {
FILE: shared/manifest.go
type Manifest (line 18) | type Manifest struct
method FilterByPath (line 42) | func (m Manifest) FilterByPath(paths ...string) (*Manifest, error) {
method unmarshalAll (line 59) | func (m *Manifest) unmarshalAll() error {
method ContainsFile (line 88) | func (m *Manifest) ContainsFile(path string) (bool, error) {
method ContainsTest (line 108) | func (m *Manifest) ContainsTest(testURL string) (bool, error) {
type rawManifestTrie (line 31) | type rawManifestTrie
method MarshalJSON (line 33) | func (t rawManifestTrie) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 37) | func (t *rawManifestTrie) UnmarshalJSON(b []byte) error {
method FilterByPath (line 154) | func (t rawManifestTrie) FilterByPath(pathParts []string) (rawManifest...
function findNode (line 74) | func findNode(t interface{}, parts []string) interface{} {
function explosions (line 175) | func explosions() map[string][]string {
function implosions (line 190) | func implosions() [][]string {
function ExplodePossibleRenames (line 203) | func ExplodePossibleRenames(before, after string) map[string]string {
function ExplodePossibleFilenames (line 219) | func ExplodePossibleFilenames(filePath string) []string {
function ParseTestURL (line 239) | func ParseTestURL(testURL string) (filePath, query string) {
FILE: shared/manifest_test.go
function TestManifestFilterByPath (line 55) | func TestManifestFilterByPath(t *testing.T) {
function TestExplodePossibleFilename_AnyJS (line 94) | func TestExplodePossibleFilename_AnyJS(t *testing.T) {
function TestExplodePossibleFilename_WindowJS (line 105) | func TestExplodePossibleFilename_WindowJS(t *testing.T) {
function TestExplodePossibleFilename_Standard (line 113) | func TestExplodePossibleFilename_Standard(t *testing.T) {
function TestExplodePossibleRenames_AnyJS (line 118) | func TestExplodePossibleRenames_AnyJS(t *testing.T) {
function TestExplodePossibleRenames_WindowJS (line 130) | func TestExplodePossibleRenames_WindowJS(t *testing.T) {
function TestExplodePossibleRenames_WorkerJS (line 139) | func TestExplodePossibleRenames_WorkerJS(t *testing.T) {
function TestParseTestURL (line 148) | func TestParseTestURL(t *testing.T) {
function TestManifestContainsFile (line 174) | func TestManifestContainsFile(t *testing.T) {
function TestManifestContainsTest (line 214) | func TestManifestContainsTest(t *testing.T) {
FILE: shared/metadata.go
constant ShowMetadataParam (line 15) | ShowMetadataParam = "metadataInfo"
constant MetadataFileName (line 18) | MetadataFileName = "META.yml"
type MetadataResults (line 23) | type MetadataResults
type Metadata (line 26) | type Metadata struct
type MetadataLinks (line 31) | type MetadataLinks
type MetadataLink (line 36) | type MetadataLink struct
type MetadataTestResult (line 45) | type MetadataTestResult struct
function GetMetadataResponse (line 55) | func GetMetadataResponse(testRuns []TestRun, includeTestLevel bool, log ...
function GetMetadataResponseOnProducts (line 75) | func GetMetadataResponseOnProducts(productSpecs ProductSpecs, includeTes...
function GetMetadataByteMap (line 88) | func GetMetadataByteMap(log Logger, fetcher MetadataFetcher) (sha *strin...
function parseMetadata (line 99) | func parseMetadata(metadataByteMap map[string][]byte, log Logger) map[st...
function addResponseLink (line 116) | func addResponseLink(fullTestName string, link MetadataLink, result Meta...
function constructMetadataResponse (line 139) | func constructMetadataResponse(productSpecs ProductSpecs, includeTestLev...
function PrepareLinkFilter (line 166) | func PrepareLinkFilter(metadata MetadataResults) map[string][]string {
function PrepareTestLabelFilter (line 184) | func PrepareTestLabelFilter(metadata MetadataResults) map[string][]string {
function GetWPTTestPath (line 203) | func GetWPTTestPath(folderPath string, testname string) string {
function SplitWPTTestPath (line 211) | func SplitWPTTestPath(githubPath string) (string, string) {
function GetMetadataFilePath (line 227) | func GetMetadataFilePath(folderName string) string {
FILE: shared/metadata_test.go
function TestMarshalMetadata (line 16) | func TestMarshalMetadata(t *testing.T) {
function TestParseMetadata (line 48) | func TestParseMetadata(t *testing.T) {
function TestConstructMetadataResponse_OneLink (line 93) | func TestConstructMetadataResponse_OneLink(t *testing.T) {
function TestConstructMetadataResponse_NoMatchingLink (line 164) | func TestConstructMetadataResponse_NoMatchingLink(t *testing.T) {
function TestConstructMetadataResponse_MultipleLinks (line 199) | func TestConstructMetadataResponse_MultipleLinks(t *testing.T) {
function TestConstructMetadataResponse_OneMatchingBrowserVersion (line 245) | func TestConstructMetadataResponse_OneMatchingBrowserVersion(t *testing....
function TestConstructMetadataResponse_TestIssueMetadata (line 282) | func TestConstructMetadataResponse_TestIssueMetadata(t *testing.T) {
function TestGetWPTTestPath (line 316) | func TestGetWPTTestPath(t *testing.T) {
function TestGetWPTTestPath_EmptyFolder (line 321) | func TestGetWPTTestPath_EmptyFolder(t *testing.T) {
function TestSplitWPTTestPath_InvalidPath (line 326) | func TestSplitWPTTestPath_InvalidPath(t *testing.T) {
function TestSplitWPTTestPath_EmptyPath (line 332) | func TestSplitWPTTestPath_EmptyPath(t *testing.T) {
function TestSplitWPTTestPath_NoFolderPath (line 338) | func TestSplitWPTTestPath_NoFolderPath(t *testing.T) {
function TestSplitWPTTestPath_Success (line 344) | func TestSplitWPTTestPath_Success(t *testing.T) {
function TestGetMetadataFilePath (line 354) | func TestGetMetadataFilePath(t *testing.T) {
function TestPrepareLinkFilter (line 362) | func TestPrepareLinkFilter(t *testing.T) {
function TestPrepareTestLabelFilter (line 391) | func TestPrepareTestLabelFilter(t *testing.T) {
FILE: shared/metadata_util.go
constant PendingMetadataCacheKey (line 24) | PendingMetadataCacheKey = "WPT-PENDING-METADATA"
constant PendingMetadataCachePrefix (line 28) | PendingMetadataCachePrefix = "PENDING-PR-"
constant SourceOwner (line 31) | SourceOwner string = "web-platform-tests"
constant SourceRepo (line 34) | SourceRepo string = "wpt-metadata"
constant baseBranch (line 35) | baseBranch string = "master"
type MetadataFetcher (line 39) | type MetadataFetcher interface
function GetWPTMetadataMasterSHA (line 44) | func GetWPTMetadataMasterSHA(ctx context.Context, gitHubClient *github.C...
function GetWPTMetadataArchive (line 55) | func GetWPTMetadataArchive(client *http.Client, ref *string) (res map[st...
function getWPTMetadataArchiveWithURL (line 60) | func getWPTMetadataArchiveWithURL(client *http.Client, url string, ref *...
function parseMetadataFromGZip (line 84) | func parseMetadataFromGZip(gzip *gzip.Reader) (res map[string][]byte, er...
FILE: shared/metadata_util_test.go
function TestGetWPTMetadataArchiveWithURL (line 19) | func TestGetWPTMetadataArchiveWithURL(t *testing.T) {
function TestParseMetadataFromGZip_Success (line 54) | func TestParseMetadataFromGZip_Success(t *testing.T) {
FILE: shared/metrics/models.go
type SubTest (line 18) | type SubTest struct
type TestResults (line 25) | type TestResults struct
type RunInfo (line 34) | type RunInfo struct
method MarshalJSON (line 40) | func (r RunInfo) MarshalJSON() ([]byte, error) {
type TestResultsReport (line 55) | type TestResultsReport struct
type TestRunsMetadata (line 61) | type TestRunsMetadata struct
method Load (line 72) | func (t *TestRunsMetadata) Load(ps []datastore.Property) error {
method Save (line 83) | func (t *TestRunsMetadata) Save() ([]datastore.Property, error) {
method LoadTestRuns (line 88) | func (t *TestRunsMetadata) LoadTestRuns(ctx context.Context) (err erro...
type TestRunLegacy (line 98) | type TestRunLegacy struct
method Load (line 125) | func (r *TestRunLegacy) Load(ps []datastore.Property) error {
method Save (line 137) | func (r *TestRunLegacy) Save() ([]datastore.Property, error) {
function ConvertRuns (line 142) | func ConvertRuns(runs shared.TestRuns) (converted []TestRunLegacy, err e...
type TestRunsMetadataLegacy (line 155) | type TestRunsMetadataLegacy struct
method LoadTestRuns (line 164) | func (t *TestRunsMetadataLegacy) LoadTestRuns(ctx context.Context) (er...
method Load (line 178) | func (t *TestRunsMetadataLegacy) Load(ps []datastore.Property) error {
method Save (line 189) | func (t *TestRunsMetadataLegacy) Save() ([]datastore.Property, error) {
type PassRateMetadata (line 197) | type PassRateMetadata struct
type PassRateMetadataLegacy (line 206) | type PassRateMetadataLegacy struct
function GetDatastoreKindName (line 212) | func GetDatastoreKindName(data interface{}) string {
FILE: shared/metrics/models_test.go
function TestTestRunsLegacy_Convert (line 17) | func TestTestRunsLegacy_Convert(t *testing.T) {
function TestGetDatastoreKindName (line 44) | func TestGetDatastoreKindName(t *testing.T) {
FILE: shared/models.go
type Product (line 17) | type Product struct
method String (line 24) | func (p Product) String() string {
type ByBrowserName (line 39) | type ByBrowserName
method Len (line 41) | func (e ByBrowserName) Len() int { return len(e) }
method Swap (line 42) | func (e ByBrowserName) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
method Less (line 43) | func (e ByBrowserName) Less(i, j int) bool { return e[i].BrowserName <...
type Version (line 46) | type Version struct
method String (line 54) | func (v Version) String() string {
type ProductAtRevision (line 73) | type ProductAtRevision struct
method String (line 85) | func (p ProductAtRevision) String() string {
type TestRun (line 90) | type TestRun struct
method IsExperimental (line 116) | func (r TestRun) IsExperimental() bool {
method IsPRBase (line 121) | func (r TestRun) IsPRBase() bool {
method hasLabel (line 125) | func (r TestRun) hasLabel(label string) bool {
method Channel (line 130) | func (r TestRun) Channel() string {
method Load (line 144) | func (r *TestRun) Load(ps []datastore.Property) error {
method Save (line 156) | func (r *TestRun) Save() ([]datastore.Property, error) {
method LabelsSet (line 328) | func (r TestRun) LabelsSet() mapset.Set {
type PendingTestRunStage (line 161) | type PendingTestRunStage
method String (line 179) | func (s PendingTestRunStage) String() string {
method MarshalJSON (line 210) | func (s PendingTestRunStage) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 215) | func (s *PendingTestRunStage) UnmarshalJSON(b []byte) error {
constant StageGitHubQueued (line 165) | StageGitHubQueued PendingTestRunStage = 100
constant StageGitHubInProgress (line 166) | StageGitHubInProgress PendingTestRunStage = 200
constant StageCIRunning (line 167) | StageCIRunning PendingTestRunStage = 300
constant StageCIFinished (line 168) | StageCIFinished PendingTestRunStage = 400
constant StageGitHubSuccess (line 169) | StageGitHubSuccess PendingTestRunStage = 500
constant StageGitHubFailure (line 170) | StageGitHubFailure PendingTestRunStage = 550
constant StageWptFyiReceived (line 171) | StageWptFyiReceived PendingTestRunStage = 600
constant StageWptFyiProcessing (line 172) | StageWptFyiProcessing PendingTestRunStage = 700
constant StageValid (line 173) | StageValid PendingTestRunStage = 800
constant StageInvalid (line 174) | StageInvalid PendingTestRunStage = 850
constant StageEmpty (line 175) | StageEmpty PendingTestRunStage = 851
constant StageDuplicate (line 176) | StageDuplicate PendingTestRunStage = 852
type PendingTestRun (line 256) | type PendingTestRun struct
method Transition (line 270) | func (s *PendingTestRun) Transition(next PendingTestRunStage) error {
method Load (line 280) | func (s *PendingTestRun) Load(ps []datastore.Property) error {
method Save (line 291) | func (s *PendingTestRun) Save() ([]datastore.Property, error) {
type PendingTestRunByUpdated (line 296) | type PendingTestRunByUpdated
method Len (line 298) | func (a PendingTestRunByUpdated) Len() int { return len(a) }
method Swap (line 299) | func (a PendingTestRunByUpdated) Swap(i, j int) { a[i], a[j] = a[...
method Less (line 300) | func (a PendingTestRunByUpdated) Less(i, j int) bool { return a[i].Upd...
type TestHistoryEntry (line 303) | type TestHistoryEntry struct
type CheckSuite (line 315) | type CheckSuite struct
type TestRuns (line 337) | type TestRuns
method Len (line 339) | func (t TestRuns) Len() int { return len(t) }
method Less (line 340) | func (t TestRuns) Less(i, j int) bool { return t[i].TimeStart.Before(t...
method Swap (line 341) | func (t TestRuns) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
method SetTestRunIDs (line 344) | func (t TestRuns) SetTestRunIDs(ids TestRunIDs) {
method GetTestRunIDs (line 351) | func (t TestRuns) GetTestRunIDs() TestRunIDs {
method OldestRunTimeStart (line 360) | func (t TestRuns) OldestRunTimeStart() time.Time {
type ProductTestRuns (line 374) | type ProductTestRuns struct
type TestRunsByProduct (line 381) | type TestRunsByProduct
method AllRuns (line 384) | func (t TestRunsByProduct) AllRuns() TestRuns {
method First (line 393) | func (t TestRunsByProduct) First() *TestRun {
type ProductTestRunKeys (line 402) | type ProductTestRunKeys struct
type KeysByProduct (line 409) | type KeysByProduct
method AllKeys (line 412) | func (t KeysByProduct) AllKeys() []Key {
type TestRunIDs (line 421) | type TestRunIDs
method GetKeys (line 433) | func (ids TestRunIDs) GetKeys(store Datastore) []Key {
method LoadTestRuns (line 443) | func (ids TestRunIDs) LoadTestRuns(store Datastore) (testRuns TestRuns...
function GetTestRunIDs (line 424) | func GetTestRunIDs(keys []Key) TestRunIDs {
type Browser (line 456) | type Browser struct
type Token (line 467) | type Token struct
type Uploader (line 473) | type Uploader struct
type Flag (line 479) | type Flag struct
type LegacySearchRunResult (line 488) | type LegacySearchRunResult struct
type SearchResult (line 504) | type SearchResult struct
type SearchResponse (line 528) | type SearchResponse struct
FILE: shared/models_test.go
function TestTestRunIDs_LoadTestRuns (line 13) | func TestTestRunIDs_LoadTestRuns(t *testing.T) {
FILE: shared/params.go
type QueryFilter (line 26) | type QueryFilter struct
constant MaxCountMaxValue (line 32) | MaxCountMaxValue = 500
constant MaxCountMinValue (line 35) | MaxCountMinValue = 1
function ParseSHAParam (line 41) | func ParseSHAParam(v url.Values) (SHAs, error) {
function ParseSHA (line 55) | func ParseSHA(shaParam string) (sha string, err error) {
function ParseProductSpecs (line 68) | func ParseProductSpecs(specs ...string) (products ProductSpecs, err erro...
function splitAtNonMainAt (line 84) | func splitAtNonMainAt(stringInput string) []string {
function ParseProductSpec (line 111) | func ParseProductSpec(spec string) (productSpec ProductSpec, err error) {
function ParseProductSpecUnsafe (line 154) | func ParseProductSpecUnsafe(s string) ProductSpec {
function ParseProduct (line 160) | func ParseProduct(product string) (result Product, err error) {
function ParseVersion (line 190) | func ParseVersion(version string) (result *Version, err error) {
function ParseBrowserParam (line 237) | func ParseBrowserParam(v url.Values) (product *Product, err error) {
function ParseBrowsersParam (line 253) | func ParseBrowsersParam(v url.Values) (browsers []string, err error) {
function ParseProductParam (line 268) | func ParseProductParam(v url.Values) (product *ProductSpec, err error) {
function ParseProductsParam (line 283) | func ParseProductsParam(v url.Values) (ProductSpecs, error) {
function ParseProductOrBrowserParams (line 305) | func ParseProductOrBrowserParams(v url.Values) (products ProductSpecs, e...
function ParseMaxCountParam (line 323) | func ParseMaxCountParam(v url.Values) (*int, error) {
function ParseOffsetParam (line 341) | func ParseOffsetParam(v url.Values) (*int, error) {
function ParseMaxCountParamWithDefault (line 354) | func ParseMaxCountParamWithDefault(v url.Values, defaultValue int) (coun...
function ParseViewParam (line 364) | func ParseViewParam(v url.Values) (*string, error) {
function ParseDateTimeParam (line 373) | func ParseDateTimeParam(v url.Values, name string) (*time.Time, error) {
type DiffFilterParam (line 389) | type DiffFilterParam struct
method String (line 407) | func (d DiffFilterParam) String() string {
function ParseDiffFilterParams (line 427) | func ParseDiffFilterParams(v url.Values) (param DiffFilterParam, paths m...
function ParsePathsParam (line 456) | func ParsePathsParam(v url.Values) []string {
function ParseLabelsParam (line 462) | func ParseLabelsParam(v url.Values) []string {
function ParseRepeatedParam (line 469) | func ParseRepeatedParam(v url.Values, singular string, plural string) (p...
function parseRepeatedParamValues (line 475) | func parseRepeatedParamValues(repeatedParam []string, pluralParam string...
function ParseIntParam (line 498) | func ParseIntParam(v url.Values, param string) (*int, error) {
function ParseRepeatedInt64Param (line 511) | func ParseRepeatedInt64Param(v url.Values, singular, plural string) (par...
function ParseQueryParamInt (line 528) | func ParseQueryParamInt(v url.Values, key string) (*int, error) {
function ParseAlignedParam (line 541) | func ParseAlignedParam(v url.Values) (aligned *bool, err error) {
function ParseBooleanParam (line 552) | func ParseBooleanParam(v url.Values, name string) (result *bool, err err...
function ParseRunIDsParam (line 567) | func ParseRunIDsParam(v url.Values) (ids TestRunIDs, err error) {
function ParsePRParam (line 573) | func ParsePRParam(v url.Values) (*int, error) {
function ParseQueryFilterParams (line 578) | func ParseQueryFilterParams(v url.Values) (filter QueryFilter, err error) {
function ParseTestRunFilterParams (line 591) | func ParseTestRunFilterParams(v url.Values) (filter TestRunFilter, err e...
function ParseBeforeAndAfterParams (line 634) | func ParseBeforeAndAfterParams(v url.Values) (ProductSpecs, error) {
function ParsePageToken (line 662) | func ParsePageToken(v url.Values) (*TestRunFilter, error) {
function ExtractRunIDsBodyParam (line 681) | func ExtractRunIDsBodyParam(r *http.Request, replay bool) (TestRunIDs, e...
FILE: shared/params_test.go
function TestParseSHAParam (line 24) | func TestParseSHAParam(t *testing.T) {
function TestParseSHAParam_Latest (line 31) | func TestParseSHAParam_Latest(t *testing.T) {
function TestParseSHAParam_ShortSHA (line 38) | func TestParseSHAParam_ShortSHA(t *testing.T) {
function TestParseSHAParam_FullSHA (line 46) | func TestParseSHAParam_FullSHA(t *testing.T) {
function TestParseSHAParam_TooShortSHA (line 54) | func TestParseSHAParam_TooShortSHA(t *testing.T) {
function TestParseSHAParam_TooLongSHA (line 60) | func TestParseSHAParam_TooLongSHA(t *testing.T) {
function TestParseSHAParam_NonSHAs (line 67) | func TestParseSHAParam_NonSHAs(t *testing.T) {
function TestParseSHAParam_Multiple (line 77) | func TestParseSHAParam_Multiple(t *testing.T) {
function TestParseBrowserParam (line 90) | func TestParseBrowserParam(t *testing.T) {
function TestParseBrowserParam_Chrome (line 97) | func TestParseBrowserParam_Chrome(t *testing.T) {
function TestParseBrowserParam_Invalid (line 105) | func TestParseBrowserParam_Invalid(t *testing.T) {
function TestGetProductsOrDefault_Default (line 112) | func TestGetProductsOrDefault_Default(t *testing.T) {
function TestGetProductsOrDefault_BrowserParam_ChromeSafari (line 124) | func TestGetProductsOrDefault_BrowserParam_ChromeSafari(t *testing.T) {
function TestGetProductsOrDefault_BrowserParam_ChromeInvalid (line 134) | func TestGetProductsOrDefault_BrowserParam_ChromeInvalid(t *testing.T) {
function TestGetProductsOrDefault_BrowserParam_EmptyCommas (line 140) | func TestGetProductsOrDefault_BrowserParam_EmptyCommas(t *testing.T) {
function TestGetProductsOrDefault_BrowserParam_SafariChrome (line 150) | func TestGetProductsOrDefault_BrowserParam_SafariChrome(t *testing.T) {
function TestGetProductsOrDefault_BrowserParam_WebKitNightly (line 160) | func TestGetProductsOrDefault_BrowserParam_WebKitNightly(t *testing.T) {
function TestGetProductsOrDefault_BrowserParam_MultiBrowserParam_SafariChrome (line 174) | func TestGetProductsOrDefault_BrowserParam_MultiBrowserParam_SafariChrom...
function TestGetProductsOrDefault_BrowserParam_MultiBrowserParam_SafariInvalid (line 184) | func TestGetProductsOrDefault_BrowserParam_MultiBrowserParam_SafariInval...
function TestGetProductsOrDefault_BrowserAndProductParam (line 190) | func TestGetProductsOrDefault_BrowserAndProductParam(t *testing.T) {
function TestGetProductsOrDefault_BrowsersAndProductsParam (line 201) | func TestGetProductsOrDefault_BrowsersAndProductsParam(t *testing.T) {
function TestParseMaxCountParam_Missing (line 214) | func TestParseMaxCountParam_Missing(t *testing.T) {
function TestParseMaxCountParam_TooSmall (line 225) | func TestParseMaxCountParam_TooSmall(t *testing.T) {
function TestParseMaxCountParam_TooLarge (line 237) | func TestParseMaxCountParam_TooLarge(t *testing.T) {
function TestParseMaxCountParam (line 249) | func TestParseMaxCountParam(t *testing.T) {
function TestParseDateTimeParam (line 256) | func TestParseDateTimeParam(t *testing.T) {
function TestParsePathsParam_Missing (line 295) | func TestParsePathsParam_Missing(t *testing.T) {
function TestParsePathsParam_Empty (line 301) | func TestParsePathsParam_Empty(t *testing.T) {
function TestParsePathsParam_Path_Duplicate (line 311) | func TestParsePathsParam_Path_Duplicate(t *testing.T) {
function TestParsePathsParam_Paths_Duplicate (line 317) | func TestParsePathsParam_Paths_Duplicate(t *testing.T) {
function TestParsePathsParam_PathsAndPath_Duplicate (line 323) | func TestParsePathsParam_PathsAndPath_Duplicate(t *testing.T) {
function TestParsePathsParam_Paths_DiffFilter (line 329) | func TestParsePathsParam_Paths_DiffFilter(t *testing.T) {
function TestParseDiffFilterParam (line 336) | func TestParseDiffFilterParam(t *testing.T) {
function TestParseDiffFilterParam_Empty (line 366) | func TestParseDiffFilterParam_Empty(t *testing.T) {
function TestParseDiffFilterParam_Invalid (line 373) | func TestParseDiffFilterParam_Invalid(t *testing.T) {
function TestParseLabelsParam_Missing (line 379) | func TestParseLabelsParam_Missing(t *testing.T) {
function TestParseLabelsParam_Empty (line 385) | func TestParseLabelsParam_Empty(t *testing.T) {
function TestParseLabelsParam_Label_Duplicate (line 395) | func TestParseLabelsParam_Label_Duplicate(t *testing.T) {
function TestParseLabelsParam_Labels_Duplicate (line 401) | func TestParseLabelsParam_Labels_Duplicate(t *testing.T) {
function TestParseLabelsParam_LabelsAndLabel_Duplicate (line 407) | func TestParseLabelsParam_LabelsAndLabel_Duplicate(t *testing.T) {
function valuePtr (line 414) | func valuePtr[T any](in T) *T {
function TestParseViewParam (line 418) | func TestParseViewParam(t *testing.T) {
function TestParseVersion (line 462) | func TestParseVersion(t *testing.T) {
function TestParseProductSpec (line 499) | func TestParseProductSpec(t *testing.T) {
function TestParseProductSpec_FullSHA (line 510) | func TestParseProductSpec_FullSHA(t *testing.T) {
function TestParseProductSpec_BrowserVersion (line 522) | func TestParseProductSpec_BrowserVersion(t *testing.T) {
function TestParseProductSpec_OS (line 547) | func TestParseProductSpec_OS(t *testing.T) {
function TestParseProductSpec_OSVersion (line 556) | func TestParseProductSpec_OSVersion(t *testing.T) {
function TestParseProductSpec_Labels (line 566) | func TestParseProductSpec_Labels(t *testing.T) {
function TestParseProductSpec_String (line 596) | func TestParseProductSpec_String(t *testing.T) {
function TestParseProductSpec_Plural (line 602) | func TestParseProductSpec_Plural(t *testing.T) {
function TestParseAligned (line 618) | func TestParseAligned(t *testing.T) {
function TestParseRunIDsParam_nil (line 636) | func TestParseRunIDsParam_nil(t *testing.T) {
function TestParseRunIDsParam_ok (line 643) | func TestParseRunIDsParam_ok(t *testing.T) {
function TestParseRunIDsParam_err (line 660) | func TestParseRunIDsParam_err(t *testing.T) {
function TestParseQueryFilterParams_nil (line 672) | func TestParseQueryFilterParams_nil(t *testing.T) {
function TestParseQueryFilterParams_runIDs (line 679) | func TestParseQueryFilterParams_runIDs(t *testing.T) {
function TestParseQueryFilterParams_q (line 688) | func TestParseQueryFilterParams_q(t *testing.T) {
function TestParseQueryFilterParams_aligned (line 697) | func TestParseQueryFilterParams_aligned(t *testing.T) {
function TestParseQueryFilterParams_err (line 707) | func TestParseQueryFilterParams_err(t *testing.T) {
function TestParseTestRunFilterParams (line 713) | func TestParseTestRunFilterParams(t *testing.T) {
function TestParseTestRunFilterParams_Invalid (line 730) | func TestParseTestRunFilterParams_Invalid(t *testing.T) {
function TestProductSpecMatches (line 736) | func TestProductSpecMatches(t *testing.T) {
function TestProductSpecMatches_Labels (line 760) | func TestProductSpecMatches_Labels(t *testing.T) {
function TestProductSpecMatches_Revision (line 771) | func TestProductSpecMatches_Revision(t *testing.T) {
function TestMatchesProductSpec_Labels (line 788) | func TestMatchesProductSpec_Labels(t *testing.T) {
function TestParsePageToken (line 801) | func TestParsePageToken(t *testing.T) {
function TestExtractRunIDsBodyParam_ParseError (line 820) | func TestExtractRunIDsBodyParam_ParseError(t *testing.T) {
function TestExtractRunIDsBodyParam_MissingRunIDs (line 828) | func TestExtractRunIDsBodyParam_MissingRunIDs(t *testing.T) {
function TestExtractRunIDsBodyParam_NonInt (line 836) | func TestExtractRunIDsBodyParam_NonInt(t *testing.T) {
function TestExtractRunIDsBodyParam_OK (line 851) | func TestExtractRunIDsBodyParam_OK(t *testing.T) {
function TestExtractRunIDsBodyParam_Replayable (line 862) | func TestExtractRunIDsBodyParam_Replayable(t *testing.T) {
function TestParseTestRunFilterParams_Page (line 871) | func TestParseTestRunFilterParams_Page(t *testing.T) {
FILE: shared/product_spec.go
type ProductSpec (line 16) | type ProductSpec struct
method Matches (line 23) | func (p ProductSpec) Matches(run TestRun) bool {
method MatchesProductSpec (line 29) | func (p ProductSpec) MatchesProductSpec(productSpec ProductSpec) bool {
method MatchesLabels (line 36) | func (p ProductSpec) MatchesLabels(labels mapset.Set) bool {
method MatchesProductAtRevision (line 46) | func (p ProductSpec) MatchesProductAtRevision(productAtRevision Produc...
method IsExperimental (line 66) | func (p ProductSpec) IsExperimental() bool {
method DisplayName (line 71) | func (p ProductSpec) DisplayName() string {
method String (line 144) | func (p ProductSpec) String() string {
method MarshalJSON (line 168) | func (p ProductSpec) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 173) | func (p *ProductSpec) UnmarshalJSON(data []byte) (err error) {
method UnmarshalYAML (line 183) | func (p *ProductSpec) UnmarshalYAML(unmarshal func(interface{}) error)...
method MarshalYAML (line 193) | func (p ProductSpec) MarshalYAML() (interface{}, error) {
type ProductSpecs (line 115) | type ProductSpecs
method Products (line 118) | func (p ProductSpecs) Products() []Product {
method OrDefault (line 127) | func (p ProductSpecs) OrDefault() ProductSpecs {
method Strings (line 136) | func (p ProductSpecs) Strings() []string {
method Len (line 163) | func (p ProductSpecs) Len() int { return len(p) }
method Swap (line 164) | func (p ProductSpecs) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
method Less (line 165) | func (p ProductSpecs) Less(i, j int) bool { return p[i].String() < p[j...
FILE: shared/request_caching.go
type CachingResponseWriter (line 18) | type CachingResponseWriter interface
type cachingResponseWriter (line 26) | type cachingResponseWriter struct
method Header (line 33) | func (w *cachingResponseWriter) Header() http.Header {
method Write (line 37) | func (w *cachingResponseWriter) Write(data []byte) (int, error) {
method WriteHeader (line 52) | func (w *cachingResponseWriter) WriteHeader(statusCode int) {
method WriteTo (line 57) | func (w *cachingResponseWriter) WriteTo(wtr io.Writer) (int64, error) {
method StatusCode (line 65) | func (w *cachingResponseWriter) StatusCode() int {
method Bytes (line 69) | func (w *cachingResponseWriter) Bytes() []byte {
function NewCachingResponseWriter (line 74) | func NewCachingResponseWriter(delegate http.ResponseWriter) CachingRespo...
type cachingHandler (line 81) | type cachingHandler struct
method ServeHTTP (line 90) | func (h cachingHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque...
method delegateAndCache (line 128) | func (h cachingHandler) delegateAndCache(w http.ResponseWriter, r *htt...
function NewCachingHandler (line 159) | func NewCachingHandler(ctx context.Context, delegate http.Handler, cache...
function AlwaysCachable (line 164) | func AlwaysCachable(r *http.Request) bool {
function URLAsCacheKey (line 172) | func URLAsCacheKey(r *http.Request) interface{} {
function CacheStatusOK (line 178) | func CacheStatusOK(ctx context.Context, statusCode int, payload []byte) ...
FILE: shared/request_caching_test.go
type failReader (line 22) | type failReader struct
method Read (line 30) | func (failReader) Read([]byte) (int, error) { return 0, errFailRead }
type okHandler (line 23) | type okHandler struct
method ServeHTTP (line 32) | func (okHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
function TestNoCaching404 (line 36) | func TestNoCaching404(t *testing.T) {
function TestCaching200 (line 54) | func TestCaching200(t *testing.T) {
FILE: shared/routing.go
function Router (line 17) | func Router() *mux.Router {
function AddRoute (line 28) | func AddRoute(route, name string, h http.HandlerFunc) *mux.Route {
function WrapHSTS (line 34) | func WrapHSTS(h http.HandlerFunc) http.HandlerFunc {
function WrapPermissiveCORS (line 44) | func WrapPermissiveCORS(h http.HandlerFunc, methods ...string) http.Hand...
function WrapTrustedCORS (line 57) | func WrapTrustedCORS(h http.HandlerFunc, origins []string, methods []str...
function WrapApplicationJSON (line 71) | func WrapApplicationJSON(h http.HandlerFunc) http.HandlerFunc {
FILE: shared/run_diff.go
type DiffAPI (line 31) | type DiffAPI interface
type diffAPIImpl (line 37) | type diffAPIImpl struct
method GetDiffURL (line 50) | func (d diffAPIImpl) GetDiffURL(before, after TestRun, diffFilter *Dif...
method GetMasterDiffURL (line 65) | func (d diffAPIImpl) GetMasterDiffURL(testRun TestRun, diffFilter *Dif...
method GetRunsDiff (line 349) | func (d diffAPIImpl) GetRunsDiff(before, after TestRun, filter DiffFil...
method getRunsDiffFromSearchCache (line 382) | func (d diffAPIImpl) getRunsDiffFromSearchCache(before, after TestRun,...
function NewDiffAPI (line 43) | func NewDiffAPI(ctx context.Context) DiffAPI {
type RunDiff (line 88) | type RunDiff struct
type TestSummary (line 101) | type TestSummary
method Add (line 104) | func (s TestSummary) Add(other TestSummary) {
type ResultsSummary (line 110) | type ResultsSummary
method Add (line 114) | func (s ResultsSummary) Add(k string, other TestSummary) {
type TestDiff (line 122) | type TestDiff
method IsEmpty (line 125) | func (d TestDiff) IsEmpty() bool {
method NewlyPassing (line 141) | func (d TestDiff) NewlyPassing() int {
method Regressions (line 149) | func (d TestDiff) Regressions() int {
method TotalDelta (line 157) | func (d TestDiff) TotalDelta() int {
method Add (line 165) | func (d TestDiff) Add(other TestDiff) {
method Append (line 172) | func (d TestDiff) Append(before, after TestStatus, filter *DiffFilterP...
constant newlyPassingIndex (line 135) | newlyPassingIndex = 0
constant newlyFailingIndex (line 136) | newlyFailingIndex = 1
constant totalDeltaIndex (line 137) | totalDeltaIndex = 2
function NewTestDiff (line 204) | func NewTestDiff(before, after []int, filter DiffFilterParam) TestDiff {
type ResultsDiff (line 249) | type ResultsDiff
method Add (line 253) | func (r ResultsDiff) Add(k string, diff TestDiff) {
method Regressions (line 266) | func (r ResultsDiff) Regressions() mapset.Set {
function FetchRunResultsJSONForParam (line 279) | func FetchRunResultsJSONForParam(
function FetchRunResultsJSONForSpec (line 297) | func FetchRunResultsJSONForSpec(
function FetchRunForSpec (line 309) | func FetchRunForSpec(ctx context.Context, spec ProductSpec) (*TestRun, e...
function FetchRunResultsJSON (line 326) | func FetchRunResultsJSON(ctx context.Context, run TestRun) (results Resu...
function RunDiffFromSearchResponse (line 417) | func RunDiffFromSearchResponse(aeAPI AppEngineAPI, before, after TestRun...
function GetResultsDiff (line 451) | func GetResultsDiff(
function getDiffRenames (line 505) | func getDiffRenames(aeAPI AppEngineAPI, shaBefore, shaAfter string) map[...
function anyPathMatches (line 539) | func anyPathMatches(paths mapset.Set, testPath string) bool {
function abs (line 551) | func abs(x int) int {
function max (line 558) | func max(x int, y int) int {
FILE: shared/run_diff_test.go
constant mockTestPath (line 22) | mockTestPath = "/mock/path.html"
function allDifferences (line 24) | func allDifferences() shared.DiffFilterParam {
function TestDiffResults_NoDifference (line 33) | func TestDiffResults_NoDifference(t *testing.T) {
function TestDiffResults_Difference (line 38) | func TestDiffResults_Difference(t *testing.T) {
function TestDiffResults_Added (line 52) | func TestDiffResults_Added(t *testing.T) {
function TestDiffResults_Removed (line 75) | func TestDiffResults_Removed(t *testing.T) {
function TestDiffResults_Filtered (line 89) | func TestDiffResults_Filtered(t *testing.T) {
function assertNoDeltaDifferences (line 139) | func assertNoDeltaDifferences(t *testing.T, before []int, after []int) {
function assertNoDeltaDifferencesWithFilter (line 143) | func assertNoDeltaDifferencesWithFilter(t *testing.T, before []int, afte...
function assertDelta (line 148) | func assertDelta(t *testing.T, before []int, after []int, delta []int) {
function assertDeltaWithFilter (line 152) | func assertDeltaWithFilter(t *testing.T, before []int, after []int, delt...
function getDeltaResultsMaps (line 160) | func getDeltaResultsMaps(before []int, after []int) (shared.ResultsSumma...
function TestRegressions (line 165) | func TestRegressions(t *testing.T) {
function TestRunDiffFromSearchResponse (line 191) | func TestRunDiffFromSearchResponse(t *testing.T) {
FILE: shared/secret_manager.go
type SecretManager (line 8) | type SecretManager interface
function GetUploader (line 13) | func GetUploader(m SecretManager, uploader string) (Uploader, error) {
FILE: shared/secret_manager_cloud.go
type CloudSecretManager (line 17) | type CloudSecretManager struct
method GetSecret (line 35) | func (m CloudSecretManager) GetSecret(name string) ([]byte, error) {
function NewAppEngineSecretManager (line 25) | func NewAppEngineSecretManager(ctx context.Context, projectID string) Cl...
FILE: shared/secret_manager_cloud_cloud_test.go
function TestCloudSecretManagerGetSecret (line 22) | func TestCloudSecretManagerGetSecret(t *testing.T) {
FILE: shared/sharedtest/appengine_mock.go
type MockAppEngineAPI (line 25) | type MockAppEngineAPI struct
method EXPECT (line 44) | func (m *MockAppEngineAPI) EXPECT() *MockAppEngineAPIMockRecorder {
method Context (line 49) | func (m *MockAppEngineAPI) Context() context.Context {
method GetGitHubClient (line 63) | func (m *MockAppEngineAPI) GetGitHubClient() (*github.Client, error) {
method GetHTTPClient (line 78) | func (m *MockAppEngineAPI) GetHTTPClient() *http.Client {
method GetHTTPClientWithTimeout (line 92) | func (m *MockAppEngineAPI) GetHTTPClientWithTimeout(arg0 time.Duration...
method GetHostname (line 106) | func (m *MockAppEngineAPI) GetHostname() string {
method GetResultsURL (line 120) | func (m *MockAppEngineAPI) GetResultsURL(filter shared.TestRunFilter) ...
method GetResultsUploadURL (line 134) | func (m *MockAppEngineAPI) GetResultsUploadURL() *url.URL {
method GetRunsURL (line 148) | func (m *MockAppEngineAPI) GetRunsURL(filter shared.TestRunFilter) *ur...
method GetServiceHostname (line 162) | func (m *MockAppEngineAPI) GetServiceHostname(service string) string {
method GetUploader (line 176) | func (m *MockAppEngineAPI) GetUploader(uploader string) (shared.Upload...
method GetVersion (line 191) | func (m *MockAppEngineAPI) GetVersion() string {
method GetVersionedHostname (line 205) | func (m *MockAppEngineAPI) GetVersionedHostname() string {
method IsFeatureEnabled (line 219) | func (m *MockAppEngineAPI) IsFeatureEnabled(featureName string) bool {
method ScheduleTask (line 233) | func (m *MockAppEngineAPI) ScheduleTask(queueName, taskName, target st...
type MockAppEngineAPIMockRecorder (line 32) | type MockAppEngineAPIMockRecorder struct
method Context (line 57) | func (mr *MockAppEngineAPIMockRecorder) Context() *gomock.Call {
method GetGitHubClient (line 72) | func (mr *MockAppEngineAPIMockRecorder) GetGitHubClient() *gomock.Call {
method GetHTTPClient (line 86) | func (mr *MockAppEngineAPIMockRecorder) GetHTTPClient() *gomock.Call {
method GetHTTPClientWithTimeout (line 100) | func (mr *MockAppEngineAPIMockRecorder) GetHTTPClientWithTimeout(arg0 ...
method GetHostname (line 114) | func (mr *MockAppEngineAPIMockRecorder) GetHostname() *gomock.Call {
method GetResultsURL (line 128) | func (mr *MockAppEngineAPIMockRecorder) GetResultsURL(filter any) *gom...
method GetResultsUploadURL (line 142) | func (mr *MockAppEngineAPIMockRecorder) GetResultsUploadURL() *gomock....
method GetRunsURL (line 156) | func (mr *MockAppEngineAPIMockRecorder) GetRunsURL(filter any) *gomock...
method GetServiceHostname (line 170) | func (mr *MockAppEngineAPIMockRecorder) GetServiceHostname(service any...
method GetUploader (line 185) | func (mr *MockAppEngineAPIMockRecorder) GetUploader(uploader any) *gom...
method GetVersion (line 199) | func (mr *MockAppEngineAPIMockRecorder) GetVersion() *gomock.Call {
method GetVersionedHostname (line 213) | func (mr *MockAppEngineAPIMockRecorder) GetVersionedHostname() *gomock...
method IsFeatureEnabled (line 227) | func (mr *MockAppEngineAPIMockRecorder) IsFeatureEnabled(featureName a...
method ScheduleTask (line 242) | func (mr *MockAppEngineAPIMockRecorder) ScheduleTask(queueName, taskNa...
function NewMockAppEngineAPI (line 37) | func NewMockAppEngineAPI(ctrl *gomock.Controller) *MockAppEngineAPI {
FILE: shared/sharedtest/cache_mock.go
type MockCachedStore (line 20) | type MockCachedStore struct
method EXPECT (line 39) | func (m *MockCachedStore) EXPECT() *MockCachedStoreMockRecorder {
method Get (line 44) | func (m *MockCachedStore) Get(cacheID, storeID, value any) error {
type MockCachedStoreMockRecorder (line 27) | type MockCachedStoreMockRecorder struct
method Get (line 52) | func (mr *MockCachedStoreMockRecorder) Get(cacheID, storeID, value any...
function NewMockCachedStore (line 32) | func NewMockCachedStore(ctrl *gomock.Controller) *MockCachedStore {
type MockObjectCache (line 58) | type MockObjectCache struct
method EXPECT (line 77) | func (m *MockObjectCache) EXPECT() *MockObjectCacheMockRecorder {
method Get (line 82) | func (m *MockObjectCache) Get(id, value any) error {
method Put (line 96) | func (m *MockObjectCache) Put(id, value any) error {
type MockObjectCacheMockRecorder (line 65) | type MockObjectCacheMockRecorder struct
method Get (line 90) | func (mr *MockObjectCacheMockRecorder) Get(id, value any) *gomock.Call {
method Put (line 104) | func (mr *MockObjectCacheMockRecorder) Put(id, value any) *gomock.Call {
function NewMockObjectCache (line 70) | func NewMockObjectCache(ctrl *gomock.Controller) *MockObjectCache {
type MockObjectStore (line 110) | type MockObjectStore struct
method EXPECT (line 129) | func (m *MockObjectStore) EXPECT() *MockObjectStoreMockRecorder {
method Get (line 134) | func (m *MockObjectStore) Get(id, value any) error {
type MockObjectStoreMockRecorder (line 117) | type MockObjectStoreMockRecorder struct
method Get (line 142) | func (mr *MockObjectStoreMockRecorder) Get(id, value any) *gomock.Call {
function NewMockObjectStore (line 122) | func NewMockObjectStore(ctrl *gomock.Controller) *MockObjectStore {
type MockReadWritable (line 148) | type MockReadWritable struct
method EXPECT (line 167) | func (m *MockReadWritable) EXPECT() *MockReadWritableMockRecorder {
method NewReadCloser (line 172) | func (m *MockReadWritable) NewReadCloser(arg0 any) (io.ReadCloser, err...
method NewWriteCloser (line 187) | func (m *MockReadWritable) NewWriteCloser(arg0 any) (io.WriteCloser, e...
type MockReadWritableMockRecorder (line 155) | type MockReadWritableMockRecorder struct
method NewReadCloser (line 181) | func (mr *MockReadWritableMockRecorder) NewReadCloser(arg0 any) *gomoc...
method NewWriteCloser (line 196) | func (mr *MockReadWritableMockRecorder) NewWriteCloser(arg0 any) *gomo...
function NewMockReadWritable (line 160) | func NewMockReadWritable(ctrl *gomock.Controller) *MockReadWritable {
type MockReadable (line 202) | type MockReadable struct
method EXPECT (line 221) | func (m *MockReadable) EXPECT() *MockReadableMockRecorder {
method NewReadCloser (line 226) | func (m *MockReadable) NewReadCloser(arg0 any) (io.ReadCloser, error) {
type MockReadableMockRecorder (line 209) | type MockReadableMockRecorder struct
method NewReadCloser (line 235) | func (mr *MockReadableMockRecorder) NewReadCloser(arg0 any) *gomock.Ca...
function NewMockReadable (line 214) | func NewMockReadable(ctrl *gomock.Controller) *MockReadable {
type MockRedisSet (line 241) | type MockRedisSet struct
method EXPECT (line 260) | func (m *MockRedisSet) EXPECT() *MockRedisSetMockRecorder {
method Add (line 265) | func (m *MockRedisSet) Add(key, value string) error {
method GetAll (line 279) | func (m *MockRedisSet) GetAll(key string) ([]string, error) {
method Remove (line 294) | func (m *MockRedisSet) Remove(key, value string) error {
type MockRedisSetMockRecorder (line 248) | type MockRedisSetMockRecorder struct
method Add (line 273) | func (mr *MockRedisSetMockRecorder) Add(key, value any) *gomock.Call {
method GetAll (line 288) | func (mr *MockRedisSetMockRecorder) GetAll(key any) *gomock.Call {
method Remove (line 302) | func (mr *MockRedisSetMockRecorder) Remove(key, value any) *gomock.Call {
function NewMockRedisSet (line 253) | func NewMockRedisSet(ctrl *gomock.Controller) *MockRedisSet {
FILE: shared/sharedtest/datastore_mock.go
type MockDatastore (line 21) | type MockDatastore struct
method EXPECT (line 40) | func (m *MockDatastore) EXPECT() *MockDatastoreMockRecorder {
method Context (line 45) | func (m *MockDatastore) Context() context.Context {
method Done (line 59) | func (m *MockDatastore) Done() any {
method Get (line 73) | func (m *MockDatastore) Get(key shared.Key, dst any) error {
method GetAll (line 87) | func (m *MockDatastore) GetAll(q shared.Query, dst any) ([]shared.Key,...
method GetMulti (line 102) | func (m *MockDatastore) GetMulti(keys []shared.Key, dst any) error {
method Insert (line 116) | func (m *MockDatastore) Insert(key shared.Key, src any) error {
method NewIDKey (line 130) | func (m *MockDatastore) NewIDKey(typeName string, id int64) shared.Key {
method NewIncompleteKey (line 144) | func (m *MockDatastore) NewIncompleteKey(typeName string) shared.Key {
method NewNameKey (line 158) | func (m *MockDatastore) NewNameKey(typeName, name string) shared.Key {
method NewQuery (line 172) | func (m *MockDatastore) NewQuery(typeName string) shared.Query {
method Put (line 186) | func (m *MockDatastore) Put(key shared.Key, src any) (shared.Key, erro...
method PutMulti (line 201) | func (m *MockDatastore) PutMulti(keys []shared.Key, src any) ([]shared...
method ReserveID (line 216) | func (m *MockDatastore) ReserveID(typeName string) (shared.Key, error) {
method TestRunQuery (line 231) | func (m *MockDatastore) TestRunQuery() shared.TestRunQuery {
method Update (line 245) | func (m *MockDatastore) Update(key shared.Key, dst any, mutator func(a...
type MockDatastoreMockRecorder (line 28) | type MockDatastoreMockRecorder struct
method Context (line 53) | func (mr *MockDatastoreMockRecorder) Context() *gomock.Call {
method Done (line 67) | func (mr *MockDatastoreMockRecorder) Done() *gomock.Call {
method Get (line 81) | func (mr *MockDatastoreMockRecorder) Get(key, dst any) *gomock.Call {
method GetAll (line 96) | func (mr *MockDatastoreMockRecorder) GetAll(q, dst any) *gomock.Call {
method GetMulti (line 110) | func (mr *MockDatastoreMockRecorder) GetMulti(keys, dst any) *gomock.C...
method Insert (line 124) | func (mr *MockDatastoreMockRecorder) Insert(key, src any) *gomock.Call {
method NewIDKey (line 138) | func (mr *MockDatastoreMockRecorder) NewIDKey(typeName, id any) *gomoc...
method NewIncompleteKey (line 152) | func (mr *MockDatastoreMockRecorder) NewIncompleteKey(typeName any) *g...
method NewNameKey (line 166) | func (mr *MockDatastoreMockRecorder) NewNameKey(typeName, name any) *g...
method NewQuery (line 180) | func (mr *MockDatastoreMockRecorder) NewQuery(typeName any) *gomock.Ca...
method Put (line 195) | func (mr *MockDatastoreMockRecorder) Put(key, src any) *gomock.Call {
method PutMulti (line 210) | func (mr *MockDatastoreMockRecorder) PutMulti(keys, src any) *gomock.C...
method ReserveID (line 225) | func (mr *MockDatastoreMockRecorder) ReserveID(typeName any) *gomock.C...
method TestRunQuery (line 239) | func (mr *MockDatastoreMockRecorder) TestRunQuery() *gomock.Call {
method Update (line 253) | func (mr *MockDatastoreMockRecorder) Update(key, dst, mutator any) *go...
function NewMockDatastore (line 33) | func NewMockDatastore(ctrl *gomock.Controller) *MockDatastore {
FILE: shared/sharedtest/fetch_bsf_mock.go
type MockFetchBSF (line 19) | type MockFetchBSF struct
method EXPECT (line 38) | func (m *MockFetchBSF) EXPECT() *MockFetchBSFMockRecorder {
method Fetch (line 43) | func (m *MockFetchBSF) Fetch(isExperimental bool) ([][]string, error) {
type MockFetchBSFMockRecorder (line 26) | type MockFetchBSFMockRecorder struct
method Fetch (line 52) | func (mr *MockFetchBSFMockRecorder) Fetch(isExperimental any) *gomock....
function NewMockFetchBSF (line 31) | func NewMockFetchBSF(ctrl *gomock.Controller) *MockFetchBSF {
FILE: shared/sharedtest/github_oauth_mock.go
type MockGitHubOAuth (line 23) | type MockGitHubOAuth struct
method EXPECT (line 42) | func (m *MockGitHubOAuth) EXPECT() *MockGitHubOAuthMockRecorder {
method Context (line 47) | func (m *MockGitHubOAuth) Context() context.Context {
method Datastore (line 61) | func (m *MockGitHubOAuth) Datastore() shared.Datastore {
method GetAccessToken (line 75) | func (m *MockGitHubOAuth) GetAccessToken() string {
method GetAuthCodeURL (line 89) | func (m *MockGitHubOAuth) GetAuthCodeURL(state string, opts ...oauth2....
method GetUser (line 108) | func (m *MockGitHubOAuth) GetUser(client *github.Client) (*github.User...
method NewClient (line 123) | func (m *MockGitHubOAuth) NewClient(oauthCode string) (*github.Client,...
method SetRedirectURL (line 138) | func (m *MockGitHubOAuth) SetRedirectURL(url string) {
type MockGitHubOAuthMockRecorder (line 30) | type MockGitHubOAuthMockRecorder struct
method Context (line 55) | func (mr *MockGitHubOAuthMockRecorder) Context() *gomock.Call {
method Datastore (line 69) | func (mr *MockGitHubOAuthMockRecorder) Datastore() *gomock.Call {
method GetAccessToken (line 83) | func (mr *MockGitHubOAuthMockRecorder) GetAccessToken() *gomock.Call {
method GetAuthCodeURL (line 101) | func (mr *MockGitHubOAuthMockRecorder) GetAuthCodeURL(state any, opts ...
method GetUser (line 117) | func (mr *MockGitHubOAuthMockRecorder) GetUser(client any) *gomock.Call {
method NewClient (line 132) | func (mr *MockGitHubOAuthMockRecorder) NewClient(oauthCode any) *gomoc...
method SetRedirectURL (line 144) | func (mr *MockGitHubOAuthMockRecorder) SetRedirectURL(url any) *gomock...
function NewMockGitHubOAuth (line 35) | func NewMockGitHubOAuth(ctrl *gomock.Controller) *MockGitHubOAuth {
type MockGitHubAccessControl (line 150) | type MockGitHubAccessControl struct
method EXPECT (line 169) | func (m *MockGitHubAccessControl) EXPECT() *MockGitHubAccessControlMoc...
method IsValidAdmin (line 174) | func (m *MockGitHubAccessControl) IsValidAdmin() (bool, error) {
method IsValidWPTMember (line 189) | func (m *MockGitHubAccessControl) IsValidWPTMember() (bool, error) {
type MockGitHubAccessControlMockRecorder (line 157) | type MockGitHubAccessControlMockRecorder struct
method IsValidAdmin (line 183) | func (mr *MockGitHubAccessControlMockRecorder) IsValidAdmin() *gomock....
method IsValidWPTMember (line 198) | func (mr *MockGitHubAccessControlMockRecorder) IsValidWPTMember() *gom...
function NewMockGitHubAccessControl (line 162) | func NewMockGitHubAccessControl(ctrl *gomock.Controller) *MockGitHubAcce...
FILE: shared/sharedtest/io.go
type MockWriteCloser (line 17) | type MockWriteCloser struct
method Write (line 23) | func (mwc *MockWriteCloser) Write(p []byte) (n int, err error) {
method Close (line 29) | func (mwc *MockWriteCloser) Close() error {
method IsClosed (line 35) | func (mwc *MockWriteCloser) IsClosed() bool {
method Bytes (line 40) | func (mwc *MockWriteCloser) Bytes() []byte {
function NewMockWriteCloser (line 45) | func NewMockWriteCloser(t *testing.T) *MockWriteCloser {
type MockReadCloser (line 54) | type MockReadCloser struct
method Read (line 60) | func (mrc *MockReadCloser) Read(p []byte) (n int, err error) {
method Close (line 66) | func (mrc *MockReadCloser) Close() error {
method IsClosed (line 81) | func (mrc *MockReadCloser) IsClosed() bool {
function NewMockReadCloser (line 72) | func NewMockReadCloser(t *testing.T, data []byte) *MockReadCloser {
FILE: shared/sharedtest/metadata_util_mock.go
type MockMetadataFetcher (line 19) | type MockMetadataFetcher struct
method EXPECT (line 38) | func (m *MockMetadataFetcher) EXPECT() *MockMetadataFetcherMockRecorder {
method Fetch (line 43) | func (m *MockMetadataFetcher) Fetch() (*string, map[string][]byte, err...
type MockMetadataFetcherMockRecorder (line 26) | type MockMetadataFetcherMockRecorder struct
method Fetch (line 53) | func (mr *MockMetadataFetcherMockRecorder) Fetch() *gomock.Call {
function NewMockMetadataFetcher (line 31) | func NewMockMetadataFetcher(ctrl *gomock.Controller) *MockMetadataFetcher {
FILE: shared/sharedtest/run_diff_mock.go
type MockDiffAPI (line 22) | type MockDiffAPI struct
method EXPECT (line 41) | func (m *MockDiffAPI) EXPECT() *MockDiffAPIMockRecorder {
method GetDiffURL (line 46) | func (m *MockDiffAPI) GetDiffURL(before, after shared.TestRun, diffFil...
method GetMasterDiffURL (line 60) | func (m *MockDiffAPI) GetMasterDiffURL(testRun shared.TestRun, diffFil...
method GetRunsDiff (line 74) | func (m *MockDiffAPI) GetRunsDiff(before, after shared.TestRun, filter...
type MockDiffAPIMockRecorder (line 29) | type MockDiffAPIMockRecorder struct
method GetDiffURL (line 54) | func (mr *MockDiffAPIMockRecorder) GetDiffURL(before, after, diffFilte...
method GetMasterDiffURL (line 68) | func (mr *MockDiffAPIMockRecorder) GetMasterDiffURL(testRun, diffFilte...
method GetRunsDiff (line 83) | func (mr *MockDiffAPIMockRecorder) GetRunsDiff(before, after, filter, ...
function NewMockDiffAPI (line 34) | func NewMockDiffAPI(ctrl *gomock.Controller) *MockDiffAPI {
FILE: shared/sharedtest/test_run_query_mock.go
type MockTestRunQuery (line 22) | type MockTestRunQuery struct
method EXPECT (line 41) | func (m *MockTestRunQuery) EXPECT() *MockTestRunQueryMockRecorder {
method GetAlignedRunSHAs (line 46) | func (m *MockTestRunQuery) GetAlignedRunSHAs(products shared.ProductSp...
method LoadTestRunKeys (line 62) | func (m *MockTestRunQuery) LoadTestRunKeys(products []shared.ProductSp...
method LoadTestRuns (line 77) | func (m *MockTestRunQuery) LoadTestRuns(products []shared.ProductSpec,...
method LoadTestRunsByKeys (line 92) | func (m *MockTestRunQuery) LoadTestRunsByKeys(arg0 shared.KeysByProduc...
type MockTestRunQueryMockRecorder (line 29) | type MockTestRunQueryMockRecorder struct
method GetAlignedRunSHAs (line 56) | func (mr *MockTestRunQueryMockRecorder) GetAlignedRunSHAs(products, la...
method LoadTestRunKeys (line 71) | func (mr *MockTestRunQueryMockRecorder) LoadTestRunKeys(products, labe...
method LoadTestRuns (line 86) | func (mr *MockTestRunQueryMockRecorder) LoadTestRuns(products, labels,...
method LoadTestRunsByKeys (line 101) | func (mr *MockTestRunQueryMockRecorder) LoadTestRunsByKeys(arg0 any) *...
function NewMockTestRunQuery (line 34) | func NewMockTestRunQuery(ctrl *gomock.Controller) *MockTestRunQuery {
FILE: shared/sharedtest/triage_metadata_mock.go
type MockTriageMetadata (line 20) | type MockTriageMetadata struct
method EXPECT (line 39) | func (m *MockTriageMetadata) EXPECT() *MockTriageMetadataMockRecorder {
method Triage (line 44) | func (m *MockTriageMetadata) Triage(metadata shared.MetadataResults) (...
type MockTriageMetadataMockRecorder (line 27) | type MockTriageMetadataMockRecorder struct
method Triage (line 53) | func (mr *MockTriageMetadataMockRecorder) Triage(metadata any) *gomock...
function NewMockTriageMetadata (line 32) | func NewMockTriageMetadata(ctrl *gomock.Controller) *MockTriageMetadata {
FILE: shared/sharedtest/util.go
type Instance (line 26) | type Instance interface
type aeInstance (line 33) | type aeInstance struct
method Close (line 40) | func (i aeInstance) Close() error {
method NewRequest (line 45) | func (i aeInstance) NewRequest(method, urlStr string, body io.Reader) ...
method start (line 50) | func (i *aeInstance) start(stronglyConsistentDatastore bool) error {
method stop (line 111) | func (i aeInstance) stop() error {
function NewAEInstance (line 152) | func NewAEInstance(stronglyConsistentDatastore bool) (Instance, error) {
function NewAEContext (line 167) | func NewAEContext(stronglyConsistentDatastore bool) (context.Context, fu...
function NewTestContext (line 184) | func NewTestContext() context.Context {
function ctxWithNilLogger (line 188) | func ctxWithNilLogger(ctx context.Context) context.Context {
type sameStringSpec (line 192) | type sameStringSpec struct
method Matches (line 200) | func (s sameStringSpec) Matches(x interface{}) bool {
method String (line 208) | func (s sameStringSpec) String() string {
type stringifiable (line 196) | type stringifiable interface
function SameProductSpec (line 213) | func SameProductSpec(spec string) gomock.Matcher {
function SameDiffFilter (line 220) | func SameDiffFilter(filter string) gomock.Matcher {
type sameKeys (line 226) | type sameKeys struct
method Matches (line 230) | func (s sameKeys) Matches(x interface{}) bool {
method String (line 249) | func (s sameKeys) String() string {
function SameKeys (line 254) | func SameKeys(ids []int64) gomock.Matcher {
function MultiRuns (line 260) | func MultiRuns(runs shared.TestRuns) func(keys []shared.Key, dst interfa...
type MockKey (line 277) | type MockKey struct
method IntID (line 284) | func (m MockKey) IntID() int64 {
method StringID (line 289) | func (m MockKey) StringID() string {
method Kind (line 294) | func (m MockKey) Kind() string {
FILE: shared/statuses.go
type TestStatus (line 14) | type TestStatus
method IsPassOrOK (line 140) | func (s TestStatus) IsPassOrOK() bool {
method IsHarnessStatus (line 146) | func (s TestStatus) IsHarnessStatus() bool {
method IsPass (line 151) | func (s TestStatus) IsPass() bool {
method String (line 166) | func (s TestStatus) String() string {
method UnmarshalJSON (line 175) | func (s *TestStatus) UnmarshalJSON(b []byte) error {
method UnmarshalYAML (line 191) | func (s *TestStatus) UnmarshalYAML(unmarshal func(interface{}) error) ...
method MarshalYAML (line 206) | func (s *TestStatus) MarshalYAML() (interface{}, error) {
constant TestStatusUnknown (line 19) | TestStatusUnknown TestStatus = 0
constant TestStatusPass (line 22) | TestStatusPass TestStatus = 1
constant TestStatusOK (line 25) | TestStatusOK TestStatus = 2
constant TestStatusError (line 29) | TestStatusError TestStatus = 3
constant TestStatusTimeout (line 32) | TestStatusTimeout TestStatus = 4
constant TestStatusNotRun (line 35) | TestStatusNotRun TestStatus = 5
constant TestStatusFail (line 38) | TestStatusFail TestStatus = 6
constant TestStatusCrash (line 41) | TestStatusCrash TestStatus = 7
constant TestStatusSkip (line 44) | TestStatusSkip TestStatus = 8
constant TestStatusAssert (line 48) | TestStatusAssert TestStatus = 9
constant TestStatusPreconditionFailed (line 52) | TestStatusPreconditionFailed TestStatus = 10
constant TestStatusNameUnknown (line 56) | TestStatusNameUnknown string = "UNKNOWN"
constant TestStatusNamePass (line 60) | TestStatusNamePass string = "PASS"
constant TestStatusNameOK (line 65) | TestStatusNameOK string = "OK"
constant TestStatusNameError (line 69) | TestStatusNameError string = "ERROR"
constant TestStatusNameTimeout (line 73) | TestStatusNameTimeout string = "TIMEOUT"
constant TestStatusNameNotRun (line 77) | TestStatusNameNotRun string = "NOTRUN"
constant TestStatusNameFail (line 81) | TestStatusNameFail string = "FAIL"
constant TestStatusNameCrash (line 85) | TestStatusNameCrash string = "CRASH"
constant TestStatusNameSkip (line 89) | TestStatusNameSkip string = "SKIP"
constant TestStatusNameAssert (line 94) | TestStatusNameAssert string = "ASSERT"
constant TestStatusNamePreconditionFailed (line 99) | TestStatusNamePreconditionFailed string = "PRECONDITION_FAILED"
constant TestStatusDefault (line 103) | TestStatusDefault TestStatus = TestStatusUnknown
constant TestStatusNameDefault (line 107) | TestStatusNameDefault string = TestStatusNameUnknown
function TestStatusValueFromString (line 157) | func TestStatusValueFromString(str string) TestStatus {
FILE: shared/statuses_test.go
function TestMaps (line 15) | func TestMaps(t *testing.T) {
function TestDefaults (line 28) | func TestDefaults(t *testing.T) {
function TestPass (line 33) | func TestPass(t *testing.T) {
function TestDefaultsFromAPI (line 38) | func TestDefaultsFromAPI(t *testing.T) {
function TestPreconditionFailed (line 43) | func TestPreconditionFailed(t *testing.T) {
FILE: shared/tag_test.go
function init (line 5) | func init() {
FILE: shared/test_run_filter.go
type SHAs (line 19) | type SHAs
method EmptyOrLatest (line 23) | func (s SHAs) EmptyOrLatest() bool {
method FirstOrLatest (line 28) | func (s SHAs) FirstOrLatest() string {
method ShortSHAs (line 36) | func (s SHAs) ShortSHAs() []string {
type TestRunFilter (line 46) | type TestRunFilter struct
method MarshalJSON (line 65) | func (filter TestRunFilter) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 74) | func (filter *TestRunFilter) UnmarshalJSON(data []byte) error {
method IsDefaultQuery (line 86) | func (filter TestRunFilter) IsDefaultQuery() bool {
method OrDefault (line 98) | func (filter TestRunFilter) OrDefault() TestRunFilter {
method OrAlignedStableRuns (line 108) | func (filter TestRunFilter) OrAlignedStableRuns() TestRunFilter {
method OrExperimentalRuns (line 120) | func (filter TestRunFilter) OrExperimentalRuns() TestRunFilter {
method MasterOnly (line 130) | func (filter TestRunFilter) MasterOnly() TestRunFilter {
method IsDefaultProducts (line 140) | func (filter TestRunFilter) IsDefaultProducts() bool {
method GetProductsOrDefault (line 158) | func (filter TestRunFilter) GetProductsOrDefault() (products ProductSp...
method ToQuery (line 163) | func (filter TestRunFilter) ToQuery() (q url.Values) {
method NextPage (line 205) | func (filter TestRunFilter) NextPage(loadedRuns TestRunsByProduct) *Te...
method Token (line 242) | func (filter TestRunFilter) Token() (string, error) {
type testRunFilterNoCustomMarshalling (line 58) | type testRunFilterNoCustomMarshalling
type marshallableTestRunFilter (line 59) | type marshallableTestRunFilter struct
FILE: shared/test_run_filter_test.go
function TestTestRunFilter_NextPage_MaxCount (line 18) | func TestTestRunFilter_NextPage_MaxCount(t *testing.T) {
function TestTestRunFilter_NextPage_From (line 36) | func TestTestRunFilter_NextPage_From(t *testing.T) {
function TestTestRunFilter_NextPage_FromAndMax (line 60) | func TestTestRunFilter_NextPage_FromAndMax(t *testing.T) {
function TestTestRunFilter_JSONRoundTrip (line 101) | func TestTestRunFilter_JSONRoundTrip(t *testing.T) {
FILE: shared/test_run_query.go
type TestRunQuery (line 22) | type TestRunQuery interface
type testRunQueryImpl (line 63) | type testRunQueryImpl struct
method LoadTestRuns (line 72) | func (t testRunQueryImpl) LoadTestRuns(
method LoadTestRunsByKeys (line 91) | func (t testRunQueryImpl) LoadTestRunsByKeys(keysByProduct KeysByProdu...
method LoadTestRunKeys (line 111) | func (t testRunQueryImpl) LoadTestRunKeys(
method GetAlignedRunSHAs (line 256) | func (t testRunQueryImpl) GetAlignedRunSHAs(
function NewTestRunQuery (line 68) | func NewTestRunQuery(store Datastore) TestRunQuery {
function clientSideFilter (line 208) | func clientSideFilter(
function merge (line 335) | func merge(s1, s2 mapset.Set) mapset.Set {
function contains (line 346) | func contains(s []string, x string) bool {
function loadIDsForRevision (line 356) | func loadIDsForRevision(store Datastore, query Query, sha string) (resul...
function loadIDsForBrowserVersion (line 384) | func loadIDsForBrowserVersion(store Datastore, query Query, version stri...
function VersionPrefix (line 407) | func VersionPrefix(query Query, fieldName, versionPrefix string, desc bo...
function getTestRunRedisKey (line 419) | func getTestRunRedisKey(id int64) string {
FILE: shared/test_run_query_medium_test.go
function TestLoadTestRuns (line 18) | func TestLoadTestRuns(t *testing.T) {
function TestLoadTestRunsBySHAs (line 47) | func TestLoadTestRunsBySHAs(t *testing.T) {
function TestLoadTestRuns_Experimental_Only (line 89) | func TestLoadTestRuns_Experimental_Only(t *testing.T) {
function TestLoadTestRuns_LabelinProductSpec (line 175) | func TestLoadTestRuns_LabelinProductSpec(t *testing.T) {
function TestLoadTestRuns_SHAinProductSpec (line 213) | func TestLoadTestRuns_SHAinProductSpec(t *testing.T) {
function TestLoadTestRuns_Ordering (line 277) | func TestLoadTestRuns_Ordering(t *testing.T) {
function TestLoadTestRuns_From (line 321) | func TestLoadTestRuns_From(t *testing.T) {
function TestLoadTestRuns_To (line 364) | func TestLoadTestRuns_To(t *testing.T) {
function TestGetAlignedRunSHAs (line 406) | func TestGetAlignedRunSHAs(t *testing.T) {
FILE: shared/triage_metadata.go
type TriageMetadata (line 22) | type TriageMetadata interface
type triageMetadata (line 27) | type triageMetadata struct
method getCommitBranchRef (line 88) | func (tm triageMetadata) getCommitBranchRef(sha *string) (ref *github....
method getTree (line 100) | func (tm triageMetadata) getTree(ref *github.Reference, triagedMetadat...
method pushCommit (line 114) | func (tm triageMetadata) pushCommit(ref *github.Reference, tree *githu...
method createPR (line 144) | func (tm triageMetadata) createPR() (*github.PullRequest, error) {
method addPRLabels (line 162) | func (tm triageMetadata) addPRLabels(pr *github.PullRequest) (err erro...
method createWPTMetadataPR (line 172) | func (tm triageMetadata) createWPTMetadataPR(sha *string, triagedMetad...
method Triage (line 291) | func (tm triageMetadata) Triage(metadata MetadataResults) (string, err...
type wptmetadataGitHubInfo (line 39) | type wptmetadataGitHubInfo struct
function init (line 52) | func init() {
function getNewCommitBranchName (line 56) | func getNewCommitBranchName(ctx context.Context, client *github.Client, ...
function getWptmetadataGitHubInfo (line 72) | func getWptmetadataGitHubInfo(ctx context.Context, client *github.Client...
function addToFiles (line 211) | func addToFiles(metadata MetadataResults, filesMap map[string]Metadata, ...
function appendTestName (line 259) | func appendTestName(test string, metadata MetadataResults) {
function containsInterop (line 275) | func containsInterop(metadata MetadataResults) bool {
function generateRandomInt (line 287) | func generateRandomInt() string {
function NewTriageMetadata (line 304) | func NewTriageMetadata(ctx context.Context, githubClient *github.Client,...
FILE: shared/triage_metadata_test.go
function TestAppendTestName (line 18) | func TestAppendTestName(t *testing.T) {
function TestAppendTestName_EmptyResults (line 68) | func TestAppendTestName_EmptyResults(t *testing.T) {
function TestAddToFiles_AddNewFile (line 96) | func TestAddToFiles_AddNewFile(t *testing.T) {
function TestAddToFiles_AddNewMetadataResult (line 146) | func TestAddToFiles_AddNewMetadataResult(t *testing.T) {
function TestAddToFiles_AddNewMetadataLink (line 200) | func TestAddToFiles_AddNewMetadataLink(t *testing.T) {
function TestAddToFiles_AddNewMetadataLink_Label (line 254) | func TestAddToFiles_AddNewMetadataLink_Label(t *testing.T) {
function TestAddToFiles_AddNewMetadataResults_Label (line 304) | func TestAddToFiles_AddNewMetadataResults_Label(t *testing.T) {
function TestAddToFiles_AddNewMetadataLink_Asterisk (line 342) | func TestAddToFiles_AddNewMetadataLink_Asterisk(t *testing.T) {
function TestNewTriageMetadata_email_fallback (line 396) | func TestNewTriageMetadata_email_fallback(t *testing.T) {
function TestContainsInterop_True (line 410) | func TestContainsInterop_True(t *testing.T) {
function TestContainsInterop_NotInteropLabel (line 425) | func TestContainsInterop_NotInteropLabel(t *testing.T) {
function TestContainsInterop_False (line 440) | func TestContainsInterop_False(t *testing.T) {
FILE: shared/util.go
constant ExperimentalLabel (line 19) | ExperimentalLabel = "experimental"
constant LatestSHA (line 22) | LatestSHA = "latest"
constant StableLabel (line 25) | StableLabel = "stable"
constant BetaLabel (line 28) | BetaLabel = "beta"
constant MasterLabel (line 32) | MasterLabel = "master"
constant PRBaseLabel (line 36) | PRBaseLabel = "pr_base"
constant PRHeadLabel (line 40) | PRHeadLabel = "pr_head"
constant UserLabelPrefix (line 44) | UserLabelPrefix = "user:"
constant WPTRepoOwner (line 47) | WPTRepoOwner = "web-platform-tests"
constant WPTRepoName (line 50) | WPTRepoName = "wpt"
function GetUserLabel (line 53) | func GetUserLabel(username string) string {
function ProductChannelToLabel (line 59) | func ProductChannelToLabel(channel string) string {
function GetDefaultProducts (line 72) | func GetDefaultProducts() ProductSpecs {
function ToStringSlice (line 83) | func ToStringSlice(set mapset.Set) []string {
function IsLatest (line 97) | func IsLatest(sha string) bool {
function NewSetFromStringSlice (line 102) | func NewSetFromStringSlice(items []string) mapset.Set {
function StringSliceContains (line 114) | func StringSliceContains(ss []string, s string) bool {
function MapStringKeys (line 124) | func MapStringKeys(m interface{}) ([]string, error) {
function GetResultsURL (line 142) | func GetResultsURL(run TestRun, testFile string) (resultsURL string) {
function CropString (line 157) | func CropString(s string, i int) string {
function GetSharedPath (line 165) | func GetSharedPath(paths ...string) string {
function IsValidURL (line 187) | func IsValidURL(s string) bool {
FILE: shared/util_test.go
constant shortSHA (line 15) | shortSHA = "abcdef0123"
constant resultsURLBase (line 16) | resultsURLBase = "https://storage.googleapis.com/wptd/" + shortSHA + "/"
constant product (line 17) | product = "chrome-63.0-linux"
constant resultsURL (line 18) | resultsURL = resultsURLBase + "/" + product + "-summary_v2.json.gz"
function TestMapStringKeys (line 20) | func TestMapStringKeys(t *testing.T) {
function TestMapStringKeys_NotAMap (line 36) | func TestMapStringKeys_NotAMap(t *testin
Copy disabled (too large)
Download .json
Condensed preview — 439 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (16,761K chars).
[
{
"path": ".github/actions/make-in-docker/action.yml",
"chars": 295,
"preview": "name: Run make in Docker\ndescription: Run a make target inside a container created from Dockerfile\ninputs:\n target:\n "
},
{
"path": ".github/dependabot.yml",
"chars": 3081,
"preview": "version: 2\nupdates:\n- package-ecosystem: \"pip\"\n directory: \"/results-processor\"\n schedule:\n interval: \"weekly\"\n- pa"
},
{
"path": ".github/workflows/ci.yml",
"chars": 5448,
"preview": "name: Continuous Integration\non:\n push:\n branches:\n - main\n pull_request:\njobs:\n lint:\n runs-on: ubuntu-la"
},
{
"path": ".github/workflows/codeql.yml",
"chars": 2791,
"preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
},
{
"path": ".github/workflows/deploy.yml",
"chars": 2818,
"preview": "name: Deploy\non:\n push:\n branches:\n - main\n pull_request:\njobs:\n deploy-staging:\n # Forks and dependabot c"
},
{
"path": ".github/workflows/docker-update.yml",
"chars": 1239,
"preview": "name: Update Docker image\non:\n push:\n # Rebuild the image when Dockerfile is changed. This is safe on a PR\n # bra"
},
{
"path": ".gitignore",
"chars": 71,
"preview": "node_modules/\ndebug.test\n/web\n\n# Google Cloud secret\nclient-secret.json"
},
{
"path": ".golangci.yaml",
"chars": 1745,
"preview": "version: \"2\"\nlinters:\n default: none\n enable:\n - containedctx\n - copyloopvar\n - dogsled\n - dupl\n - errc"
},
{
"path": ".vscode/launch.json",
"chars": 713,
"preview": "{\n // Use IntelliSense to learn about possible attributes.\n // Hover to view descriptions of existing attributes.\n"
},
{
"path": ".vscode/settings.json",
"chars": 229,
"preview": "{\n \"go.buildTags\": \"small,medium,large,cloud\",\n \"search.exclude\": {\n \"**/node_modules\": true,\n \"**/bower_compone"
},
{
"path": ".vscode/tasks.json",
"chars": 1797,
"preview": "{\n \"version\": \"2.0.0\",\n \"tasks\": [\n {\n \"label\": \"Build\",\n \"type\": \"shell\",\n "
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 188,
"preview": "# Code of Conduct\n\nAll code and communication under WPT Dashboard is covered by the [Chromium Code of Conduct](https://c"
},
{
"path": "CONTRIBUTING.md",
"chars": 1595,
"preview": "# Contributing\n\nWe'd love to accept your patches and contributions to this project. There are\njust a few small guideline"
},
{
"path": "Dockerfile",
"chars": 3082,
"preview": "# vim: set expandtab sw=4\nFROM golang:1.26.2-bookworm\n\n# Create a non-priviledged user to run browsers as (Firefox and C"
},
{
"path": "ISSUE_TEMPLATE/checks.md",
"chars": 337,
"preview": "### Check\nA link to the GitHub Check run containing my issue:\nhttps://github.com/web-platform-tests/wpt/pull/[PR Number]"
},
{
"path": "ISSUE_TEMPLATE/prod-deployment.md",
"chars": 296,
"preview": "Previous deployment was #ISSUE_NUM (PREV_SHA)\n\nChangelist PREV_SHA...NEW_SHA\n\nMajor changes:\n- A pull request title (#PR"
},
{
"path": "ISSUE_TEMPLATE/screenshots.md",
"chars": 439,
"preview": "<!-- Note that runs before 2019-04-01 might not have complete screenshots. -->\n\n### Example\nPermalink to an example reft"
},
{
"path": "ISSUE_TEMPLATE/search.md",
"chars": 251,
"preview": "### Search\nA link to the search containing my issue:\n<!-- You can easily get the permalink using the \"LINK\" dialog. Plea"
},
{
"path": "ISSUE_TEMPLATE.md",
"chars": 321,
"preview": "<!--\nThis project's primary focus is visualizing test results. It is not responsible\nfor collecting web-platform-tests. "
},
{
"path": "LICENSE",
"chars": 1504,
"preview": "W3C 3-clause BSD License\n\nhttp://www.w3.org/Consortium/Legal/2008/03-bsd-license.html\n\nRedistribution and use in source "
},
{
"path": "Makefile",
"chars": 12964,
"preview": "# Copyright 2017 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "PULL_REQUEST_TEMPLATE.md",
"chars": 897,
"preview": "<!--\nThanks for the PR, you probably worked hard on it! Before you submit it for review, please make sure you read our g"
},
{
"path": "README.md",
"chars": 3333,
"preview": "# [web-platform-tests dashboard](https://wpt.fyi/) 📈\n\n[, and this\ndocument"
},
{
"path": "api/azure/api.go",
"chars": 3756,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/azure/mock_azure/api_mock.go",
"chars": 2779,
"preview": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/web-platform-tests/wpt.fyi/api/azure (interfaces: API)\n"
},
{
"path": "api/azure/notify.go",
"chars": 1282,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/azure/routes.go",
"chars": 695,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/azure/webhook.go",
"chars": 3586,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/azure/webhook_test.go",
"chars": 3214,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/bsf_handler.go",
"chars": 2097,
"preview": "// Copyright 2020 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/bsf_handler_test.go",
"chars": 3202,
"preview": "//go:build small\n\n// Copyright 2020 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/checks/README.md",
"chars": 731,
"preview": "# wpt.fyi GitHub Checks integration\n\nThis directory implements the wpt.fyi (and staging.wpt.fyi) integration with\nthe Gi"
},
{
"path": "api/checks/api.go",
"chars": 6672,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/jwt.go",
"chars": 3507,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/mock_checks/api_mock.go",
"chars": 12259,
"preview": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/web-platform-tests/wpt.fyi/api/checks (interfaces: API)"
},
{
"path": "api/checks/routes.go",
"chars": 704,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/runs.go",
"chars": 5444,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/suites.go",
"chars": 1205,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/suites_medium_test.go",
"chars": 998,
"preview": "//go:build medium\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is gover"
},
{
"path": "api/checks/summaries/actions.go",
"chars": 1116,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/summaries/actions_test.go",
"chars": 848,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/checks/summaries/compile.go",
"chars": 3346,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/summaries/compile_test.go",
"chars": 4499,
"preview": "//go:build medium\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is gover"
},
{
"path": "api/checks/summaries/completed.go",
"chars": 1237,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/summaries/pending.go",
"chars": 811,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/summaries/regressed.go",
"chars": 1751,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/summaries/templates/_file_an_issue.md",
"chars": 114,
"preview": "> _Note: wpt.fyi checks are still in beta!_\n>\n> See something wrong? Please [file an issue]({{ .FileIssueURL }})!\n"
},
{
"path": "api/checks/summaries/templates/_pr_and_master_specs.md",
"chars": 126,
"preview": "Run | Spec\n--- | ---\n`master` | {{ .BaseRun.String }}\n`{{ printf \"%.7s\" .HeadRun.FullRevisionHash }}` | {{ .HeadRun.Stri"
},
{
"path": "api/checks/summaries/templates/_pr_runs_links.md",
"chars": 219,
"preview": "{{- range $pr := .CheckState.PRNumbers }}\n- [Latest results for PR #{{ $pr }}]({{ $.HostURL }}results/?pr={{ $pr }}&labe"
},
{
"path": "api/checks/summaries/templates/_successfully_scraped.md",
"chars": 86,
"preview": "Results have successfully been scraped and added to [{{ .HostName }}]({{ .HostURL }})."
},
{
"path": "api/checks/summaries/templates/completed.md",
"chars": 981,
"preview": "{{ template \"_successfully_scraped.md\" . }}\n\nThere were no regressions detected in the results.\n\n{{ template \"_pr_and_ma"
},
{
"path": "api/checks/summaries/templates/pending.md",
"chars": 174,
"preview": "Results have been produced, and are being collected as we speak...\n\nThey'll eventually be visible on [{{ .HostName }}]({"
},
{
"path": "api/checks/summaries/templates/regressed.md",
"chars": 1088,
"preview": "{{ template \"_successfully_scraped.md\" . }}\n\nUh-oh - it looks like there are some newly-failing results when we compared"
},
{
"path": "api/checks/update.go",
"chars": 11784,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/update_medium_test.go",
"chars": 3793,
"preview": "//go:build medium\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is gover"
},
{
"path": "api/checks/update_test.go",
"chars": 7215,
"preview": "//go:build small\n\npackage checks\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/tes"
},
{
"path": "api/checks/webhook.go",
"chars": 11709,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/checks/webhook_test.go",
"chars": 9219,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/diff.go",
"chars": 5106,
"preview": "package api //nolint:revive\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\n\tmapset \"github.co"
},
{
"path": "api/ghactions/notify.go",
"chars": 4762,
"preview": "// Copyright 2024 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/ghactions/notify_test.go",
"chars": 3946,
"preview": "//go:build small\n\n// Copyright 2024 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/ghactions/routes.go",
"chars": 687,
"preview": "// Copyright 2024 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/labels.go",
"chars": 1813,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/labels_medium_test.go",
"chars": 1310,
"preview": "//go:build medium\n\n// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is gover"
},
{
"path": "api/manifest/api.go",
"chars": 4117,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/manifest/mock_manifest/api_mock.go",
"chars": 2182,
"preview": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/web-platform-tests/wpt.fyi/api/manifest (interfaces: AP"
},
{
"path": "api/manifest/util.go",
"chars": 768,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/manifest/util_test.go",
"chars": 1039,
"preview": "//go:build small\n\n// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/manifest.go",
"chars": 3858,
"preview": "// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/manifest_test.go",
"chars": 3932,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/metadata_cache.go",
"chars": 2388,
"preview": "// Copyright 2020 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/metadata_handler.go",
"chars": 9598,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/metadata_handler_test.go",
"chars": 15835,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/pending_test_runs.go",
"chars": 2125,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/pending_test_runs_medium_test.go",
"chars": 3997,
"preview": "//go:build medium\n\npackage api //nolint:revive\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httpte"
},
{
"path": "api/query/README.md",
"chars": 9120,
"preview": "# wpt.fyi Search queries\n\nwpt.fyi supports a structured search syntax, allowing the user to filter specific results.\n\n##"
},
{
"path": "api/query/atoms.go",
"chars": 33857,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/atoms_test.go",
"chars": 35039,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/cache/README.md",
"chars": 2677,
"preview": "# Searchcache\n\nThis directory contains the implementation of the searchcache for wpt.fyi. The\nsearchcache runs as a sepa"
},
{
"path": "api/query/cache/backfill/backfill.go",
"chars": 4900,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/backfill/backfill_medium_test.go",
"chars": 3841,
"preview": "//go:build medium\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is gover"
},
{
"path": "api/query/cache/backfill/backfill_test.go",
"chars": 1183,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/cache/backfill/mock_backfill/backfill_mock.go",
"chars": 1563,
"preview": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/web-platform-tests/wpt.fyi/api/query/cache/backfill (in"
},
{
"path": "api/query/cache/index/aggregator.go",
"chars": 3071,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/index/filter.go",
"chars": 14135,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/index/index.go",
"chars": 13990,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/index/index_filter_test.go",
"chars": 39499,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/cache/index/index_medium_test.go",
"chars": 1605,
"preview": "//go:build medium\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is gover"
},
{
"path": "api/query/cache/index/index_mock.go",
"chars": 4855,
"preview": "// Code generated by MockGen. DO NOT EDIT.\n// Source: api/query/cache/index/index.go\n\n// Package index is a generated Go"
},
{
"path": "api/query/cache/index/index_test.go",
"chars": 9846,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/cache/index/results.go",
"chars": 2799,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/index/results_test.go",
"chars": 1021,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/cache/index/tests.go",
"chars": 1953,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/index/tests_test.go",
"chars": 966,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/cache/lru/lru.go",
"chars": 2416,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/lru/lru_test.go",
"chars": 1713,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/cache/monitor/monitor.go",
"chars": 5835,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/monitor/monitor_mock.go",
"chars": 3508,
"preview": "// Code generated by MockGen. DO NOT EDIT.\n// Source: api/query/cache/monitor/monitor.go\n\n// Package monitor is a genera"
},
{
"path": "api/query/cache/monitor/monitor_test.go",
"chars": 4457,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/cache/poll/poll.go",
"chars": 6992,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/poll/poll_test.go",
"chars": 2346,
"preview": "//go:build small\n\n// Copyright 2024 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/cache/query/query.go",
"chars": 1283,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/cache/query/query_test.go",
"chars": 1192,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/concrete_query.go",
"chars": 6250,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/metadata_cache.go",
"chars": 979,
"preview": "// Copyright 2020 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/query.go",
"chars": 4926,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/query_test.go",
"chars": 6789,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/routes.go",
"chars": 478,
"preview": "// Copyright 218 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style l"
},
{
"path": "api/query/search.go",
"chars": 9366,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/search_medium_test.go",
"chars": 13924,
"preview": "//go:build medium\n\n// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is gover"
},
{
"path": "api/query/search_test.go",
"chars": 6550,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/query/test/types.go",
"chars": 2168,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/query/util.go",
"chars": 106,
"preview": "package query\n\nimport \"strings\"\n\nfunc canonicalizeStr(str string) string {\n\treturn strings.ToLower(str)\n}\n"
},
{
"path": "api/query/web_features_manifest_cache.go",
"chars": 1814,
"preview": "// Copyright 2024 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/api.go",
"chars": 6004,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/api_cloud_test.go",
"chars": 1269,
"preview": "//go:build cloud\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/receiver/api_medium_test.go",
"chars": 7348,
"preview": "//go:build medium\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is gover"
},
{
"path": "api/receiver/azure.go",
"chars": 638,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/azure_test.go",
"chars": 553,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/receiver/client/client.go",
"chars": 2689,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/client/client_test.go",
"chars": 1843,
"preview": "//go:build small\n\n// Copyright 2020 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/receiver/create_run.go",
"chars": 3544,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/create_run_test.go",
"chars": 8510,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/receiver/gcs.go",
"chars": 1046,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/handlers.go",
"chars": 1092,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/mock_receiver/api_mock.go",
"chars": 11230,
"preview": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/web-platform-tests/wpt.fyi/api/receiver (interfaces: AP"
},
{
"path": "api/receiver/receive_results.go",
"chars": 5686,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/receive_results_test.go",
"chars": 11732,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/receiver/routes.go",
"chars": 966,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/update_pending_run.go",
"chars": 1427,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/receiver/update_pending_run_test.go",
"chars": 1578,
"preview": "//go:build small\n\n// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/results_redirect_handler.go",
"chars": 1576,
"preview": "// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/routes.go",
"chars": 3684,
"preview": "// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/screenshot/cache.go",
"chars": 4093,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/screenshot/model.go",
"chars": 4626,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/screenshot/model_medium_test.go",
"chars": 5218,
"preview": "//go:build medium\n\n// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is gover"
},
{
"path": "api/screenshot/routes.go",
"chars": 705,
"preview": "// Copyright 2019 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/screenshot_redirect_handler.go",
"chars": 1036,
"preview": "// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/shas.go",
"chars": 2727,
"preview": "// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/shas_medium_test.go",
"chars": 2068,
"preview": "//go:build medium\n\npackage api //nolint:revive\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strin"
},
{
"path": "api/taskcluster/mock_taskcluster/webhook_mock.go",
"chars": 2428,
"preview": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/web-platform-tests/wpt.fyi/api/taskcluster (interfaces:"
},
{
"path": "api/taskcluster/routes.go",
"chars": 490,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/taskcluster/webhook.go",
"chars": 19162,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/taskcluster/webhook_test.go",
"chars": 29902,
"preview": "//go:build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/test_history.go",
"chars": 2322,
"preview": "package api //nolint:revive\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"sort\"\n\n\t\"github.com/web-platform-tests"
},
{
"path": "api/test_history_test.go",
"chars": 1718,
"preview": "//go:build small\n\n// Copyright 2023 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is govern"
},
{
"path": "api/test_run.go",
"chars": 2383,
"preview": "// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/test_run_medium_test.go",
"chars": 1212,
"preview": "//go:build medium\n\npackage api //nolint:revive\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testi"
},
{
"path": "api/test_runs.go",
"chars": 5296,
"preview": "// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/test_runs_medium_test.go",
"chars": 8572,
"preview": "//go:build medium\n\npackage api //nolint:revive\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n"
},
{
"path": "api/user.go",
"chars": 1599,
"preview": "// Copyright 2020 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/versions.go",
"chars": 3084,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "api/versions_medium_test.go",
"chars": 2345,
"preview": "//go:build medium\n\npackage api //nolint:revive\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testi"
},
{
"path": "docs/admin.md",
"chars": 682,
"preview": "# Admin\n\n## Flags\n\n[`/admin/flags`](https://wpt.fyi/admin/flags) allows site-wide settings to be set, similar to the per"
},
{
"path": "docs/api.md",
"chars": 38,
"preview": "See [/api/README.md](/api/README.md).\n"
},
{
"path": "docs/app-engine.md",
"chars": 3083,
"preview": "# App Engine Documentation\n\nThe project runs on Google App Engine. It contains the following three services,\neach of whi"
},
{
"path": "docs/cache.md",
"chars": 2198,
"preview": "# Triage Metadata Caching\n\nThe [wpt.fyi](https://wpt.fyi) dashboard has support for linking test results\nfor a specific "
},
{
"path": "docs/docker.md",
"chars": 1333,
"preview": "# Docker\n\nWe use Docker for two purposes: development and production. And we have a few\ndifferent Docker images.\n\n## Dev"
},
{
"path": "docs/gcs.md",
"chars": 2247,
"preview": "# Google Cloud Storage\n\n**Note:** to apply the all permissive CORS policy to a new bucket, run:\n`gsutil cors set util/gs"
},
{
"path": "docs/triaging.md",
"chars": 2880,
"preview": "# Triaging failing tests (aka wpt-metadata)\n\nThe [wpt.fyi](https://wpt.fyi) dashboard has support for linking test resul"
},
{
"path": "docs/ui.md",
"chars": 561,
"preview": "# UI Development\n\nThe UI consists of base HTML templates served by the Go App Engine app in `webapp/templates/` and Poly"
},
{
"path": "docs/upgrading-go.md",
"chars": 2317,
"preview": "# Maintenance: Upgrading Golang\n\nThis document details the files to change and the necessary steps when upgrading Golang"
},
{
"path": "git/hooks/README.md",
"chars": 198,
"preview": "# Git hooks\n\nTo opt in for these version-controlled Git hooks, sym-link to this directory from `../.git/hooks`, i.e.:\n\n "
},
{
"path": "git/hooks/pre-push",
"chars": 2085,
"preview": "#!/bin/bash\n\nREPO_DIR=\"$(git rev-parse --show-toplevel)\"\nsource \"${REPO_DIR}/util/logging.sh\"\nsource \"${REPO_DIR}/util/c"
},
{
"path": "go.mod",
"chars": 4910,
"preview": "module github.com/web-platform-tests/wpt.fyi\n\ngo 1.26.2\n\nrequire (\n\tcloud.google.com/go/cloudtasks v1.16.0\n\tcloud.google"
},
{
"path": "go.sum",
"chars": 32418,
"preview": "cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=\ncel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ"
},
{
"path": "results-processor/.gcloudignore",
"chars": 62,
"preview": "#!include:.gitignore\n\n# Google Cloud secret\nclient-secret.json"
},
{
"path": "results-processor/.gitignore",
"chars": 37,
"preview": "env/\n.tox/\n__pycache__/\n.mypy_cache/\n"
},
{
"path": "results-processor/.python-version",
"chars": 5,
"preview": "3.11\n"
},
{
"path": "results-processor/Dockerfile",
"chars": 1705,
"preview": "FROM python:3.11.15-bookworm\n\n# Install runtime dependencies.\n# python3-crcmod for faster gsutil checksum\n# python3-virt"
},
{
"path": "results-processor/README.md",
"chars": 1472,
"preview": "## Basics\n\nThe results processor runs on Python 3.11. The entry point is a Flask web server\n(`main.py`). In production, "
},
{
"path": "results-processor/app.staging.yaml",
"chars": 424,
"preview": "# Copyright 2022 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "results-processor/app.yaml",
"chars": 256,
"preview": "service: processor\nruntime: custom\nenv: flex\n\nmanual_scaling:\n instances: 5\nresources:\n cpu: 4\n memory_gb: 4\n disk_s"
},
{
"path": "results-processor/config.py",
"chars": 762,
"preview": "import os\n\n\ndef _is_prod() -> bool:\n return os.getenv('GOOGLE_CLOUD_PROJECT') == 'wptdashboard'\n\n\ndef raw_results_buc"
},
{
"path": "results-processor/gsutil.py",
"chars": 1542,
"preview": "# Copyright 2018 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "results-processor/main.py",
"chars": 4580,
"preview": "#!/usr/bin/env python3\nimport functools\nimport logging\nimport os\nimport tempfile\nimport time\nfrom http import HTTPStatus"
},
{
"path": "results-processor/mypy.ini",
"chars": 502,
"preview": "[mypy]\ncheck_untyped_defs = True\ndisallow_any_generics = True\ndisallow_incomplete_defs = True\ndisallow_subclassing_any ="
},
{
"path": "results-processor/processor.py",
"chars": 16393,
"preview": "# Copyright 2018 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "results-processor/processor_test.py",
"chars": 13088,
"preview": "# Copyright 2019 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "results-processor/requirements.in",
"chars": 103,
"preview": "Flask\nfilelock\nflake8\ngoogle-cloud-datastore\ngoogle-cloud-storage\ngunicorn\nmypy\nrequests\ntypes-requests"
},
{
"path": "results-processor/requirements.txt",
"chars": 2481,
"preview": "#\n# This file is autogenerated by pip-compile with Python 3.11\n# by the following command:\n#\n# pip-compile requiremen"
},
{
"path": "results-processor/test_server.py",
"chars": 2131,
"preview": "#!/usr/bin/env python3\n\n# Copyright 2019 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is go"
},
{
"path": "results-processor/test_util.py",
"chars": 873,
"preview": "# Copyright 2019 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "results-processor/tox.ini",
"chars": 364,
"preview": "[tox]\nenvlist = py311\n# We don't have or need setup.py for now.\nskipsdist=True\n\n[flake8]\nexclude=__pycache__,env,.tox\n\n["
},
{
"path": "results-processor/wptreport.py",
"chars": 25821,
"preview": "#!/usr/bin/env python3\n\n# Copyright 2018 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is go"
},
{
"path": "results-processor/wptreport_test.py",
"chars": 24578,
"preview": "# Copyright 2018 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "results-processor/wptscreenshot.py",
"chars": 4903,
"preview": "# Copyright 2019 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "results-processor/wptscreenshot_test.py",
"chars": 4592,
"preview": "# Copyright 2019 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "scripts/README.md",
"chars": 2642,
"preview": "## Updating the pinned Chromium revision in WPT\nThese scripts exists as Cloud Functions in GCP and will need to be redep"
},
{
"path": "scripts/check_chromium_revision.py",
"chars": 5452,
"preview": "# Copyright 2025 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "scripts/process_test_history.py",
"chars": 21464,
"preview": "# Copyright 2023 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "scripts/update_chromium_revision.py",
"chars": 4242,
"preview": "# Copyright 2025 The WPT Dashboard Project. All rights reserved.\n# Use of this source code is governed by a BSD-style li"
},
{
"path": "shared/appengine.go",
"chars": 13684,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "shared/appengine_test.go",
"chars": 3105,
"preview": "// +build small\n\n// Copyright 2020 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governe"
},
{
"path": "shared/browsers.go",
"chars": 1519,
"preview": "package shared\n\nimport (\n\t\"strings\"\n\n\tmapset \"github.com/deckarep/golang-set\"\n)\n\n// A list of browsers that are shown on"
},
{
"path": "shared/browsers_test.go",
"chars": 2163,
"preview": "//go:build small\n// +build small\n\n// Copyright 2017 The WPT Dashboard Project. All rights reserved.\n// Use of this sourc"
},
{
"path": "shared/cache.go",
"chars": 12779,
"preview": "// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governed by a BSD-style "
},
{
"path": "shared/cache_test.go",
"chars": 2322,
"preview": "// +build small\n\n// Copyright 2018 The WPT Dashboard Project. All rights reserved.\n// Use of this source code is governe"
}
]
// ... and 239 more files (download for full content)
About this extraction
This page contains the full source code of the web-platform-tests/wpt.fyi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 439 files (138.5 MB), approximately 3.9M tokens, and a symbol index with 3169 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.