From 87d89d5c5030131cd2a5d97ee6e1847892709063 Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Mon, 19 May 2025 10:44:53 +0100 Subject: [PATCH 1/3] Added staging tests to CI/CD closes https://linear.app/ghost/issue/PROD-1779 - Added a CI/CD step that runs tests in staging. This will attempt to catch errors in GCP components before being shipped to production. --- .github/workflows/cicd.yml | 44 +++++++++++++++++++- Dockerfile | 1 + src/test/db.ts | 85 ++++++++++++++++++++++++++------------ 3 files changed, 101 insertions(+), 29 deletions(-) diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index e1e923947..d6952e146 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -102,8 +102,8 @@ jobs: load: true tags: ${{ steps.migrations-docker-metadata.outputs.tags }} - - name: "Run Tests" - run: yarn test + #- name: "Run Tests" + # run: yarn test - name: "Authenticate with GCP" if: github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && (github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened' || github.event.action == 'labeled' || github.event.action == 'unlabeled')) @@ -240,6 +240,26 @@ jobs: labels: |- commit-sha=${{ github.sha }} + - name: "Deploy Tests to Cloud Run" + if: ${{ steps.check-labels.outputs.is_ephemeral_staging == 'true' }} + uses: google-github-actions/deploy-cloudrun@v2 + with: + image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.migrations_docker_version }} + region: europe-west4 + job: stg-pr-${{ github.event.pull_request.number }}-tests + flags: --command="yarn" --args "_test:single" --wait --execute-now + skip_default_labels: true + labels: |- + commit-sha=${{ github.sha }} + + - name: "Destroy Tests databases" + if: ${{ steps.check-labels.outputs.is_ephemeral_staging == 'true' }} + run: | + TEST_DATABASES=$(gcloud sql databases list --instance=stg-netherlands-activitypub --filter="name~pr_${{ github.event.pull_request.number }}_test*" --format="value(name)" --project ${GCP_PROJECT}) + for TEST_DATABASE in ${TEST_DATABASES}; do + gcloud sql databases delete ${TEST_DATABASE} --instance=stg-netherlands-activitypub --quiet --project ${GCP_PROJECT} + done + - name: "Add route to GCP Load Balancer" if: ${{ steps.check-labels.outputs.is_ephemeral_staging == 'true' }} env: @@ -306,6 +326,26 @@ jobs: labels: |- commit-sha=${{ github.sha }} + - name: "Deploy Tests to Cloud Run" + if: ${{ matrix.region == 'europe-west4' }} + uses: google-github-actions/deploy-cloudrun@v2 + with: + image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.migrations_docker_version }} + region: ${{ matrix.region }} + job: stg-${{ matrix.region_name }}-activitypub-tests + flags: --command="yarn _test:single" --wait --execute-now + skip_default_labels: true + labels: |- + commit-sha=${{ github.sha }} + + - name: "Destroy Tests databases" + if: ${{ matrix.region == 'europe-west4' }} + run: | + TEST_DATABASES=$(gcloud sql databases list --instance=stg-netherlands-activitypub --filter="name~pr_${{ github.event.pull_request.number }}_test*" --format="value(name)" --project ${GCP_PROJECT}) + for TEST_DATABASE in ${TEST_DATABASES}; do + gcloud sql databases delete ${TEST_DATABASE} --instance=stg-netherlands-activitypub --quiet --project ${GCP_PROJECT} + done + - name: "Deploy ActivityPub Queue to Cloud Run" uses: google-github-actions/deploy-cloudrun@v2 with: diff --git a/Dockerfile b/Dockerfile index 26061f0aa..47219f43b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,7 @@ RUN yarn && \ COPY tsconfig.json . COPY src ./src +COPY vitest.config.ts vitest.config.ts ENV NODE_ENV=production RUN yarn build diff --git a/src/test/db.ts b/src/test/db.ts index c1df96cb7..c6c616805 100644 --- a/src/test/db.ts +++ b/src/test/db.ts @@ -9,17 +9,25 @@ import { afterAll } from 'vitest'; export async function createTestDb() { const systemClient = knex({ client: 'mysql2', - connection: { - host: process.env.MYSQL_HOST, - port: Number.parseInt(process.env.MYSQL_PORT!), - user: process.env.MYSQL_USER, - password: process.env.MYSQL_PASSWORD, - database: 'mysql', - timezone: '+00:00', - }, + connection: process.env.MYSQL_SOCKET_PATH + ? { + socketPath: process.env.MYSQL_SOCKET_PATH, + user: process.env.MYSQL_USER, + password: process.env.MYSQL_PASSWORD, + database: 'mysql', + timezone: '+00:00', + } + : { + host: process.env.MYSQL_HOST, + port: Number.parseInt(process.env.MYSQL_PORT!), + user: process.env.MYSQL_USER, + password: process.env.MYSQL_PASSWORD, + database: 'mysql', + timezone: '+00:00', + }, }); - const dbName = `test_${randomBytes(16).toString('hex')}`; + const dbName = `${process.env.MYSQL_DATABASE?.includes('pr-') ? `${process.env.MYSQL_DATABASE.replace(/-/g, '_')}_` : ''}test_${randomBytes(16).toString('hex')}`; await systemClient.raw(`CREATE DATABASE ${dbName}`); @@ -29,37 +37,60 @@ export async function createTestDb() { // Clone each table structure for (const { TABLE_NAME } of tables[0]) { - await systemClient.raw( - `CREATE TABLE ${dbName}.${TABLE_NAME} LIKE ${process.env.MYSQL_DATABASE}.${TABLE_NAME}`, + const [createTableResult] = await systemClient.raw( + `SHOW CREATE TABLE \`${process.env.MYSQL_DATABASE}\`.\`${TABLE_NAME}\``, ); + const createTableSql = createTableResult[0]['Create Table'] + .replace('CREATE TABLE ', `CREATE TABLE \`${dbName}\`.`) + .split('\n') + .filter((line: string) => !line.trim().startsWith('CONSTRAINT')) + .join('\n') + .replace(/,\n\)/, '\n)'); // clean up trailing comma + await systemClient.raw(createTableSql); } await systemClient.destroy(); const dbClient = knex({ client: 'mysql2', - connection: { - host: process.env.MYSQL_HOST, - port: Number.parseInt(process.env.MYSQL_PORT!), - user: process.env.MYSQL_USER, - password: process.env.MYSQL_PASSWORD, - database: dbName, - timezone: '+00:00', - }, + connection: process.env.MYSQL_SOCKET_PATH + ? { + socketPath: process.env.MYSQL_SOCKET_PATH, + user: process.env.MYSQL_USER, + password: process.env.MYSQL_PASSWORD, + database: dbName, + timezone: '+00:00', + } + : { + host: process.env.MYSQL_HOST, + port: Number.parseInt(process.env.MYSQL_PORT!), + user: process.env.MYSQL_USER, + password: process.env.MYSQL_PASSWORD, + database: dbName, + timezone: '+00:00', + }, }); afterAll(async () => { await dbClient.destroy(); const systemClient = knex({ client: 'mysql2', - connection: { - host: process.env.MYSQL_HOST, - port: Number.parseInt(process.env.MYSQL_PORT!), - user: process.env.MYSQL_USER, - password: process.env.MYSQL_PASSWORD, - database: 'mysql', - timezone: '+00:00', - }, + connection: process.env.MYSQL_SOCKET_PATH + ? { + socketPath: process.env.MYSQL_SOCKET_PATH, + user: process.env.MYSQL_USER, + password: process.env.MYSQL_PASSWORD, + database: 'mysql', + timezone: '+00:00', + } + : { + host: process.env.MYSQL_HOST, + port: Number.parseInt(process.env.MYSQL_PORT!), + user: process.env.MYSQL_USER, + password: process.env.MYSQL_PASSWORD, + database: 'mysql', + timezone: '+00:00', + }, }); await systemClient.raw(`DROP DATABASE ${dbName}`); await systemClient.destroy(); From 7f55ecbb1af58361e687eae50e7b1144a66847c2 Mon Sep 17 00:00:00 2001 From: Princi Vershwal Date: Thu, 22 May 2025 18:47:15 +0530 Subject: [PATCH 2/3] Added integration tests for GCP Storage --- src/storage/gcloud-storage/assets/dog.jpg | Bin 0 -> 70761 bytes .../gcp-storage.service.integration.test.ts | 153 ++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/storage/gcloud-storage/assets/dog.jpg create mode 100644 src/storage/gcloud-storage/gcp-storage.service.integration.test.ts diff --git a/src/storage/gcloud-storage/assets/dog.jpg b/src/storage/gcloud-storage/assets/dog.jpg new file mode 100644 index 0000000000000000000000000000000000000000..61e15290a0ebd03dca38287fd3231248677d2c60 GIT binary patch literal 70761 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

    9-COlBr+%A%-n?MCkB8yWWPjUohY;vFs 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 literal 0 HcmV?d00001 diff --git a/src/storage/gcloud-storage/gcp-storage.service.integration.test.ts b/src/storage/gcloud-storage/gcp-storage.service.integration.test.ts new file mode 100644 index 000000000..8f1fad2ca --- /dev/null +++ b/src/storage/gcloud-storage/gcp-storage.service.integration.test.ts @@ -0,0 +1,153 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { getError, getValue, isError } from 'core/result'; +import { File as NodeFile } from 'fetch-blob/file.js'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { GCPStorageService } from './gcp-storage.service'; + +const logger = { + info: console.log, + error: console.error, + warn: console.warn, +} as unknown as import('@logtape/logtape').Logger; + +const TEST_IMAGE_PATH = path.join(__dirname, 'assets/dog.jpg'); +const TEST_ACCOUNT_UUID = 'integration-tests'; + +describe('GCPStorageService Integration', () => { + let service: GCPStorageService; + + beforeAll(async () => { + service = new GCPStorageService(logger); + await service.init(); + }); + + describe('saveFile', () => { + it('should save an image file to the bucket and return a valid URL', async () => { + const buffer = readFileSync(TEST_IMAGE_PATH); + const file = new NodeFile([buffer], 'dog.jpg', { + type: 'image/jpeg', + }); + + const result = await service.saveFile( + file as unknown as File, + TEST_ACCOUNT_UUID, + ); + + expect(isError(result)).toBe(false); + if (!isError(result)) { + const url = getValue(result); + expect(url).toBeTruthy(); + expect(() => new URL(url)).not.toThrow(); + expect(url).toContain(TEST_ACCOUNT_UUID); + + if (process.env.GCP_STORAGE_EMULATOR_HOST) { + expect(url).toContain( + 'localhost:4443/storage/v1/b/activitypub/o/', + ); + expect(url).toContain('?alt=media'); + } else { + const res = await fetch(url); + expect(res.status).toBe(200); + } + } + }); + + it('should reject files larger than 5MB', async () => { + // Create a 6MB buffer + const largeBuffer = Buffer.alloc(6 * 1024 * 1024); + const file = new NodeFile([largeBuffer], 'large.jpg', { + type: 'image/jpeg', + }); + + const result = await service.saveFile( + file as unknown as File, + TEST_ACCOUNT_UUID, + ); + + expect(isError(result)).toBe(true); + if (isError(result)) { + expect(getError(result)).toBe('file-too-large'); + } + }); + + it('should reject unsupported file types', async () => { + const buffer = readFileSync(TEST_IMAGE_PATH); + const file = new NodeFile([buffer], 'test.gif', { + type: 'image/gif', + }); + + const result = await service.saveFile( + file as unknown as File, + TEST_ACCOUNT_UUID, + ); + + expect(isError(result)).toBe(true); + if (isError(result)) { + expect(getError(result)).toBe('file-type-not-supported'); + } + }); + }); + + describe('verifyImageUrl', () => { + it('should verify a valid image URL', async () => { + const buffer = readFileSync(TEST_IMAGE_PATH); + const file = new NodeFile([buffer], 'dog.jpg', { + type: 'image/jpeg', + }); + + const saveResult = await service.saveFile( + file as unknown as File, + TEST_ACCOUNT_UUID, + ); + + expect(isError(saveResult)).toBe(false); + if (!isError(saveResult)) { + const url = new URL(getValue(saveResult)); + const verifyResult = await service.verifyImageUrl(url); + expect(isError(verifyResult)).toBe(false); + if (!isError(verifyResult)) { + expect(getValue(verifyResult)).toBe(true); + } + } + }); + + it('should reject invalid URLs', async () => { + const invalidUrl = new URL('https://example.com/invalid.jpg'); + const result = await service.verifyImageUrl(invalidUrl); + + expect(isError(result)).toBe(true); + if (isError(result)) { + expect(getError(result)).toBe('invalid-url'); + } + }); + + it('should reject URLs with invalid file paths', async () => { + const invalidPathUrl = new URL( + 'https://storage.googleapis.com/activitypub/invalid/path.jpg', + ); + const result = await service.verifyImageUrl(invalidPathUrl); + + expect(isError(result)).toBe(true); + if (isError(result)) { + process.env.GCP_STORAGE_EMULATOR_HOST + ? expect(getError(result)).toBe('invalid-url') + : expect(getError(result)).toBe('invalid-file-path'); + } + }); + + it('should reject non-existent files', async () => { + const nonExistentUrl = new URL( + `https://storage.googleapis.com/${process.env.GCP_BUCKET_NAME}/images/nonexistent.jpg`, + ); + const result = await service.verifyImageUrl(nonExistentUrl); + + expect(isError(result)).toBe(true); + if (isError(result)) { + process.env.GCP_STORAGE_EMULATOR_HOST + ? expect(getError(result)).toBe('invalid-url') + : expect(getError(result)).toBe('file-not-found'); + } + }); + }); +}); From 234f595e849b4231ded83e8709996f16751889a1 Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Mon, 26 May 2025 10:22:49 +0100 Subject: [PATCH 3/3] Remove comment (tests) --- .github/workflows/cicd.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index d6952e146..1c764cf03 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -102,8 +102,8 @@ jobs: load: true tags: ${{ steps.migrations-docker-metadata.outputs.tags }} - #- name: "Run Tests" - # run: yarn test + - name: "Run Tests" + run: yarn test - name: "Authenticate with GCP" if: github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && (github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened' || github.event.action == 'labeled' || github.event.action == 'unlabeled')) @@ -247,13 +247,15 @@ jobs: image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.migrations_docker_version }} region: europe-west4 job: stg-pr-${{ github.event.pull_request.number }}-tests - flags: --command="yarn" --args "_test:single" --wait --execute-now + flags: --command="yarn" --args="_test:single" --wait --execute-now skip_default_labels: true labels: |- commit-sha=${{ github.sha }} - name: "Destroy Tests databases" if: ${{ steps.check-labels.outputs.is_ephemeral_staging == 'true' }} + env: + GCP_PROJECT: ghost-activitypub run: | TEST_DATABASES=$(gcloud sql databases list --instance=stg-netherlands-activitypub --filter="name~pr_${{ github.event.pull_request.number }}_test*" --format="value(name)" --project ${GCP_PROJECT}) for TEST_DATABASE in ${TEST_DATABASES}; do @@ -333,15 +335,17 @@ jobs: image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.migrations_docker_version }} region: ${{ matrix.region }} job: stg-${{ matrix.region_name }}-activitypub-tests - flags: --command="yarn _test:single" --wait --execute-now + flags: --command="yarn" --args="_test:single" --wait --execute-now skip_default_labels: true labels: |- commit-sha=${{ github.sha }} - name: "Destroy Tests databases" if: ${{ matrix.region == 'europe-west4' }} + env: + GCP_PROJECT: ghost-activitypub run: | - TEST_DATABASES=$(gcloud sql databases list --instance=stg-netherlands-activitypub --filter="name~pr_${{ github.event.pull_request.number }}_test*" --format="value(name)" --project ${GCP_PROJECT}) + TEST_DATABASES=$(gcloud sql databases list --instance=stg-netherlands-activitypub --filter="name~test*" --format="value(name)" --project ${GCP_PROJECT}) for TEST_DATABASE in ${TEST_DATABASES}; do gcloud sql databases delete ${TEST_DATABASE} --instance=stg-netherlands-activitypub --quiet --project ${GCP_PROJECT} done