From 2c34cf96803e6bc921574f7024f361dc4b3a3690 Mon Sep 17 00:00:00 2001 From: Marshall Cottrell Date: Fri, 24 May 2024 16:45:03 -0400 Subject: [PATCH] chore: add basic smoke tests with sso, git commit, and file uploads (#132) Fixes #130 --- .github/workflows/test.yaml | 7 +++ .gitignore | 4 ++ tasks.yaml | 6 +++ tasks/test.yaml | 92 +++++++++++++++++++++++++------ tests/auth.setup.ts | 26 +++++++++ tests/data/unicorns.jpeg | Bin 0 -> 10810 bytes tests/data/zarf.yaml | 12 +++++ tests/gitlab.test.ts | 68 +++++++++++++++++++++++ tests/package-lock.json | 104 ++++++++++++++++++++++++++++++++++++ tests/package.json | 9 ++++ tests/playwright.config.ts | 43 +++++++++++++++ tests/tsconfig.json | 10 ++++ 12 files changed, 366 insertions(+), 15 deletions(-) create mode 100644 tests/auth.setup.ts create mode 100644 tests/data/unicorns.jpeg create mode 100644 tests/data/zarf.yaml create mode 100644 tests/gitlab.test.ts create mode 100644 tests/package-lock.json create mode 100644 tests/package.json create mode 100644 tests/playwright.config.ts create mode 100644 tests/tsconfig.json diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ed7d253c..7062e683 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -63,3 +63,10 @@ jobs: uses: defenseunicorns/uds-common/.github/actions/save-logs@859a9b2469c8a6c24c414fe34b127ec5677aea62 # v0.4.3 with: suffix: ${{ matrix.type }}-${{ matrix.flavor }}-${{ github.run_id }}-${{ github.run_attempt }} + + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + if: always() + with: + name: playwright-report-${{ matrix.type }}-${{ matrix.flavor }}-${{ github.run_id }}-${{ github.run_attempt }} + path: tests/.playwright/reports/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index 00998119..81511050 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,7 @@ test/tf/public-ec2-instance/.terraform terraform.tfstate terraform.tfstate.backup .terraform.lock.hcl + +# Tests +node_modules/ +.playwright/ diff --git a/tasks.yaml b/tasks.yaml index 54afc3bf..933a8fe4 100644 --- a/tasks.yaml +++ b/tasks.yaml @@ -47,8 +47,11 @@ tasks: - task: create-gl-test-bundle - task: setup:k3d-test-cluster - task: deploy:test-bundle + - task: setup:create-doug-user - task: test:health-check - task: test:ingress + - task: test:ui + - task: test:git - name: test-upgrade description: Test an upgrade from the latest released package to the current branch @@ -58,5 +61,8 @@ tasks: - task: deploy:test-bundle - task: create-gl-test-bundle - task: deploy:test-bundle + - task: setup:create-doug-user - task: test:health-check - task: test:ingress + - task: test:ui + - task: test:git diff --git a/tasks/test.yaml b/tasks/test.yaml index b4e4b90c..2d8dd306 100644 --- a/tasks/test.yaml +++ b/tasks/test.yaml @@ -1,7 +1,11 @@ +variables: + - name: GITLAB_TOKEN + default: glpat-NO_DEFAULT_VALUE + tasks: - name: health-check actions: - - description: Gitlab Exporter Health Check + - description: GitLab Exporter Health Check wait: cluster: kind: Deployment @@ -9,7 +13,7 @@ tasks: namespace: gitlab condition: Available - - description: Gitlab Registry Health Check + - description: GitLab Registry Health Check wait: cluster: kind: Deployment @@ -17,7 +21,7 @@ tasks: namespace: gitlab condition: Available - - description: Gitlab Shell Health Check + - description: GitLab Shell Health Check wait: cluster: kind: Deployment @@ -25,7 +29,7 @@ tasks: namespace: gitlab condition: Available - - description: Gitlab Toolbox Health Check + - description: GitLab Toolbox Health Check wait: cluster: kind: Deployment @@ -33,7 +37,7 @@ tasks: namespace: gitlab condition: Available - - description: Gitlab Sidekiq Health Check + - description: GitLab Sidekiq Health Check wait: cluster: kind: Deployment @@ -41,7 +45,7 @@ tasks: namespace: gitlab condition: Available - - description: Gitlab Webservice Health Check + - description: GitLab Webservice Health Check wait: cluster: kind: Deployment @@ -49,7 +53,7 @@ tasks: namespace: gitlab condition: Available - - description: Gitlab Pages Health Check + - description: GitLab Pages Health Check wait: cluster: kind: Deployment @@ -58,7 +62,7 @@ tasks: condition: Available # StatefulSets don't show conditions themselves so we look for an underlying Pod - - description: Gitlab Gitaly Health Check + - description: GitLab Gitaly Health Check wait: cluster: kind: Pod @@ -66,7 +70,7 @@ tasks: namespace: gitlab condition: Ready - - description: Gitlab Migrations Health Check + - description: GitLab Migrations Health Check wait: cluster: kind: Job @@ -76,12 +80,70 @@ tasks: - name: ingress actions: - - description: Gitlab UI Health Check - wait: - network: - protocol: https - address: gitlab.uds.dev - code: 200 + # `/-/readiness` endpoint returns 503 if any checks fail. + # When `?all=1` is specified, dependent services are also checked. + # https://docs.gitlab.com/ee/administration/monitoring/health_check.html#readiness + - description: GitLab Readiness Check + maxRetries: 30 + cmd: | + STATUS=$(curl -s -o /dev/null --write-out '%{http_code}' 'https://gitlab.uds.dev/-/readiness?all=1') + echo "GitLab readiness status: ${STATUS}" + if [ $STATUS != "200" ]; then + sleep 10 + exit 1 + fi + + - name: git + description: GitLab Repository Mirror Checks + actions: + - cmd: | + ./uds zarf package create --confirm + dir: tests/data + - task: create-doug-pat + - cmd: | + ./uds zarf package mirror-resources \ + zarf-package-gitlab-git-tests-${UDS_ARCH}-0.0.1.tar.zst \ + --git-url "https://gitlab.uds.dev" \ + --git-push-username "doug" \ + --git-push-password "${GITLAB_TOKEN}" \ + --confirm + dir: tests/data + + - name: ui + description: GitLab UI Checks + actions: + - cmd: npm ci + dir: tests + - cmd: npx playwright install --with-deps + dir: tests + - cmd: npx playwright test + dir: tests + + - name: create-doug-admin + description: Create "doug" account as admin (must be run *before* first login) + actions: + - cmd: | + ./uds zarf tools kubectl exec -n gitlab deployment/gitlab-toolbox -- gitlab-rails runner -e production '\ + user = User.new(username: "doug", name: "Doug Unicorn", email: "doug@uds.dev", password: "0123456789!", password_confirmation: "0123456789!"); \ + user.assign_personal_namespace!; \ + user.skip_confirmation!; \ + user.admin = true; \ + user.save!; \ + puts user.username; puts user.id; \ + ' + + - name: create-doug-pat + description: Create personal access token (PAT) for "doug" account + actions: + - cmd: | + ./uds zarf tools kubectl exec -n gitlab deployment/gitlab-toolbox -- gitlab-rails runner -e production '\ + user = User.find_by_username("doug"); \ + token = user.personal_access_tokens.create(scopes: ["api"], name: "doug", expires_at: 365.days.from_now); \ + token.save!; \ + puts token.token; \ + ' + setVariables: + - name: GITLAB_TOKEN - name: root-password actions: diff --git a/tests/auth.setup.ts b/tests/auth.setup.ts new file mode 100644 index 00000000..03899310 --- /dev/null +++ b/tests/auth.setup.ts @@ -0,0 +1,26 @@ +import { test as setup, expect } from '@playwright/test'; +import { authFile } from './playwright.config'; + +setup('authenticate', async ({ page, context }) => { + await page.goto('/'); + + await page.getByLabel('Username or email').fill('doug'); + await page.getByLabel('Password').fill('unicorn123!@#'); + await page.getByRole('button', { name: "Log In" }).click(); + + await page.waitForURL('/'); // successful redirect + + // ensure auth cookies were set + const cookies = await context.cookies(); + const keycloakCookie = cookies.find( + (cookie) => cookie.name === "KEYCLOAK_SESSION", + ); + + expect(keycloakCookie).toBeDefined(); + expect(keycloakCookie?.value).not.toBe(""); + expect(keycloakCookie?.domain).toContain("sso."); + + await page.context().storageState({ path: authFile }); + + await expect(page).toHaveURL('/'); +}) diff --git a/tests/data/unicorns.jpeg b/tests/data/unicorns.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..571d08da2a5e8b55724fd0f2e1b731fb8e8f8fb5 GIT binary patch literal 10810 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 literal 0 HcmV?d00001 diff --git a/tests/data/zarf.yaml b/tests/data/zarf.yaml new file mode 100644 index 00000000..1f798886 --- /dev/null +++ b/tests/data/zarf.yaml @@ -0,0 +1,12 @@ +kind: ZarfPackageConfig +metadata: + name: gitlab-git-tests + version: 0.0.1 + description: A package with git repos used for testing + +components: + - name: git-repos + repos: + # This references a commit that has a .gitlab-ci.yml in it - to update this push a PR and a new commit. + - https://github.com/defenseunicorns/uds-package-gitlab-runner.git + - https://github.com/defenseunicorns/uds-core.git diff --git a/tests/gitlab.test.ts b/tests/gitlab.test.ts new file mode 100644 index 00000000..88e61ab8 --- /dev/null +++ b/tests/gitlab.test.ts @@ -0,0 +1,68 @@ +import { test, expect } from "@playwright/test"; +import path from "path"; + +function randomProjectName(prefix: string = 'uds-package-test') { + return [ prefix, Math.floor((Math.random() * 10_000)) ].join('-'); +} + +test('setup a project', async ({ page }) => { + const projectName = randomProjectName(); + + await page.goto('/projects/new#blank_project'); + await page.getByLabel('Project name').fill(projectName); + await page.getByLabel('Initialize repository with a README').setChecked(true); + await page.getByRole('button', { name: 'Create project' }).click(); + + await expect(page).toHaveURL(`/doug/${projectName}`); + + await test.step('create a file', async () => { + await page.goto(`/doug/${projectName}/-/new/main`); + + await page.getByTestId('file-name-field').fill('docs/README.md'); + await page.getByLabel('Editor content;Press Alt+F1').fill('# Docs', { force: true }); + await page.getByTestId('commit-button').click(); + + await expect(page).toHaveURL(`/doug/${projectName}/-/blob/main/docs/README.md`) + await expect(page.getByRole('heading', { level: 1 })).toContainText('Docs'); + }); + + await test.step('create an issue', async () => { + await page.goto(`/doug/${projectName}/-/issues/new`); + + await page.getByTestId('issuable-form-title-field').fill('We should write more tests!'); + + const descriptionBox = page.getByTestId('issuable-form-description-field'); + + await descriptionBox.fill(`Why are there no tests???\n\n`); + + // upload a file + const fileChooserPromise = page.waitForEvent('filechooser'); + await page.getByRole('button', { name: 'Attach a file or image' }).click(); + const fileChooser = await fileChooserPromise; + await fileChooser.setFiles(path.join(__dirname, 'data/unicorns.jpeg')); + + // check that markdown description box is updated + await expect(descriptionBox).toHaveValue(/uploads\/[a-z0-9]+\/unicorns\.jpeg/); + + await page.getByTestId('issuable-create-button').click(); + + // check that rendered image ends up in issue description + await expect(page.getByRole('img', { name: 'unicorns' })) + .toHaveAttribute('src', /uploads\/[a-z0-9]+\/unicorns\.jpeg/); + }); + + // regression test for Istio path decoding: https://github.com/defenseunicorns/uds-core/issues/288 + await test.step('fetch via API', async () => { + const projectPath = encodeURIComponent(`doug/${projectName}`); + + const res = await page.request.get(`/api/v4/projects/${projectPath}`); + + expect(res.url()).toContain('%2F'); + await expect(res).toBeOK(); + + const project = await res.json(); + + expect(project.path).toBe(projectName); + expect(project.namespace.path).toBe('doug'); + }); +}); diff --git a/tests/package-lock.json b/tests/package-lock.json new file mode 100644 index 00000000..fc17509f --- /dev/null +++ b/tests/package-lock.json @@ -0,0 +1,104 @@ +{ + "name": "uds-package-gitlab", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "uds-package-gitlab", + "license": "Apache-2.0", + "devDependencies": { + "@playwright/test": "^1.43.1", + "@types/node": "^20.12.12", + "typescript": "^5.4.5" + } + }, + "node_modules/@playwright/test": { + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz", + "integrity": "sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==", + "dev": true, + "dependencies": { + "playwright": "1.43.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@types/node": { + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz", + "integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==", + "dev": true, + "dependencies": { + "playwright-core": "1.43.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz", + "integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + } + } +} diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 00000000..cb7750cf --- /dev/null +++ b/tests/package.json @@ -0,0 +1,9 @@ +{ + "name": "uds-package-gitlab", + "license": "Apache-2.0", + "devDependencies": { + "@playwright/test": "^1.43.1", + "@types/node": "^20.12.12", + "typescript": "^5.4.5" + } +} diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts new file mode 100644 index 00000000..33e2b098 --- /dev/null +++ b/tests/playwright.config.ts @@ -0,0 +1,43 @@ +import { defineConfig, devices } from '@playwright/test'; + +export const playwrightDir = '.playwright'; +export const authFile = `${playwrightDir}/auth/user.json`; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + fullyParallel: true, + forbidOnly: !!process.env.CI, // fail CI if you accidently leave `test.only` in source + retries: process.env.CI ? 1 : 0, + workers: 1, + reporter: [ + // Reporter to use. See https://playwright.dev/docs/test-reporters + ['html', { outputFolder: `${playwrightDir}/reports`, open: 'never' }], + ['json', { outputFile: `${playwrightDir}/reports/test-results.json`, open: 'never' }], + ['list'] + ], + + outputDir: `${playwrightDir}/output`, + + use: { + baseURL: process.env.BASE_URL || 'https://gitlab.uds.dev', // for `await page.goto('/')` etc + trace: 'on-first-retry', // collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer + }, + + projects: [ + { name: 'setup', testMatch: /.*\.setup\.ts/ }, // authentication + + ...[ + 'Desktop Chrome', + 'Desktop Firefox', + ].map((p) => ({ + name: devices[p].defaultBrowserType, + dependencies: ['setup'], + use: { + ...devices[p], + storageState: authFile, + }, + })), + ], +}); diff --git a/tests/tsconfig.json b/tests/tsconfig.json new file mode 100644 index 00000000..a3b60e83 --- /dev/null +++ b/tests/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "module": "commonjs", /* Specify what module code is generated. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "strict": true, /* Enable all strict type-checking options. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +}