From 936fe87512e81c1ad25c082122949c62acdb6a32 Mon Sep 17 00:00:00 2001 From: Iulia Grumaz Date: Tue, 20 Aug 2024 11:12:33 +0300 Subject: [PATCH 1/2] feat(costs): add costs audit that returns the ahrefs API units consumed and limit (#365) Add costs audit that returns the Ahrefs API units consumed and limit. Ahrefs API call to get limits and usage is free. Audit will be scheduled weekly. Since this is a global audit, it will be by default disabled in the global configuration. It will only be enabled on dev, for ahrefs.com site. The follow-up PR https://github.com/adobe/spacecat-audit-worker/issues/369 will add a post-processor notifying only internally about the audit result. --- src/costs/handler.js | 51 +++++++++++++++++++ src/index.js | 2 + test/audits/costs.test.js | 102 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 src/costs/handler.js create mode 100644 test/audits/costs.test.js diff --git a/src/costs/handler.js b/src/costs/handler.js new file mode 100644 index 00000000..0b7427cf --- /dev/null +++ b/src/costs/handler.js @@ -0,0 +1,51 @@ +/* + * Copyright 2024 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import AhrefsAPIClient from '@adobe/spacecat-shared-ahrefs-client'; +import { AuditBuilder } from '../common/audit-builder.js'; + +export async function runner(auditUrl, context) { + const { log } = context; + const ahrefsAPIClient = AhrefsAPIClient.createFrom(context); + + let ahrefsCostsAuditResult; + try { + const { + result, + fullAuditRef, + } = await ahrefsAPIClient.getLimitsAndUsage(); + + log.info(`Retrieved Ahrefs limits and usage: ${JSON.stringify(result)}`); + ahrefsCostsAuditResult = { + usedApiUnits: result?.limits_and_usage?.units_usage_api_key, + limitApiUnits: result?.limits_and_usage?.units_limit_api_key, + fullAuditRef, + }; + } catch (e) { + log.error(`Ahrefs costs type audit failed with error: ${e.message}`, e); + ahrefsCostsAuditResult = { + error: `Ahrefs costs type audit failed with error: ${e.message}`, + }; + } + + return { + auditResult: { + ahrefs: ahrefsCostsAuditResult, + }, + fullAuditRef: ahrefsCostsAuditResult?.fullAuditRef, + }; +} + +export default new AuditBuilder() + .withRunner(runner) + .withMessageSender(() => {}) + .build(); diff --git a/src/index.js b/src/index.js index a51ef9b0..ca3a21e3 100644 --- a/src/index.js +++ b/src/index.js @@ -29,6 +29,7 @@ import experimentation from './experimentation/handler.js'; import conversion from './conversion/handler.js'; import essExperimentationDaily from './experimentation-ess/daily.js'; import essExperimentationAll from './experimentation-ess/all.js'; +import costs from './costs/handler.js'; const HANDLERS = { apex, @@ -43,6 +44,7 @@ const HANDLERS = { conversion, 'experimentation-ess-daily': essExperimentationDaily, 'experimentation-ess-all': essExperimentationAll, + costs, }; function getElapsedSeconds(startTime) { diff --git a/test/audits/costs.test.js b/test/audits/costs.test.js new file mode 100644 index 00000000..715a0fbf --- /dev/null +++ b/test/audits/costs.test.js @@ -0,0 +1,102 @@ +/* + * Copyright 2024 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +/* eslint-env mocha */ +import { expect, use } from 'chai'; +import sinon from 'sinon'; +import sinonChai from 'sinon-chai'; +import chaiAsPromised from 'chai-as-promised'; +import nock from 'nock'; +import { MockContextBuilder } from '../shared.js'; +import { runner } from '../../src/costs/handler.js'; + +use(sinonChai); +use(chaiAsPromised); + +const message = { + type: 'costs', + url: 'site-id', +}; +const sandbox = sinon.createSandbox(); + +describe('Costs audit', () => { + let context; + + beforeEach('setup', () => { + context = new MockContextBuilder() + .withSandbox(sandbox) + .withOverrides({ + env: { + AHREFS_API_BASE_URL: 'https://ahrefs-example.com', + AHREFS_API_KEY: 'ahrefs-token', + }, + }) + .build(message); + }); + + afterEach(() => { + nock.cleanAll(); + sandbox.restore(); + }); + + it('costs audit returns ahrefs costs succesfully', async () => { + const limitsUsageResponse = { + limits_and_usage: { + subscription: 'Enterprise, billed yearly', + usage_reset_date: '2024-08-28T00:00:00Z', + units_limit_workspace: 12000000, + units_usage_workspace: 6618294, + units_limit_api_key: 1000000, + units_usage_api_key: 198771, + api_key_expiration_date: '2025-01-04T17:44:07Z', + }, + }; + + nock('https://ahrefs-example.com') + .get('/subscription-info/limits-and-usage') + .reply(200, limitsUsageResponse); + + const result = await runner('https://spacecat.com', context); + + const expectedAuditResult = { + ahrefs: { + usedApiUnits: 198771, + limitApiUnits: 1000000, + fullAuditRef: 'https://ahrefs-example.com/subscription-info/limits-and-usage', + }, + }; + + expect(result).to.eql({ + auditResult: expectedAuditResult, + fullAuditRef: 'https://ahrefs-example.com/subscription-info/limits-and-usage', + }); + }); + + it('costs audit returns error for ahrefs costs when call to ahrefs throws', async () => { + nock('https://ahrefs-example.com') + .get('/subscription-info/limits-and-usage') + .reply(500); + + const result = await runner('https://spacecat.com', context); + + const expectedAuditResult = { + ahrefs: { + error: 'Ahrefs costs type audit failed with error: Ahrefs API request failed with status: 500', + }, + }; + + expect(result).to.eql({ + auditResult: expectedAuditResult, + fullAuditRef: undefined, + }); + }); +}); From 63b170274d3919a34901535940b83da4b4e6e7fb Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 20 Aug 2024 08:15:09 +0000 Subject: [PATCH 2/2] chore(release): 1.26.0 [skip ci] # [1.26.0](https://github.com/adobe/spacecat-audit-worker/compare/v1.25.7...v1.26.0) (2024-08-20) ### Features * **costs:** add costs audit that returns the ahrefs API units consumed and limit ([#365](https://github.com/adobe/spacecat-audit-worker/issues/365)) ([936fe87](https://github.com/adobe/spacecat-audit-worker/commit/936fe87512e81c1ad25c082122949c62acdb6a32)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ced46d6c..8604fc7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.26.0](https://github.com/adobe/spacecat-audit-worker/compare/v1.25.7...v1.26.0) (2024-08-20) + + +### Features + +* **costs:** add costs audit that returns the ahrefs API units consumed and limit ([#365](https://github.com/adobe/spacecat-audit-worker/issues/365)) ([936fe87](https://github.com/adobe/spacecat-audit-worker/commit/936fe87512e81c1ad25c082122949c62acdb6a32)) + ## [1.25.7](https://github.com/adobe/spacecat-audit-worker/compare/v1.25.6...v1.25.7) (2024-08-20) diff --git a/package-lock.json b/package-lock.json index d7db7348..54af8e01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@adobe/spacecat-audit-worker", - "version": "1.25.7", + "version": "1.26.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@adobe/spacecat-audit-worker", - "version": "1.25.7", + "version": "1.26.0", "license": "Apache-2.0", "dependencies": { "@adobe/fetch": "4.1.8", diff --git a/package.json b/package.json index 9397ec3d..e773173f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/spacecat-audit-worker", - "version": "1.25.7", + "version": "1.26.0", "description": "SpaceCat Audit Worker", "main": "src/index.js", "type": "module",