Skip to content

Commit

Permalink
Merge pull request #928 from 18F/staging
Browse files Browse the repository at this point in the history
[Feature] Add realtime events report -- Production
  • Loading branch information
levinmr authored Nov 21, 2024
2 parents 2691c80 + 6294540 commit 04eeff7
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 116 deletions.
25 changes: 22 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,30 @@ jobs:
- name: Install node
uses: actions/setup-node@v4
with:
node-version: "lts/*"
node-version-file: ".nvmrc"
cache: 'npm'
- name: Install node dependencies
run: npm ci
- name: Lint javascript
run: npm run lint
audit_dependencies:
runs-on: ubuntu-latest
steps:
- name: Code checkout
uses: actions/checkout@v4
- name: Install node
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: 'npm'
- name: Install node dependencies
run: npm ci
- name: Validate npm package signatures
run: npm audit signatures
test:
needs: lint
needs:
- lint
- audit_dependencies
runs-on: ubuntu-latest
# Start Postgres as a service, wait until healthy. Uses latest Postgres version.
services:
Expand All @@ -43,7 +59,7 @@ jobs:
- name: Install node
uses: actions/setup-node@v4
with:
node-version: "lts/*"
node-version-file: ".nvmrc"
cache: 'npm'
- name: Install node dependencies
run: npm ci
Expand All @@ -52,6 +68,7 @@ jobs:
deploy_dev:
needs:
- lint
- audit_dependencies
- test
if: github.ref == 'refs/heads/develop'
uses: 18F/analytics-reporter/.github/workflows/deploy.yml@develop
Expand Down Expand Up @@ -81,6 +98,7 @@ jobs:
deploy_stg:
needs:
- lint
- audit_dependencies
- test
if: github.ref == 'refs/heads/staging'
uses: 18F/analytics-reporter/.github/workflows/deploy.yml@develop
Expand Down Expand Up @@ -110,6 +128,7 @@ jobs:
deploy_prd:
needs:
- lint
- audit_dependencies
- test
if: github.ref == 'refs/heads/master'
uses: 18F/analytics-reporter/.github/workflows/deploy.yml@develop
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
- name: Install node
uses: actions/setup-node@v4
with:
node-version: "lts/*"
node-version-file: ".nvmrc"
cache: 'npm'
- name: Install node dependencies
# This causes npm install to omit dev dependencies per NPM docs.
Expand Down Expand Up @@ -133,7 +133,7 @@ jobs:
- name: Install node
uses: actions/setup-node@v4
with:
node-version: "lts/*"
node-version-file: ".nvmrc"
cache: 'npm'
- name: Install node dependencies
# This causes npm install to omit dev dependencies per NPM docs.
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.11
22
33 changes: 31 additions & 2 deletions package-lock.json

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

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
"migrate": "knex migrate:latest",
"pretest": "NODE_ENV=test npm run migrate",
"start": "./bin/analytics",
"start:publisher": "dotenv -e .env.analytics node -- deploy/cron.js",
"start:consumer": "dotenv -e .env.analytics node -- deploy/consumer.js",
"test": "NODE_ENV=test mocha",
"test:debug": "NODE_ENV=test node --inspect-brk node_modules/mocha/bin/mocha",
"coverage": "nyc --reporter html --reporter text -t coverage --report-dir coverage/summary npm run test",
Expand Down Expand Up @@ -52,7 +54,7 @@
"*.md"
],
"engines": {
"node": "20.x.x"
"node": "22.x.x"
},
"preferGlobal": true,
"main": "index",
Expand All @@ -71,7 +73,6 @@
"@google-analytics/data": "^4.7.0",
"@smithy/node-http-handler": "^3.0.0",
"@snyk/protect": "^1.1269.0",
"dotenv": "^16.3.1",
"fast-csv": "^4.3.6",
"googleapis": "^140.0.0",
"max-listeners-exceeded-warning": "^0.0.1",
Expand All @@ -85,6 +86,8 @@
"@cucumber/cucumber": "^10.3.1",
"@eslint/js": "^8.57.0",
"chai": "^4.4.0",
"dotenv": "^16.4.5",
"dotenv-cli": "^7.4.3",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jsdoc": "^48.7.0",
Expand Down
28 changes: 26 additions & 2 deletions reports/usa.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,36 @@
"metrics": [
{
"name": "activeUsers"
},
{
"name": "screenPageViews"
}
]
},
"meta": {
"name": "Active users and page views realtime",
"description": "Number of users currently visiting all sites and the number of page views."
}
},
{
"name": "realtime-event-counts",
"frequency": "realtime",
"realtime": true,
"query": {
"dimensions": [
{
"name": "eventName"
}
],
"metrics": [
{
"name": "eventCount"
}
]
},
"meta": {
"name": "Active Users Right Now",
"description": "Number of users currently visiting all sites."
"name": "Number of events of each type realtime",
"description": "Number of current events for each event name across all sites."
}
},
{
Expand Down
12 changes: 4 additions & 8 deletions test/actions/action.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,10 @@ describe("Action", () => {
}
}

beforeEach((done) => {
beforeEach(async () => {
promiseExecuted = false;
subject = new SuccessfulTestAction();
subject.execute(context).then(() => {
done();
});
await subject.execute(context);
});

it("executes the strategy and awaits", () => {
Expand All @@ -66,13 +64,11 @@ describe("Action", () => {
}
}

beforeEach((done) => {
beforeEach(async () => {
promiseExecuted = false;
errorlogSpy.resetHistory();
subject = new UnsuccessfulTestAction();
subject.execute(context).catch(() => {
done();
});
await subject.execute(context).catch(() => {});
});

it("executes the strategy and awaits", () => {
Expand Down
16 changes: 8 additions & 8 deletions test/google_analytics/query_authorizer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,42 +39,42 @@ describe("GoogleAnalyticsQueryAuthorizer", () => {
appConfig.key_file = undefined;
});

it("should resolve a query with the auth prop set to an authorized JWT", () => {
return subject.authorizeQuery(query, appConfig).then((query) => {
it("should resolve a query with the auth prop set to an authorized JWT", async () => {
await subject.authorizeQuery(query, appConfig).then((query) => {
expect(query.abc).to.equal(123);
expect(query.auth).to.not.be.undefined;
expect(query.auth).to.be.an.instanceof(googleapis.Auth.JWT);
});
});

it("should create a JWT with the proper scopes", () => {
return subject.authorizeQuery({}, appConfig).then((query) => {
it("should create a JWT with the proper scopes", async () => {
await subject.authorizeQuery({}, appConfig).then((query) => {
expect(query.auth.initArguments[3]).to.deep.equal([
"https://www.googleapis.com/auth/analytics.readonly",
]);
});
});

it("should authorize the JWT and resolve if it is valid", () => {
it("should authorize the JWT and resolve if it is valid", async () => {
let jwtAuthorized = false;
googleapis.Auth.JWT.prototype.authorize = (callback) => {
jwtAuthorized = true;
callback(null, {});
};

return subject.authorizeQuery({}, appConfig).then(() => {
await subject.authorizeQuery({}, appConfig).then(() => {
expect(jwtAuthorized).to.equal(true);
});
});

it("should authorize the JWT and reject if it is invalid", () => {
it("should authorize the JWT and reject if it is invalid", async () => {
let jwtAuthorized = false;
googleapis.Auth.JWT.prototype.authorize = (callback) => {
jwtAuthorized = true;
callback(new Error("Failed to authorize"));
};

return subject.authorizeQuery({}, appConfig).catch((err) => {
await subject.authorizeQuery({}, appConfig).catch((err) => {
expect(jwtAuthorized).to.equal(true);
expect(err.message).to.equal("Failed to authorize");
});
Expand Down
20 changes: 10 additions & 10 deletions test/process_results/result_formatter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ describe("ResultFormatter", () => {
});
});

it("should format results into JSON if the format is 'json'", () => {
it("should format results into JSON if the format is 'json'", async () => {
const result = analyticsDataProcessor.processData({ report, data });

return ResultFormatter.formatResult(result, { format: "json" }).then(
await ResultFormatter.formatResult(result, { format: "json" }).then(
(formattedResult) => {
const json = JSON.parse(formattedResult);
json.data.forEach((row, index) => {
Expand All @@ -46,10 +46,10 @@ describe("ResultFormatter", () => {
);
});

it("should remove the data attribute for JSON if options.slim is true", () => {
it("should remove the data attribute for JSON if options.slim is true", async () => {
const result = analyticsDataProcessor.processData({ report, data });

return ResultFormatter.formatResult(result, {
await ResultFormatter.formatResult(result, {
format: "json",
slim: true,
}).then((formattedResult) => {
Expand All @@ -58,19 +58,19 @@ describe("ResultFormatter", () => {
});
});

it("should reject if the data cannot be JSON stringified", () => {
it("should reject if the data cannot be JSON stringified", async () => {
const array = [];
array[0] = array;

return ResultFormatter.formatResult(array).catch((e) => {
await ResultFormatter.formatResult(array).catch((e) => {
expect(e).to.match(/TypeError: Converting circular structure to JSON/);
});
});

it("should format results into CSV if the format is 'csv'", () => {
it("should format results into CSV if the format is 'csv'", async () => {
const result = analyticsDataProcessor.processData({ report, data });

return ResultFormatter.formatResult(result, {
await ResultFormatter.formatResult(result, {
format: "csv",
slim: true,
}).then((formattedResult) => {
Expand All @@ -89,10 +89,10 @@ describe("ResultFormatter", () => {
});
});

it("should throw an error if the format is unsupported", () => {
it("should throw an error if the format is unsupported", async () => {
const result = analyticsDataProcessor.processData({ report, data });

return ResultFormatter.formatResult(result, {
await ResultFormatter.formatResult(result, {
format: "xml",
slim: true,
}).catch((e) => {
Expand Down
Loading

0 comments on commit 04eeff7

Please sign in to comment.