Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UPLOAD-1798/gha-playwright #528

Open
wants to merge 108 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 105 commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
1b7d99c
in progress commit
thetif Oct 8, 2024
686adaf
temp
thetif Oct 8, 2024
a0e0d97
Merge branch 'main' of github.com:CDCgov/data-exchange-upload into UP…
thetif Oct 8, 2024
df44564
created a docker-compose file for running playwright tests; set the p…
thetif Oct 9, 2024
5faa6f9
updated to reporting back to PR
thetif Oct 9, 2024
f1adcf8
Merge branch 'main' of github.com:CDCgov/data-exchange-upload into UP…
thetif Oct 9, 2024
994c3a8
removed reporting steps from playwright job because it wasn't allowed
thetif Oct 9, 2024
ddfc976
commented out e2e job
thetif Oct 9, 2024
6b5440b
fixed test I forgot to change with the new server url creation
thetif Oct 9, 2024
27b5f0e
updating the second image to have the same permissions as the first
thetif Oct 9, 2024
154e765
uncommenting part of e2e-test job
thetif Oct 9, 2024
5841cc3
trying to run the jobs in sequence in case that's causing the issue
thetif Oct 9, 2024
9dc2f34
explicitly stopping containers on simulation tests
thetif Oct 9, 2024
b22c254
testing
thetif Oct 9, 2024
2206025
copied the test upload file into the playwright directory; updated th…
thetif Oct 9, 2024
79d5c17
putting e2e before sim
thetif Oct 9, 2024
a6afc54
removed other docker-compose from the run command
thetif Oct 9, 2024
eb47f5c
updating the playwright command
thetif Oct 9, 2024
152c291
fixed run in workflow
thetif Oct 9, 2024
2a0bdbb
limit services being started
thetif Oct 9, 2024
60066a8
trying to see if it actually needs localhost?
thetif Oct 9, 2024
2beb464
putting quotes around the healthcheck
thetif Oct 9, 2024
1b625b5
removed hostname; creating containers before starting them
thetif Oct 9, 2024
4d7cd12
podman compose build
thetif Oct 9, 2024
8b9f814
remove build
thetif Oct 9, 2024
29c0ad1
switching to docker-compose
thetif Oct 9, 2024
f5706a4
specifying a network to see if that helps
thetif Oct 9, 2024
219903d
separating spinning up the containers
thetif Oct 9, 2024
edfad17
creating network
thetif Oct 9, 2024
e3dd2b2
trying again
thetif Oct 9, 2024
545c771
pulling out monitoring and removing ports for e2e
whytheplatypus Oct 10, 2024
b34a7de
Merge branch 'main' of github.com:CDCgov/data-exchange-upload into UP…
thetif Oct 10, 2024
585947c
extending upload-server and cache directly into the e2e docker-compos…
thetif Oct 10, 2024
7ca5f07
removed restarts; using UI_URL in wait-for-it script
thetif Oct 10, 2024
176679e
increasing timeout for wait-for-it
thetif Oct 10, 2024
601f332
changed sleep time
thetif Oct 10, 2024
a782381
removed wait-for-it
thetif Oct 10, 2024
407c748
increased sleep
thetif Oct 10, 2024
69d937c
attempting to get it working with podman
thetif Oct 11, 2024
44ac0f9
Merge branch 'main' of github.com:CDCgov/data-exchange-upload into UP…
thetif Oct 11, 2024
62597a7
detaching first call to docker-compose
thetif Oct 11, 2024
14d7304
small changes
thetif Oct 11, 2024
9d69091
commenting out failing test
thetif Oct 11, 2024
1833502
using UI_URL for wait-for-it
thetif Oct 11, 2024
2eabc27
updates to ci gha
thetif Oct 11, 2024
eaabf31
splitting different e2e into their own jobs
thetif Oct 11, 2024
8aaf59c
multiple jobs did not work
thetif Oct 11, 2024
5a7c221
moved Simulation Tests into the e2e job
thetif Oct 11, 2024
dc5e162
updated steps
thetif Oct 11, 2024
5c90fc2
starting server before tests
thetif Oct 11, 2024
d0c7a8d
stopping containers before starting
thetif Oct 11, 2024
db1ad87
removed container names
thetif Oct 11, 2024
05e04b4
removing some run commands
thetif Oct 11, 2024
2d3ecc2
adding flags to up
thetif Oct 11, 2024
b8b02e0
commenting out some steps
thetif Oct 11, 2024
16cc63a
starting server before tests
thetif Oct 11, 2024
2793f1c
switched back to all container definitions in one file
thetif Oct 15, 2024
5d60826
commenting out simulation-test job
thetif Oct 15, 2024
b6fe37c
trying to build before starting
thetif Oct 15, 2024
4bf937d
replacing wait-for-it with sleep
thetif Oct 15, 2024
8d9dcc1
reduced sleep time
thetif Oct 15, 2024
fb2c560
trying using the dockerfile to build the server instead of building i…
thetif Oct 15, 2024
d8180a8
removed image field
thetif Oct 15, 2024
fc63c4f
splitting up starting servers
thetif Oct 15, 2024
1b42679
back to single command
thetif Oct 15, 2024
60f958e
privileged true on redis
thetif Oct 15, 2024
36ccd88
not using the extended upload-server definition
thetif Oct 15, 2024
ae07a51
adding azure; file system was working in last commit
thetif Oct 15, 2024
8cd1bdc
filename typo
thetif Oct 15, 2024
2580a99
setting up azure e2e
thetif Oct 15, 2024
536bf4b
setting up running all the e2e tests
thetif Oct 15, 2024
31aa138
isolating docker-compose files on their own networks
thetif Oct 15, 2024
4afdcd1
changing report file path; uncommenting simulation-test
thetif Oct 15, 2024
9a323d9
running simulation-test in sequence with e2e; changed e2e to use stop…
thetif Oct 15, 2024
36ce694
fixing options
thetif Oct 15, 2024
1d95538
fixed failing test; working on artifact upload path
thetif Oct 15, 2024
634ea8a
trying extends in docker-compose file; removing artifact uploading
thetif Oct 15, 2024
3c2d2a1
fixed UI url creation; reverted aws to not use extends; fixed Azure s…
thetif Oct 15, 2024
77e03a3
running simulation-tests and e2e in parallel
thetif Oct 15, 2024
fb54722
trying to capture the test output so we can print the output
thetif Oct 15, 2024
fbdf1e4
trying to change the output
thetif Oct 15, 2024
a7234c9
setting report as output
thetif Oct 15, 2024
1b8d83e
fixing output
thetif Oct 15, 2024
42be422
not suppressing output from podman
thetif Oct 15, 2024
d7bce4c
separating the different e2e runs into different jobs; added scripts …
thetif Oct 16, 2024
a5426fc
adding npm install back
thetif Oct 16, 2024
31f5563
templatizing the e2e tests
thetif Oct 16, 2024
2f6b524
trying to get docker-compose file from the filename
thetif Oct 16, 2024
1e37d39
attempting to set the docker-compose filename dynamically
thetif Oct 16, 2024
2f0a753
trying to set the docker-compose file dynamically
thetif Oct 16, 2024
1fb7743
setting working directory
thetif Oct 16, 2024
a6f5251
setting test results as job summary
thetif Oct 16, 2024
6b89052
setting the GITHUB_STEP_SUMMARY from the run without needing the file
thetif Oct 16, 2024
3ad4657
added report file back
thetif Oct 16, 2024
26f34dd
trying to set GIT_STEP_SUMMARY
thetif Oct 16, 2024
5746171
typo
thetif Oct 16, 2024
1bc08cb
going back to cat
thetif Oct 16, 2024
8d10603
typo
thetif Oct 16, 2024
19efdf7
overwriting GITHUB_SUMMARY_STEP with contents of report
thetif Oct 16, 2024
6a899f5
making report print clearer
thetif Oct 16, 2024
68e5a86
trying logs instead of file
thetif Oct 16, 2024
ce7fee0
rename title
thetif Oct 16, 2024
4c0c2e4
removed outputting to a github report file
thetif Oct 16, 2024
d2a97fa
shortened test titles
thetif Oct 16, 2024
1c23aed
Merge branch 'main' of github.com:CDCgov/data-exchange-upload into UP…
thetif Oct 17, 2024
ce3ef5a
addressing comments in PR
thetif Oct 17, 2024
f0c52ca
Merge branch 'main' of github.com:CDCgov/data-exchange-upload into UP…
thetif Oct 21, 2024
b1609dd
removed UIUrl from appconfig
thetif Oct 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/e2e-test-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Template - Run E2E Tests Using Docker-Compose File

on:
workflow_call:
inputs:
TEST_TITLE:
type: string
required: true
COMPOSE_FILENAME:
type: string
required: true
STORAGE_TYPE:
type: string
required: true

defaults:
run:
working-directory: upload-server/

jobs:
e2e-tests:
runs-on: ubuntu-latest
env:
CI: true
AZURITE_STORAGE_KEY: ${{ (inputs.STORAGE_TYPE == 'azure') && secrets.AZURITE_STORAGE_KEY }}
steps:
- uses: actions/checkout@v4
- name: Install podman compose
run: pip3 install podman-compose
- name: Run E2E Tests
id: test
run: podman-compose -f ${{ inputs.COMPOSE_FILENAME }} up --build --exit-code-from playwright --abort-on-container-exit
cfarmer-fearless marked this conversation as resolved.
Show resolved Hide resolved
- name: Test Report
# Piping the logs through perl so that we can append the TEST_TITLE to make where they are coming from clearer
# The only annotation types produced by the `github` report are 'debug', 'notice', 'warning', and 'error' so this should cover them all
run: podman-compose -f ${{ inputs.COMPOSE_FILENAME }} logs -f playwright | perl -pe 's/::(debug|notice|warning|error) title=/$&\[${{ inputs.TEST_TITLE }}\] /g'
- name: Tear Down Containers
run: podman-compose -f ${{ inputs.COMPOSE_FILENAME }} down
outputs:
actualResult: ${{ steps.test.conclusion }}
24 changes: 24 additions & 0 deletions .github/workflows/tus-upload-server-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,30 @@ jobs:
run: podman-compose -f docker-compose.yml -f docker-compose.azurite.yml -f docker-compose.minio.yml -f docker-compose.testing.yml up --exit-code-from upload-server
- name: Show coverage
run: go tool cover -func=c.out
e2e-tests-fs:
name: E2E Tests - File System Storage
uses: ./.github/workflows/e2e-test-template.yml
with:
TEST_TITLE: E2E FS Tests
STORAGE_TYPE: fs
COMPOSE_FILENAME: ./docker-compose.e2e.yml
secrets: inherit
e2e-tests-azure:
name: E2E Tests - Azure Blob Storage
uses: ./.github/workflows/e2e-test-template.yml
with:
TEST_TITLE: E2E Azure Tests
COMPOSE_FILENAME: ./docker-compose.e2e.azure.yml
STORAGE_TYPE: azure
secrets: inherit
e2e-tests-aws:
name: E2E Tests - AWS S3 Storage
uses: ./.github/workflows/e2e-test-template.yml
with:
TEST_TITLE: E2E AWS Tests
COMPOSE_FILENAME: ./docker-compose.e2e.aws.yml
STORAGE_TYPE: aws
secrets: inherit
run-fortify-scan:
uses: ./.github/workflows/remote-cd-trigger-template.yml
with:
Expand Down
1 change: 1 addition & 0 deletions tests/smoke/playwright/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Playwright test results
test-results/
test-reports/
30 changes: 15 additions & 15 deletions tests/smoke/playwright/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions tests/smoke/playwright/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"main": "dist/main.js",
"scripts": {
"build": "npx tsc",
"test": "npx playwright test"
"wait": "./wait-for-it.sh ${UI_URL:-http://localhost:8081}",
"test": "npm run wait; npx playwright test",
thetif marked this conversation as resolved.
Show resolved Hide resolved
"test:docker": "npm install; npm run test"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the wait step is good, and should be explicitly done here and not in the run test script.

Also... for this, can we include a --workers=2 (or 4 maybe?) to have tests run multithreaded? That might speed up the runs. Podman seems to handle it, can our GHA runners do that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So scratch this maybe? I see below we have a workers config.

},
"dependencies": {
"dotenv": "^16.4.5",
Expand All @@ -17,7 +19,7 @@
"license": "ISC",
"devDependencies": {
"@axe-core/playwright": "^4.10.0",
"@playwright/test": "^1.42.0",
"@playwright/test": "1.48.0",
"@types/express": "^4.17.1",
"@types/node": "^20.11.22",
"ts-node": "^10.9.2",
Expand Down
43 changes: 36 additions & 7 deletions tests/smoke/playwright/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,49 @@
import { PlaywrightTestConfig, devices } from "@playwright/test";

const baseURL = process.env.UI_URL ?? 'http://localhost:8081';
const jsonReportFilename = process.env.TEST_REPORT_JSON ?? 'test-report.json'

const config: PlaywrightTestConfig = {
// Specify the directory where your tests are located
testDir: "./test",

// Use this to change the number of browsers/contexts to run in parallel
// Setting this to 1 will run tests serially which can help if you're seeing issues with parallel execution
workers: 1,
// Opt out of parallel tests on CI.
workers: process.env.CI ? 1 : 4,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to opt out of parallel tests on CI? Should we? Parallel tests might let things run faster. Does 2 workers work? Have we tried 4 with the GHA runner?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Playwright recommends only use 1 https://playwright.dev/docs/ci


// Fail the build on CI if you accidentally left test.only in the source code.
forbidOnly: !!process.env.CI,

// Configure retries for flaky tests
retries: 0,
// If a test fails, retry it additional 2 times
// Retry on CI only.
retries: process.env.CI ? 2 : 0,
thetif marked this conversation as resolved.
Show resolved Hide resolved

// Configure test timeout
timeout: 30000,

// Reporter to use
reporter: process.env.CI
? 'github' : [
['list'],
[
'html',
{
outputFolder: `./test-reports/html`,
open: 'never',
},
],
[
'json',
{
outputFile: `./test-reports/${jsonReportFilename}`,
},
],
],

// Artifacts folder where screenshots, videos, and traces are stored.
outputDir: './test-results',

// Specify browser to use
use: {
// Specify browser to use. You can also use 'firefox' or 'webkit'.
Expand All @@ -27,8 +57,10 @@ const config: PlaywrightTestConfig = {
// Specify viewport size
viewport: { width: 1280, height: 720 },

// Specify the server url
baseURL,

// More options can be set here
baseURL: "http://localhost:8081",
},

// Add any global setup or teardown in here
Expand All @@ -43,9 +75,6 @@ const config: PlaywrightTestConfig = {
},
// More projects can be configured here
],

// Configure reporter here. 'dot', 'list', 'junit', etc.
reporter: [['list']]
};

export default config;
1 change: 1 addition & 0 deletions tests/smoke/playwright/test-data/10KB-test-file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
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
Loading
Loading