Skip to content

Commit 5f2de62

Browse files
authored
Deploy May 14, 2024 (#483)
2 parents 98caf82 + c3e9f69 commit 5f2de62

File tree

7 files changed

+869
-844
lines changed

7 files changed

+869
-844
lines changed

.circleci/config.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ version: 2.1
33
executors:
44
node:
55
docker:
6-
- image: cimg/node:18.14
6+
- image: cimg/node:18.19
77
environment:
88
IMAGE_NAME: mozilla/profiler-server
99

@@ -12,7 +12,7 @@ executors:
1212
# preinstalled, but otherwise the exact version for node isn't important.
1313
python:
1414
docker:
15-
- image: cimg/python:3.10-node
15+
- image: cimg/python:3.11-node
1616

1717
orbs:
1818
shellcheck: circleci/[email protected]
@@ -166,8 +166,7 @@ jobs:
166166
- attach_workspace:
167167
at: /tmp/workspace
168168
# This sets up a remote environment that's necessary to run docker commands.
169-
- setup_remote_docker:
170-
version: 19.03.12
169+
- setup_remote_docker
171170
- run:
172171
name: Load archived Docker image
173172
command: docker load -i /tmp/workspace/image.tar

__mocks__/@google-cloud/storage.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ class MockFile {
9696
delete this.bucket.files[this.name];
9797
return Promise.resolve();
9898
}
99+
100+
if (this.name === 'THROW_ERROR') {
101+
throw new Error('Unexpected error!');
102+
}
103+
99104
// eslint-disable-next-line prefer-promise-reject-errors
100105
return Promise.reject({
101106
code: 404,

package.json

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,42 +35,42 @@
3535
"ts-generate-types": "npx --yes dts-gen -m"
3636
},
3737
"devDependencies": {
38-
"@babel/cli": "^7.23.4",
39-
"@babel/core": "^7.23.7",
40-
"@babel/eslint-parser": "^7.23.3",
41-
"@babel/eslint-plugin": "^7.23.5",
42-
"@babel/node": "^7.22.19",
38+
"@babel/cli": "^7.24.5",
39+
"@babel/core": "^7.24.5",
40+
"@babel/eslint-parser": "^7.24.5",
41+
"@babel/eslint-plugin": "^7.24.5",
42+
"@babel/node": "^7.23.9",
4343
"@babel/plugin-proposal-class-properties": "^7.18.6",
4444
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
45-
"@babel/preset-env": "^7.23.7",
46-
"@babel/preset-typescript": "^7.23.3",
45+
"@babel/preset-env": "^7.24.5",
46+
"@babel/preset-typescript": "^7.24.1",
4747
"@types/content-type": "^1.1.8",
4848
"@types/convict": "^6.1.6",
49-
"@types/jest": "^29.5.11",
50-
"@types/jsonwebtoken": "^9.0.5",
49+
"@types/jest": "^29.5.12",
50+
"@types/jsonwebtoken": "^9.0.6",
5151
"@types/koa__cors": "^4.0.3",
5252
"@types/koa__router": "^12.0.4",
53-
"@types/node": "^20.10.5",
53+
"@types/node": "^20.12.7",
5454
"@types/node-fetch": "^2.6.2",
5555
"@types/supertest": "^6.0.2",
56-
"@typescript-eslint/eslint-plugin": "^6.13.2",
57-
"@typescript-eslint/parser": "^6.13.2",
56+
"@typescript-eslint/eslint-plugin": "^7.7.0",
57+
"@typescript-eslint/parser": "^7.7.0",
5858
"babel-jest": "^29.7.0",
5959
"devtools-license-check": "^0.9.0",
60-
"eslint": "^8.56.0",
60+
"eslint": "^8.57.0",
6161
"eslint-config-prettier": "^9.1.0",
6262
"eslint-plugin-import": "^2.29.1",
6363
"husky": "^4.3.8",
6464
"jest": "^29.7.0",
65-
"lockfile-lint": "^4.12.1",
65+
"lockfile-lint": "^4.13.2",
6666
"mkdirp": "^3.0.1",
67-
"nock": "^13.4.0",
68-
"nodemon": "^3.0.2",
67+
"nock": "^13.5.4",
68+
"nodemon": "^3.1.0",
6969
"npm-run-all": "^4.1.5",
70-
"prettier": "^3.1.1",
70+
"prettier": "^3.2.5",
7171
"rimraf": "^5.0.5",
72-
"supertest": "^6.3.3",
73-
"typescript": "^5.3.3"
72+
"supertest": "^7.0.0",
73+
"typescript": "^5.4.5"
7474
},
7575
"husky": {
7676
"hooks": {
@@ -81,14 +81,14 @@
8181
}
8282
},
8383
"dependencies": {
84-
"@google-cloud/storage": "^7.7.0",
84+
"@google-cloud/storage": "^7.10.1",
8585
"@koa/cors": "^4.0.0",
8686
"@koa/router": "^12.0.1",
8787
"content-type": "^1.0.5",
8888
"convict": "^6.2.4",
89-
"dotenv": "^16.3.1",
89+
"dotenv": "^16.4.5",
9090
"jsonwebtoken": "^9.0.2",
91-
"koa": "^2.15.0",
91+
"koa": "^2.15.3",
9292
"koa-helmet": "^7.0.2",
9393
"koa-json-body": "^5.3.0",
9494
"koa-jwt": "^4.0.4",

src/routes/profile.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
} from '../utils/errors';
1616
import { config } from '../config';
1717
import { create as gcsStorageCreate } from '../logic/gcs';
18-
import { ErrorResponse } from '@google-cloud/storage';
18+
import { ApiError } from '@google-cloud/storage';
1919

2020
export function profileRoutes() {
2121
const router = new Router();
@@ -90,15 +90,24 @@ export function profileRoutes() {
9090
await storage.deleteFile(profileToken);
9191
} catch (error: any) {
9292
if ('code' in error && 'message' in error) {
93-
const { code } = error as ErrorResponse;
93+
const { code } = error as ApiError;
9494
if (code === 404) {
95+
log.info(
96+
'gcs_deleteProfileNotFound',
97+
'The profile data that we attempted to delete from Google Cloud Storage was not found.'
98+
);
99+
95100
throw new NotFoundError(
96101
'That profile was most likely already deleted.'
97102
);
98103
}
99-
throw error;
100104
}
101-
console.log(error);
105+
log.warn(
106+
'gcs_deleteProfileUnknownError',
107+
'An unknown error occurred while deleting the profile from Google Cloud Storage: ' +
108+
String(error)
109+
);
110+
throw error;
102111
}
103112

104113
ctx.body = 'Profile successfully deleted.';

src/types/@google_cloud__storage.d.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

test/api/profile.test.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe('DELETE /profile', () => {
4646
return { acceptHeader, agent, postProfileToCompressedStore };
4747
}
4848

49-
it('gives a 200 response when successfully uploading a profile', async function () {
49+
it('gives a 200 response when successfully deleting a profile', async function () {
5050
const { agent, acceptHeader, postProfileToCompressedStore } = setup();
5151

5252
const { profileToken, jwtToken } = await postProfileToCompressedStore();
@@ -199,6 +199,38 @@ describe('DELETE /profile', () => {
199199
expect(process.stdout.write).toHaveBeenCalledWith(
200200
expect.stringMatching(/server_error.*NotFoundError/)
201201
);
202+
expect(process.stdout.write).toHaveBeenCalledWith(
203+
expect.stringMatching(
204+
'FirefoxProfiler.routes.profile.delete.gcs_deleteProfileNotFound'
205+
)
206+
);
207+
});
208+
209+
it('logs appropriately for any error', async function () {
210+
jest
211+
.spyOn(process.stdout, 'write')
212+
.mockImplementation((_: string | Uint8Array) => true);
213+
const { agent, acceptHeader } = setup();
214+
215+
// Generate a random token.
216+
const profileToken = 'THROW_ERROR';
217+
const jwtToken = generateToken({ profileToken });
218+
219+
await agent
220+
.delete(`/profile/${profileToken}`)
221+
.accept(acceptHeader)
222+
.set('Authorization', `Bearer ${jwtToken}`)
223+
.send()
224+
.expect(500, 'Internal Server Error');
225+
226+
expect(process.stdout.write).toHaveBeenCalledWith(
227+
expect.stringMatching(/server_error.*Unexpected error/)
228+
);
229+
expect(process.stdout.write).toHaveBeenCalledWith(
230+
expect.stringMatching(
231+
'FirefoxProfiler.routes.profile.delete.gcs_deleteProfileUnknownError'
232+
)
233+
);
202234
});
203235

204236
it('implements security headers', async () => {

0 commit comments

Comments
 (0)