From 00a468e9404676212ec9441c8a7fccf1a93c636f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20J=C3=A4ggi?= <1872195+solaris007@users.noreply.github.com> Date: Sat, 16 Dec 2023 15:37:46 +0100 Subject: [PATCH] feat: update audit config (#63) * feat: add update audit config * fix: it test --- .../src/index.d.ts | 135 ++++++++++++++++-- .../src/models/site.js | 12 ++ .../src/models/site/audit-config-type.js | 18 ++- .../src/models/site/audit-config.js | 29 ++-- .../test/it/db.test.js | 18 +++ .../test/unit/models/site.test.js | 27 +++- .../models/site/audit-config-type.test.js | 30 +++- .../unit/models/site/audit-config.test.js | 65 ++++++++- 8 files changed, 305 insertions(+), 29 deletions(-) diff --git a/packages/spacecat-shared-data-access/src/index.d.ts b/packages/spacecat-shared-data-access/src/index.d.ts index 70a15bf5..9feafe34 100644 --- a/packages/spacecat-shared-data-access/src/index.d.ts +++ b/packages/spacecat-shared-data-access/src/index.d.ts @@ -12,66 +12,185 @@ // TODO: introduce AuditType interface or Scores interface +/** + * Represents an individual audit of a site. + */ export interface Audit { + /** + * Retrieves the site ID associated with this audit. + * @returns {string} The site ID. + */ getSiteId: () => string; + + /** + * Retrieves the timestamp when the audit was performed. + * @returns {string} The audit timestamp. + */ getAuditedAt: () => string; + + /** + * Retrieves the result of the audit. + * @returns {object} The audit result. + */ getAuditResult: () => object; + + /** + * Retrieves the type of the audit. + * @returns {object} The audit type. + */ getAuditType: () => object; + + /** + * Retrieves the expiration date of the audit. + * @returns {Date} The expiration date. + */ getExpiresAt: () => Date; + + /** + * Retrieves a reference to the full audit. + * @returns {string} The full audit reference. + */ getFullAuditRef: () => string; + + /** + * Indicates whether the audit is live. + * @returns {boolean} True if the audit is live, false otherwise. + */ isLive: () => boolean; + + /** + * Indicates whether there was an error in the audit. + * @returns {boolean} True if there was an error, false otherwise. + */ isError: () => boolean; + + /** + * Retrieves the scores from the audit. + * @returns {object} The audit scores. + */ getScores: () => object; } /** - * AuditConfigType defines the structure for specific audit type configurations + * AuditConfigType defines the structure for specific audit type configurations. */ export interface AuditConfigType { /** * Returns true if the audit type is disabled for the site. If an audit type is disabled, no * audits of that type will be scheduled for the site. - * @returns True if the audit type is disabled for the site + * @returns {boolean} True if the audit type is disabled for the site. */ - disabled(): boolean; + disabled: () => boolean; } /** - * AuditConfig defines the structure for the overall audit configuration of a site + * AuditConfig defines the structure for the overall audit configuration of a site. */ export interface AuditConfig { /** * Returns true if audits are disabled for the site. If audits are disabled, no audits will be * scheduled for the site. Overrides any audit type specific configurations. - * @returns True if audits are disabled for the site + * @returns {boolean} True if audits are disabled for the site. */ auditsDisabled: () => boolean; + /** * Returns the audit config for a specific audit type. The audit type is the key. - * @param auditType The audit type to get the config for - * @returns The audit config for the audit type + * @param {string} auditType The audit type to get the config for. + * @returns {AuditConfigType} The audit config for the audit type. */ getAuditTypeConfig: (auditType: string) => AuditConfigType; + /** * Returns the audit configs for all audit types. The keys are the audit types. - * @returns The audit configs for all audit types + * @returns {object} The audit configs for all audit types. */ getAuditTypeConfigs: () => object; } +/** + * Represents a site with associated audit and configuration data. + */ export interface Site { + /** + * Retrieves the ID of the site. + * @returns {string} The site ID. + */ getId: () => string; + + /** + * Retrieves the base URL of the site. + * @returns {string} The base URL. + */ getBaseURL: () => string; + + /** + * Retrieves the GitHub URL associated with the site. + * @returns {string} The GitHub URL. + */ getGitHubURL: () => string; + + /** + * Retrieves the IMS Organization ID associated with the site. + * @returns {string} The IMS Org ID. + */ getImsOrgId: () => string; + + /** + * Retrieves the creation timestamp of the site. + * @returns {string} The creation timestamp. + */ getCreatedAt: () => string; + + /** + * Retrieves the last update timestamp of the site. + * @returns {string} The last update timestamp. + */ getUpdatedAt: () => string; + + /** + * Retrieves the current audit configuration for the site. + * @returns {AuditConfig} The current audit configuration. + */ getAuditConfig: () => AuditConfig; + + /** + * Retrieves the audits associated with the site. + * @returns {Audit[]} The list of audits. + */ getAudits: () => Audit[]; + + /** + * Indicates whether the site is live. + * @returns {boolean} True if the site is live, false otherwise. + */ isLive: () => boolean; + + /** + * Updates the list of audits for the site. + * @param {Audit[]} audits The new list of audits. + * @returns {Site} The updated site instance. + */ setAudits: (audits: Audit[]) => Site; + + /** + * Toggles the live status of the site. + * @returns {Site} The updated site instance with the toggled live status. + */ toggleLive: () => Site; + + /** + * Updates the GitHub URL of the site. + * @param {string} gitHubURL The new GitHub URL. + * @returns {Site} The updated site instance. + */ updateGitHubURL: (gitHubURL: string) => Site; + + /** + * Updates the IMS Org ID of the site. + * @param {string} imsOrgId The new IMS Org ID. + * @returns {Site} The updated site instance. + */ updateImsOrgId: (imsOrgId: string) => Site; } diff --git a/packages/spacecat-shared-data-access/src/models/site.js b/packages/spacecat-shared-data-access/src/models/site.js index 752e4a22..2faf205d 100644 --- a/packages/spacecat-shared-data-access/src/models/site.js +++ b/packages/spacecat-shared-data-access/src/models/site.js @@ -68,6 +68,18 @@ const Site = (data = {}) => { return self; }; */ + self.setAllAuditsDisabled = (disabled) => { + self.state.auditConfig.updateAuditsDisabled(disabled); + self.touch(); + return self; + }; + + self.updateAuditTypeConfig = (type, config) => { + self.state.auditConfig.updateAuditTypeConfig(type, config); + self.touch(); + return self; + }; + /** * Updates the GitHub URL belonging to the site. * @param {string} gitHubURL - The GitHub URL. diff --git a/packages/spacecat-shared-data-access/src/models/site/audit-config-type.js b/packages/spacecat-shared-data-access/src/models/site/audit-config-type.js index 00f71fc1..1f8ef399 100644 --- a/packages/spacecat-shared-data-access/src/models/site/audit-config-type.js +++ b/packages/spacecat-shared-data-access/src/models/site/audit-config-type.js @@ -10,9 +10,21 @@ * governing permissions and limitations under the License. */ -const AuditConfigType = (data = {}, allAuditsDisabled = false) => ({ - disabled: () => allAuditsDisabled || data.disabled || false, -}); +const AuditConfigType = (data = {}) => { + const state = { + disabled: data.disabled || false, + }; + + const self = { + disabled: () => state.disabled, + + updateDisabled: (newValue) => { + state.disabled = newValue; + }, + }; + + return Object.freeze(self); +}; AuditConfigType.fromDynamoItem = (dynamoItem) => { const auditConfigTypeData = { diff --git a/packages/spacecat-shared-data-access/src/models/site/audit-config.js b/packages/spacecat-shared-data-access/src/models/site/audit-config.js index 9ebd6015..675305ae 100644 --- a/packages/spacecat-shared-data-access/src/models/site/audit-config.js +++ b/packages/spacecat-shared-data-access/src/models/site/audit-config.js @@ -9,14 +9,9 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ + import AuditConfigType from './audit-config-type.js'; -/** - * Initializes the audit type configs. If auditsDisabled is true, all audit types will be disabled. - * @param {object} auditTypeConfigs - Object containing audit type configs. - * @param {boolean} auditsDisabled - Flag indicating if all audits are disabled. - * @return {object} Object containing audit type configs. - */ function getAuditTypeConfigs(auditTypeConfigs, auditsDisabled) { return Object.entries(auditTypeConfigs || {}).reduce((acc, [key, value]) => { acc[key] = AuditConfigType(value, auditsDisabled); @@ -25,12 +20,24 @@ function getAuditTypeConfigs(auditTypeConfigs, auditsDisabled) { } const AuditConfig = (data = {}) => { - const auditTypeConfigs = getAuditTypeConfigs(data.auditTypeConfigs, data.auditsDisabled); - return { - auditsDisabled: () => data.auditsDisabled || false, - getAuditTypeConfigs: () => auditTypeConfigs, - getAuditTypeConfig: (type) => auditTypeConfigs[type], + const state = { + auditsDisabled: data.auditsDisabled || false, + auditTypeConfigs: getAuditTypeConfigs(data.auditTypeConfigs, data.auditsDisabled), }; + + const self = { + auditsDisabled: () => state.auditsDisabled, + getAuditTypeConfigs: () => state.auditTypeConfigs, + getAuditTypeConfig: (type) => state.auditTypeConfigs[type], + updateAuditsDisabled: (newValue) => { + state.auditsDisabled = newValue; + }, + updateAuditTypeConfig: (type, config) => { + state.auditTypeConfigs[type] = AuditConfigType(config); + }, + }; + + return Object.freeze(self); }; AuditConfig.fromDynamoItem = (dynamoItem) => AuditConfig(dynamoItem); diff --git a/packages/spacecat-shared-data-access/test/it/db.test.js b/packages/spacecat-shared-data-access/test/it/db.test.js index 97ca1c31..df1594de 100644 --- a/packages/spacecat-shared-data-access/test/it/db.test.js +++ b/packages/spacecat-shared-data-access/test/it/db.test.js @@ -401,4 +401,22 @@ describe('DynamoDB Integration Test', async () => { ); expect(latestAuditAfterRemoval).to.be.null; }); + + it('updates audit configurations for a site', async () => { + const siteToUpdate = await dataAccess.getSiteByBaseURL('https://example2.com'); + + // Update all audits to be disabled + siteToUpdate.setAllAuditsDisabled(true); + await dataAccess.updateSite(siteToUpdate); + + let updatedSite = await dataAccess.getSiteByID(siteToUpdate.getId()); + expect(updatedSite.getAuditConfig().auditsDisabled()).to.be.true; + + // Update a specific audit type configuration + siteToUpdate.updateAuditTypeConfig('type1', { disabled: false }); + await dataAccess.updateSite(siteToUpdate); + + updatedSite = await dataAccess.getSiteByID(siteToUpdate.getId()); + expect(updatedSite.getAuditConfig().getAuditTypeConfig('type1').disabled()).to.be.false; + }); }); diff --git a/packages/spacecat-shared-data-access/test/unit/models/site.test.js b/packages/spacecat-shared-data-access/test/unit/models/site.test.js index 7fa52a1a..de692241 100644 --- a/packages/spacecat-shared-data-access/test/unit/models/site.test.js +++ b/packages/spacecat-shared-data-access/test/unit/models/site.test.js @@ -63,9 +63,9 @@ describe('Site Model Tests', () => { expect(auditConfig).to.be.an('object'); expect(auditConfig.auditsDisabled()).to.be.true; expect(auditConfig.getAuditTypeConfig('type1')).to.be.an('object'); - expect(auditConfig.getAuditTypeConfig('type1').disabled()).to.be.true; + expect(auditConfig.getAuditTypeConfig('type1').disabled()).to.be.false; expect(auditConfig.getAuditTypeConfig('type2')).to.be.an('object'); - expect(auditConfig.getAuditTypeConfig('type2').disabled()).to.be.true; + expect(auditConfig.getAuditTypeConfig('type2').disabled()).to.be.false; }); }); @@ -153,6 +153,14 @@ describe('Site Model Tests', () => { expect(site.isLive()).to.be.true; }); + }); + + describe('AuditConfig Integration', () => { + let site; + + beforeEach(() => { + site = createSite(validData); + }); it('handles AuditConfig and AuditConfigType correctly', () => { const auditConfigData = { @@ -170,5 +178,20 @@ describe('Site Model Tests', () => { expect(auditConfig.getAuditTypeConfig('type1')).to.be.an('object'); expect(auditConfig.getAuditTypeConfig('type1').disabled()).to.be.false; }); + + it('sets all audits disabled correctly', () => { + site.setAllAuditsDisabled(true); + expect(site.getAuditConfig().auditsDisabled()).to.be.true; + }); + + it('updates a specific audit type configuration', () => { + site.updateAuditTypeConfig('type1', { disabled: true }); + expect(site.getAuditConfig().getAuditTypeConfig('type1').disabled()).to.be.true; + }); + + it('adds a new audit type configuration if it does not exist', () => { + site.updateAuditTypeConfig('type3', { disabled: true }); + expect(site.getAuditConfig().getAuditTypeConfig('type3').disabled()).to.be.true; + }); }); }); diff --git a/packages/spacecat-shared-data-access/test/unit/models/site/audit-config-type.test.js b/packages/spacecat-shared-data-access/test/unit/models/site/audit-config-type.test.js index 703ec485..d2c85fd8 100644 --- a/packages/spacecat-shared-data-access/test/unit/models/site/audit-config-type.test.js +++ b/packages/spacecat-shared-data-access/test/unit/models/site/audit-config-type.test.js @@ -30,7 +30,7 @@ describe('AuditConfigType Tests', () => { it('considers allAuditsDisabled flag', () => { const auditConfigType = AuditConfigType({}, true); - expect(auditConfigType.disabled()).to.be.true; + expect(auditConfigType.disabled()).to.be.false; }); }); @@ -45,17 +45,39 @@ describe('AuditConfigType Tests', () => { expect(auditConfigType.disabled()).to.be.false; }); - it('returns true if allAuditsDisabled is true regardless of data.disabled', () => { + it('returns false if allAuditsDisabled is true regardless', () => { const auditConfigType = AuditConfigType({ disabled: false }, true); + expect(auditConfigType.disabled()).to.be.false; + }); + }); + + describe('updateDisabled Method', () => { + it('updates the disabled status of the audit type', () => { + const auditConfigType = AuditConfigType({ disabled: false }); + + // Update the disabled status + auditConfigType.updateDisabled(true); + expect(auditConfigType.disabled()).to.be.true; }); + + it('updates the disabled status independently of allAuditsDisabled flag', () => { + // The allAuditsDisabled flag is set to true initially + const auditConfigType = AuditConfigType({ disabled: false }, true); + + // Update the disabled status + auditConfigType.updateDisabled(false); + + // The updateDisabled method should update the state regardless of allAuditsDisabled flag + expect(auditConfigType.disabled()).to.be.false; + }); }); describe('fromDynamoItem Static Method', () => { it('correctly converts from DynamoDB item', () => { const dynamoItem = { disabled: true }; - const auditConfigType = AuditConfigType.fromDynamoItem(dynamoItem); - expect(auditConfigType.disabled()).to.be.true; + const typeConfig = AuditConfigType.fromDynamoItem(dynamoItem); + expect(typeConfig.disabled()).to.be.true; }); }); diff --git a/packages/spacecat-shared-data-access/test/unit/models/site/audit-config.test.js b/packages/spacecat-shared-data-access/test/unit/models/site/audit-config.test.js index 03c4d6c8..0b20e909 100644 --- a/packages/spacecat-shared-data-access/test/unit/models/site/audit-config.test.js +++ b/packages/spacecat-shared-data-access/test/unit/models/site/audit-config.test.js @@ -35,7 +35,7 @@ describe('AuditConfig Tests', () => { const auditConfig = AuditConfig(data); expect(auditConfig.auditsDisabled()).to.be.true; expect(auditConfig.getAuditTypeConfig('type1').disabled()).to.be.true; - expect(auditConfig.getAuditTypeConfig('type2').disabled()).to.be.true; + expect(auditConfig.getAuditTypeConfig('type2').disabled()).to.be.false; }); }); @@ -86,6 +86,69 @@ describe('AuditConfig Tests', () => { }); }); + describe('updateAuditsDisabled Method', () => { + it('updates the auditsDisabled state to true', () => { + const auditConfig = AuditConfig({ auditsDisabled: false }); + auditConfig.updateAuditsDisabled(true); + expect(auditConfig.auditsDisabled()).to.be.true; + }); + + it('updates the auditsDisabled state to false', () => { + const auditConfig = AuditConfig({ auditsDisabled: true }); + auditConfig.updateAuditsDisabled(false); + expect(auditConfig.auditsDisabled()).to.be.false; + }); + + it('updates auditTypeConfigs when auditsDisabled changes', () => { + const data = { + auditsDisabled: false, + auditTypeConfigs: { + type1: { disabled: true }, + type2: { disabled: false }, + }, + }; + const auditConfig = AuditConfig(data); + + auditConfig.updateAuditsDisabled(true); + + expect(auditConfig.auditsDisabled()).to.be.true; + }); + }); + + describe('updateAuditTypeConfig Method', () => { + it('updates a specific audit type configuration', () => { + const data = { + auditsDisabled: false, + auditTypeConfigs: { + type1: { disabled: false }, + type2: { disabled: false }, + }, + }; + const auditConfig = AuditConfig(data); + + // Update the configuration for type1 + auditConfig.updateAuditTypeConfig('type1', { disabled: true }); + + expect(auditConfig.getAuditTypeConfig('type1').disabled()).to.be.true; + expect(auditConfig.getAuditTypeConfig('type2').disabled()).to.be.false; + }); + + it('adds a new audit type configuration if it does not exist', () => { + const data = { + auditsDisabled: false, + auditTypeConfigs: { + type1: { disabled: false }, + }, + }; + const auditConfig = AuditConfig(data); + + // Add a new configuration for type2 + auditConfig.updateAuditTypeConfig('type2', { disabled: true }); + + expect(auditConfig.getAuditTypeConfig('type2').disabled()).to.be.true; + }); + }); + describe('fromDynamoItem Static Method', () => { it('correctly converts from DynamoDB item', () => { const dynamoItem = {