Skip to content

Commit 18d2e86

Browse files
authored
Merge pull request #6209 from mozilla/integration-tests
feat(tests): infrastructure for integration tests
2 parents 80dcf4c + 605ac4c commit 18d2e86

File tree

10 files changed

+276
-12
lines changed

10 files changed

+276
-12
lines changed

.env

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ NEXTAUTH_URL=http://localhost:6060
99
DISABLE_DOCKERFLOW=
1010

1111
# Database server
12-
DATABASE_URL=postgres://postgres@localhost:5432/blurts
12+
DATABASE_URL=postgres://blurts:blurts@localhost:5432/blurts
1313
# How many seconds can unverified subscribers remain in the database
1414
DELETE_UNVERIFIED_SUBSCRIBERS_TIMER=86400
1515

@@ -145,9 +145,9 @@ MONTHLY_SCANS_QUOTA=
145145
STATS_TOKEN=
146146

147147
# GCP PubSub Project ID and subscription name
148-
GCP_PUBSUB_PROJECT_ID=
149-
GCP_PUBSUB_TOPIC_NAME=
150-
GCP_PUBSUB_SUBSCRIPTION_NAME=
148+
GCP_PUBSUB_PROJECT_ID=your-project-name
149+
GCP_PUBSUB_TOPIC_NAME=hibp-breaches
150+
GCP_PUBSUB_SUBSCRIPTION_NAME=hibp-cron
151151

152152
# Randomly-generated UUIDv5 namespace, until/unless we are approved to use FxA UID for Nimbus User ID.
153153
NIMBUS_UUID_NAMESPACE=00000000-0000-0000-0000-000000000000

.env.ci

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# local, heroku, stage, production
2+
APP_ENV=local
3+
SERVER_URL=http://localhost:6060
4+
PORT=6060
5+
NEXTAUTH_URL=http://localhost:6060
6+
NODE_ENV=development
7+
8+
# 1: disables the dockerflow endpoints
9+
# see: https://github.com/mozilla-services/Dockerflow#containerized-app-requirements
10+
DISABLE_DOCKERFLOW=
11+
12+
# Database server
13+
DATABASE_URL=postgres://blurts:blurts@localhost:5432/test-blurts
14+
# How many seconds can unverified subscribers remain in the database
15+
DELETE_UNVERIFIED_SUBSCRIBERS_TIMER=86400
16+
17+
# How many seconds until page tokens expire?
18+
PAGE_TOKEN_TIMER=0
19+
20+
# Email server
21+
SMTP_URL=
22+
# From: address used in emails
23+
EMAIL_FROM=
24+
# https://docs.aws.amazon.com/ses/latest/DeveloperGuide/using-configuration-sets.html
25+
SES_CONFIG_SET=
26+
# 1: only log messages coming back from SES
27+
SES_NOTIFICATION_LOG_ONLY=
28+
29+
# s3 bucket for cdn
30+
AWS_ACCESS_KEY_ID=
31+
AWS_SECRET_ACCESS_KEY=
32+
AWS_REGION=
33+
S3_BUCKET=
34+
35+
# Firefox Accounts OAuth
36+
FXA_SETTINGS_URL=https://accounts.stage.mozaws.net/settings
37+
38+
OAUTH_CLIENT_ID=edd29a80019d61a1
39+
OAUTH_CLIENT_SECRET=get-this-from-groovecoder-or-fxmonitor-engineering
40+
OAUTH_AUTHORIZATION_URI=https://accounts.stage.mozaws.net/authorization
41+
OAUTH_METRICS_FLOW_URI=https://accounts.stage.mozaws.net/metrics-flow
42+
OAUTH_PROFILE_URI=https://profile.stage.mozaws.net/v1/profile
43+
OAUTH_TOKEN_URI=https://oauth.stage.mozaws.net/v1/token
44+
OAUTH_ACCOUNT_URI="https://api-accounts.stage.mozaws.net/v1"
45+
46+
# HIBP API for breach data
47+
# How many seconds to wait before refreshing upstream breach data from HIBP
48+
HIBP_RELOAD_BREACHES_TIMER=600
49+
# HIBP API for range search and subscription
50+
HIBP_KANON_API_ROOT=https://enterprise.stage-api.haveibeenpwned.com
51+
HIBP_KANON_API_TOKEN=
52+
HIBP_API_ROOT=https://haveibeenpwned.com/api/v2
53+
HIBP_API_TOKEN=
54+
# How many milliseconds to wait before retrying an HIBP request
55+
HIBP_THROTTLE_DELAY=2000
56+
# Max number of times to try an HIBP request before throwing error
57+
HIBP_THROTTLE_MAX_TRIES=5
58+
# Authorization token for HIBP to present to /hibp/notify endpoint
59+
HIBP_NOTIFY_TOKEN=unsafe-default-token-for-dev
60+
# Domains we prefer to not link to
61+
HIBP_BREACH_DOMAIN_BLOCKLIST=a-blocked-domain.com,another-blocked-domain.org
62+
63+
# OneRep API for exposure scanning
64+
ONEREP_API_BASE=https://mozilla.api.onerep.com
65+
ONEREP_API_KEY=
66+
ONEREP_WEBHOOK_SECRET="unsafe-default-secret-for-dev"
67+
68+
# Firefox Remote Settings
69+
FX_REMOTE_SETTINGS_WRITER_SERVER=https://settings-writer.prod.mozaws.net/v1
70+
FX_REMOTE_SETTINGS_WRITER_USER=
71+
FX_REMOTE_SETTINGS_WRITER_PASS=
72+
73+
# DSN for Sentry error and event capturing
74+
# e.g., SENTRY_DSN=https://{key}@sentry.prod.mozaws.net/408
75+
SENTRY_DSN=
76+
SENTRY_DSN_LEGACY=
77+
78+
BREACH_RESOLUTION_ENABLED=1
79+
PRODUCT_PROMOS_ENABLED=1
80+
81+
# Experiment Flag
82+
EXPERIMENT_ACTIVE=0
83+
84+
REDIS_URL=redis://redis.mock
85+
86+
SUPPORTED_LOCALES=cs,cy,da,de,el,en,en-CA,en-GB,es-AR,es-CL,es-ES,es-MX,fi,fr,fy-NL,gn,hu,kab,ia,id,it,ja,ko,nl,nn-NO,pt-BR,pt-PT,ru,sk,sl,sq,sv-SE,th,tr,uk,vi,zh-CN,zh-TW
87+
88+
# Locales blocked from viewing Mozilla VPN promos. Use CSV without whitespace.
89+
VPN_PROMO_BLOCKED_LOCALES=zh-CN
90+
91+
# MaxMind GeoLite2 geolocation service used for VPN Banner
92+
# For Heroku deploys, the following 3 vars are generated automatically via Buildpack https://github.com/HiMamaInc/heroku-buildpack-geoip-geolite2
93+
# Staging and production environments will need variables set manually
94+
# Local environment uses a test database with limited data (preset here)
95+
GEOIP_GEOLITE2_PATH=./tests/mmdb/
96+
GEOIP_GEOLITE2_CITY_FILENAME=GeoLite2-City-Test.mmdb
97+
GEOIP_GEOLITE2_COUNTRY_FILENAME=GeoLite2-Country-Test.mmdb
98+
99+
# Educational video src urls, hosted by SRE team on a CDN
100+
EDUCATION_VIDEO_URL_RELAY=https://monitor.cdn.mozilla.net/videos/FF_Relay_version_02.mp4
101+
EDUCATION_VIDEO_URL_VPN=https://monitor.cdn.mozilla.net/videos/Mozilla_VPN.mp4
102+
103+
# Email addresses that are allowed to test and send emails
104+
ADMINS=
105+
106+
# Enable monthly cron-job, currently for sending unresolved breach reminder emails
107+
MONTHLY_CRON_ENABLED=
108+
109+
# Functional tests
110+
E2E_TEST_ENV=ci # need to not be 'local' because of imports
111+
E2E_TEST_SECRET=test-secret
112+
E2E_TEST_ACCOUNT_BASE_EMAIL=test-account
113+
E2E_TEST_ACCOUNT_BASE_PASSWORD=test-password
114+
115+
# Monitor Premium features
116+
# Link to start user on the subscription process. PREMIUM_ENABLED must be set to `true`.
117+
SUBSCRIPTION_BILLING_AMOUNT_MONTHLY_US=42.42
118+
SUBSCRIPTION_BILLING_AMOUNT_BUNDLE_INDIVIDUAL_MONTHLY_US=424
119+
SUBSCRIPTION_BILLING_AMOUNT_BUNDLE_MONTHLY_US=42
120+
121+
# SubPlat 2.0 URL, product and plan IDs, used for Plus subscriptions:
122+
FXA_SUBSCRIPTIONS_URL=https://accounts.stage.mozaws.net/subscriptions
123+
PREMIUM_PRODUCT_ID=prod_NErZh679W62lai
124+
PREMIUM_PLAN_ID_MONTHLY_US=price_1MUNq0Kb9q6OnNsL4BoJgepf
125+
PREMIUM_PLAN_ID_YEARLY_US=price_1NvqawKb9q6OnNsLRTnYrtrV
126+
127+
# SubPlat 3.0 URL and offering ID, used for Plus subscriptions:
128+
SUBPLAT_SUBSCRIPTIONS_URL=https://payments-next.stage.fxa.nonprod.webservices.mozgcp.net
129+
SUBPLAT_MONITOR_OFFERING_ID=monitorplusstage
130+
SUBPLAT_BUNDLE_OFFERING_ID=privacyprotectionplan/yearly
131+
SUBPLAT_BUNDLE_PRODUCT_ID=prod_SFb8iVuZIOPREe
132+
SUBPLAT_BUNDLE_PRICE_ID=price_1RMAopKb9q6OnNsLSGe1vLtt
133+
134+
# Mozilla privacy product URLs
135+
FIREFOX_RELAY_LANDING_URL=https://stage.fxprivaterelay.nonprod.cloudops.mozgcp.net
136+
MOZILLA_VPN_LANDING_URL=https://www-dev.allizom.org/products/vpn
137+
138+
# This date is used to direct users who signed up after data broker scanning
139+
# was released to the welcome flow. Users who had signed up before and thus
140+
# have seen data breach results before, will be able to see their known breaches
141+
# first:
142+
BROKER_SCAN_RELEASE_DATE=2024-02-06
143+
144+
MONTHLY_SUBSCRIBERS_QUOTA=
145+
MONTHLY_SCANS_QUOTA=
146+
STATS_TOKEN=
147+
148+
# GCP PubSub Project ID and subscription name
149+
GCP_PUBSUB_PROJECT_ID=your-project-name
150+
GCP_PUBSUB_TOPIC_NAME=hibp-breaches
151+
GCP_PUBSUB_SUBSCRIPTION_NAME=hibp-cron
152+
PUBSUB_HOST=localhost
153+
PUBSUB_PORT=8085
154+
PUBSUB_EMULATOR_HOST="${PUBSUB_HOST}:${PUBSUB_PORT}"
155+
156+
157+
# Randomly-generated UUIDv5 namespace, until/unless we are approved to use FxA UID for Nimbus User ID.
158+
NIMBUS_UUID_NAMESPACE=00000000-0000-0000-0000-000000000000
159+
NIMBUS_SIDECAR_URL=http://localhost:8001
160+
161+
# The maximum number of jobs that the email breach alert worker will process.
162+
EMAIL_BREACH_ALERT_MAX_MESSAGES = 10000
163+
164+
# The maximum number of scans and profiles allowed. May be used for alerts, and for redirecting to waitlist.
165+
MAX_MANUAL_SCANS=100
166+
MAX_INITIAL_SCANS=100
167+
MAX_PROFILES_ACTIVATED=100
168+
MAX_PROFILES_CREATED=100
169+
170+
# Used during CI to upload sourcemaps to Sentry.
171+
UPLOAD_SENTRY_SOURCEMAPS=false
172+
SENTRY_AUTH_TOKEN=
173+
174+
# Whether GA4 sends data or not. NOTE: must be set in build environment.
175+
NEXT_PUBLIC_GA4_DEBUG_MODE=true
176+
177+
GA4_API_SECRET=unsafe-default-secret-for-dev
178+
179+
# Data broker removal estimates data
180+
DATA_BROKER_REMOVAL_ESTIMATES_DATA=[]
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: "Test Integrations"
2+
permissions: {}
3+
4+
on:
5+
push:
6+
branches: [ main ]
7+
pull_request:
8+
branches: [ main ]
9+
10+
jobs:
11+
test-integrations:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v5
15+
with:
16+
persist-credentials: false
17+
18+
# Log into Docker Hub to avoid getting rate-limited
19+
- name: Login to Docker Hub
20+
uses: docker/login-action@v3
21+
with:
22+
username: ${{ secrets.DOCKER_USERNAME }}
23+
password: ${{ secrets.DOCKER_PASSWORD }}
24+
25+
# Kick off starting docker compose first, since it can take a bit and can run in the background
26+
- name: Start Docker Compose services
27+
run: docker compose --env-file=./.env.ci up -d
28+
29+
# While we wait for docker compose to be healthy we install node and needed packages for this service
30+
- name: Set up node
31+
uses: actions/setup-node@v5
32+
with:
33+
node-version: 20.19.x
34+
35+
- name: Install dependencies
36+
run: npm ci
37+
38+
# Wait for the docker services we started earlier to all be healthy
39+
- name: Wait for services to be healthy
40+
run: docker compose --env-file=./.env.ci up --wait
41+
42+
- name: Set up postgres
43+
run: npm run db:migrate
44+
env:
45+
DATABASE_URL: postgres://blurts:blurts@localhost:5432/test-blurts
46+
47+
# Let's run those integration tests!
48+
- name: Run service integration tests
49+
run: npm run test-integrations

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ You can also enforce the alert being sent for a specific email address via the
295295
# export env var first to persist between runs
296296
297297
HIBP_TEST_EMAIL="[email protected]"; \
298-
HASH=$(echo -n "$HIBP_TEST_EMAIL" | sha1sum | awk '{print toupper($1)}'); \
298+
HASH=$(echo -n "$HIBP_TEST_EMAIL" | sha1sum | awk '{print $1}'); \
299299
PREFIX=${HASH:0:7}; \
300300
SUFFIX=${HASH:7}; \
301301
curl -d "{\"breachName\": \"000webhost\", \"hashPrefix\": \"$PREFIX\", \"hashSuffixes\": [\"$SUFFIX\"]}" \

jest.config.cjs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,7 @@ const customJestConfig = {
187187
// testLocationInResults: false,
188188

189189
// The glob patterns Jest uses to detect test files
190-
// testMatch: [
191-
// "**/__tests__/**/*.[jt]s?(x)",
192-
// "**/?(*.)+(spec|test).[tj]s?(x)"
193-
// ],
190+
testMatch: ["**/src/**/?(*.)+(spec|test|integration).[tj]s?(x)"],
194191

195192
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
196193
testPathIgnorePatterns: ["/node_modules/", "/dist/"],

jest.setup.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,8 @@ jest.mock("./src/envVars", () => {
5555
getEnvVarsOrThrow: () => process.env,
5656
};
5757
});
58+
59+
// Avoiding putting in the env file in case this gets loaded into prod
60+
// TODO: Centralize and streamline configuration for environments
61+
// mozilla-hub.atlassian.net/browse/MNTOR-5089
62+
https: process.env.PUBSUB_EMULATOR_HOST = "localhost:8085";

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"start": "next start",
2626
"lint": "stylelint '**/*.scss' && prettier --check './src' && eslint --max-warnings=0 . && tsc -p tsconfig.json --noEmit && npm run validate-nimbus",
2727
"fix": "prettier --write './src' && eslint --fix . && stylelint --fix '**/*.scss'",
28-
"test": "npm run build-nimbus && jest",
28+
"test": "npm run build-nimbus && jest \"\\.(spec|test)\\.ts\"",
29+
"test-integrations": "npm run build-nimbus && jest \"\\.integration\\.ts\" --coverage=false --runInBand",
2930
"functional-tests": "playwright test functional-tests/ --config=functional-tests/playwright.config.ts",
3031
"functional-tests:debug": "playwright test functional-tests/ --config=functional-tests/playwright.config.ts --ui",
3132
"cron:first-data-broker-removal-fixed": "node dist/scripts/cronjobs/firstDataBrokerRemovalFixed.js",

src/db/knexfile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const TESTS_CONFIG = {
4343
connection: testConnectionObj,
4444
};
4545

46-
let exportConfig = NODE_ENV === "tests" ? TESTS_CONFIG : RUNTIME_CONFIG;
46+
let exportConfig = NODE_ENV === "test" ? TESTS_CONFIG : RUNTIME_CONFIG;
4747

4848
if (APP_ENV === "cloudrun") {
4949
// @ts-ignore TODO: Check if this typing error is correct, or if the types are wrong?
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import { Knex } from "knex";
6+
import createDbConnection from "../../db/connect";
7+
import { PubSub } from "@google-cloud/pubsub";
8+
9+
describe("Email breach functional tests", () => {
10+
let conn: Knex;
11+
beforeAll(() => {
12+
conn = createDbConnection();
13+
});
14+
afterAll(async () => {
15+
await conn.destroy();
16+
});
17+
it("connects to the database", async () => {
18+
const res = await conn.raw(`select 1 as connected`);
19+
expect(res.rows).toStrictEqual([{ connected: 1 }]);
20+
});
21+
it("connects to pubsub", () => {
22+
const projectId = process.env.GCP_PUBSUB_PROJECT_ID;
23+
const subscriptionName = process.env.GCP_PUBSUB_SUBSCRIPTION_NAME!;
24+
const pubsub = new PubSub({ projectId });
25+
expect(() => pubsub.subscription(subscriptionName)).not.toThrow();
26+
});
27+
});

src/scripts/cronjobs/emailBreachAlerts.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,12 @@ async function getDataSummary(
383383
/* c8 ignore start */
384384
function createPubSubClient() {
385385
let options = {};
386-
if (process.env.NODE_ENV === "development") {
386+
// TODO - Consolidate configuration logic for this and other clients
387+
// https://mozilla-hub.atlassian.net/browse/MNTOR-5089
388+
if (
389+
process.env.NODE_ENV === "development" ||
390+
process.env.NODE_ENV === "test"
391+
) {
387392
console.debug("Dev mode, connecting to local pubsub emulator");
388393
options = {
389394
servicePath: "localhost",

0 commit comments

Comments
 (0)