Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/spacecat-shared-data-access/docs/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
"AttributeName": "GSI1PK",
"AttributeType": "S"
},
{
"AttributeName": "auditConfig",
"AttributeType": "M"
},
{
"AttributeName": "createdAt",
"AttributeType": "S"
Expand Down
3 changes: 3 additions & 0 deletions packages/spacecat-shared-data-access/src/dto/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/

import { createSite } from '../models/site.js';
import AuditConfig from '../models/site/audit-config.js';

/**
* Data transfer object for Site.
Expand All @@ -30,6 +31,7 @@ export const SiteDto = {
createdAt: site.getCreatedAt(),
updatedAt: site.getUpdatedAt(),
GSI1PK: 'ALL_SITES',
auditConfig: AuditConfig.toDynamoItem(site.getAuditConfig()),
}),

/**
Expand All @@ -46,6 +48,7 @@ export const SiteDto = {
isLive: dynamoItem.isLive,
createdAt: dynamoItem.createdAt,
updatedAt: dynamoItem.updatedAt,
auditConfig: dynamoItem.auditConfig,
};

return createSite(siteData);
Expand Down
13 changes: 13 additions & 0 deletions packages/spacecat-shared-data-access/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,29 @@ export interface Audit {
getExpiresAt: () => Date;
getFullAuditRef: () => string;
isLive: () => boolean;
isError: () => boolean;
getScores: () => object;
}

// AuditConfigType defines the structure for specific audit type configurations
export interface AuditConfigType {
disabled(): boolean;
}

// AuditConfig defines the structure for the overall audit configuration of a site
export interface AuditConfig {
auditsDisabled: () => boolean;
getAuditConfigForType: (auditType: string) => AuditConfigType;
}

export interface Site {
getId: () => string;
getBaseURL: () => string;
getGitHubURL: () => string;
getImsOrgId: () => string;
getCreatedAt: () => string;
getUpdatedAt: () => string;
getAuditConfig: () => AuditConfig;
getAudits: () => Audit[];
isLive: () => boolean;
setAudits: (audits: Audit[]) => Site;
Expand Down
1 change: 1 addition & 0 deletions packages/spacecat-shared-data-access/src/models/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const Audit = (data = {}) => {
self.getExpiresAt = () => self.state.expiresAt;
self.getFullAuditRef = () => self.state.fullAuditRef;
self.isLive = () => self.state.isLive;
self.isError = () => hasText(self.getAuditResult().runtimeError?.code);
self.getScores = () => self.getAuditResult().scores;

return Object.freeze(self);
Expand Down
14 changes: 13 additions & 1 deletion packages/spacecat-shared-data-access/src/models/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
* governing permissions and limitations under the License.
*/

import { hasText, isValidUrl } from '@adobe/spacecat-shared-utils';
import { hasText, isObject, isValidUrl } from '@adobe/spacecat-shared-utils';

import { Base } from './base.js';
import AuditConfig from './site/audit-config.js';

/**
* Creates a new Site.
Expand All @@ -22,6 +24,7 @@ import { Base } from './base.js';
const Site = (data = {}) => {
const self = Base(data);

self.getAuditConfig = () => self.state.auditConfig;
self.getAudits = () => self.state.audits;
self.getBaseURL = () => self.state.baseURL;
self.getGitHubURL = () => self.state.gitHubURL;
Expand Down Expand Up @@ -135,5 +138,14 @@ export const createSite = (data) => {
newState.audits = [];
}

if (!isObject(newState.auditConfig)) {
newState.auditConfig = {
auditsDisabled: false,
auditTypeConfigs: {},
};
}

newState.auditConfig = AuditConfig(newState.auditConfig);

return Site(newState);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2023 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.
*/

const AuditConfigType = (data = {}, allAuditsDisabled = false) => ({
disabled: () => allAuditsDisabled || data.disabled || false,
});

AuditConfigType.fromDynamoItem = (dynamoItem) => {
const auditConfigTypeData = {
disabled: dynamoItem.disabled,
};
return AuditConfigType(auditConfigTypeData);
};

AuditConfigType.toDynamoItem = (auditConfigType) => ({
disabled: auditConfigType.disabled(),
});

export default AuditConfigType;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2023 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 AuditConfigType from './audit-config-type.js';

function getAuditTypeConfigs(auditTypeConfigs, auditsDisabled) {
return Object.entries(auditTypeConfigs || {}).reduce((acc, [key, value]) => {
acc[key] = AuditConfigType(value, auditsDisabled);
return acc;
}, {});
}

const AuditConfig = (data = {}) => {
const auditTypeConfigs = getAuditTypeConfigs(data.auditTypeConfigs, data.auditsDisabled);
return {
auditsDisabled: () => data.auditsDisabled || false,
getAuditTypeConfigs: () => auditTypeConfigs,
getAuditTypeConfig: (type) => auditTypeConfigs[type],
};
};

AuditConfig.fromDynamoItem = (dynamoItem) => AuditConfig(dynamoItem);

AuditConfig.toDynamoItem = (auditConfig) => ({
auditsDisabled: auditConfig.auditsDisabled(),
auditTypeConfigs: Object.entries(auditConfig.getAuditTypeConfigs())
.reduce((acc, [key, value]) => {
acc[key] = AuditConfigType.toDynamoItem(value);
return acc;
}, {}),
});

export default AuditConfig;
16 changes: 16 additions & 0 deletions packages/spacecat-shared-data-access/test/it/db.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ function checkSite(site) {
expect(isIsoDate(site.getUpdatedAt())).to.be.true;
expect(site.getAudits()).to.be.an('array');
expect(site.isLive()).to.be.a('boolean');

const auditConfig = site.getAuditConfig();
expect(auditConfig).to.be.an('object');
expect(auditConfig.auditsDisabled()).to.be.a('boolean').which.is.false;
expect(auditConfig.getAuditTypeConfig(AUDIT_TYPE_LHS_MOBILE)).to.be.an('object');
expect(auditConfig.getAuditTypeConfig(AUDIT_TYPE_LHS_MOBILE).disabled()).to.be.a('boolean').which.is.false;
expect(auditConfig.getAuditTypeConfig('non-existing-type')).to.be.undefined;
expect(auditConfig.getAuditTypeConfig('cwv')).to.be.an('object');
expect(auditConfig.getAuditTypeConfig('cwv').disabled()).to.be.a('boolean').which.is.true;
}

function checkAudit(audit) {
Expand Down Expand Up @@ -152,6 +161,13 @@ describe('DynamoDB Integration Test', async () => {
gitHubURL: 'https://github.com/some-org/test-repo',
imsOrgId: 'newOrg123',
audits: [],
auditConfig: {
auditsDisabled: false,
auditTypeConfigs: {
'lhs-mobile': { disabled: false },
cwv: { disabled: true },
},
},
};

const addedSite = await dataAccess.addSite(newSiteData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ export default async function generateSampleData(
GSI1PK: config.pkAllSites,
createdAt: nowIso,
updatedAt: nowIso,
auditConfig: {
auditsDisabled: false,
auditTypeConfigs: {
'lhs-mobile': { disabled: false },
cwv: { disabled: true },
},
},
});

if (i % 10 !== 0) { // Every tenth site will not have any audits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ import { expect } from 'chai';
import { createSite } from '../../../src/models/site.js';
import { sleep } from '../util.js';

// Constants for testing
const validData = {
baseURL: 'https://www.example.com',
imsOrgId: 'org123',
auditConfig: {
auditsDisabled: false,
auditTypeConfigs: {
type1: { /* some config */ },
type2: { /* some config */ },
},
},
};

describe('Site Model Tests', () => {
Expand All @@ -33,6 +39,34 @@ describe('Site Model Tests', () => {
expect(site).to.be.an('object');
expect(site.getBaseURL()).to.equal(validData.baseURL);
});

it('creates a site with default auditConfig when none provided', () => {
const site = createSite({ ...validData });
const auditConfig = site.getAuditConfig();

expect(auditConfig).to.be.an('object');
expect(auditConfig.auditsDisabled()).be.false;
expect(auditConfig.getAuditTypeConfig('type1')).to.be.an('object');
});

it('creates a site with provided auditConfig', () => {
const newAuditConfig = {
auditsDisabled: true,
auditTypeConfigs: {
type1: { /* some config */ },
type2: { /* some config */ },
},
};
const site = createSite({ ...validData, auditConfig: newAuditConfig });
const auditConfig = site.getAuditConfig();

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('type2')).to.be.an('object');
expect(auditConfig.getAuditTypeConfig('type2').disabled()).to.be.true;
});
});

describe('Site Object Functionality', () => {
Expand Down Expand Up @@ -119,5 +153,22 @@ describe('Site Model Tests', () => {

expect(site.isLive()).to.be.true;
});

it('handles AuditConfig and AuditConfigType correctly', () => {
const auditConfigData = {
auditsDisabled: false,
auditTypeConfigs: {
type1: { /* some config */ },
type2: { /* some config */ },
},
};
const newSite = createSite({ ...validData, auditConfig: auditConfigData });
const auditConfig = newSite.getAuditConfig();

expect(auditConfig).to.be.an('object');
expect(auditConfig.auditsDisabled()).to.be.false;
expect(auditConfig.getAuditTypeConfig('type1')).to.be.an('object');
expect(auditConfig.getAuditTypeConfig('type1').disabled()).to.be.false;
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2023 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 } from 'chai';

import AuditConfigType from '../../../../src/models/site/audit-config-type.js';

describe('AuditConfigType Tests', () => {
describe('AuditConfigType Creation', () => {
it('creates an AuditConfigType with default disabled as false', () => {
const auditConfigType = AuditConfigType();
expect(auditConfigType.disabled()).to.be.false;
});

it('creates an AuditConfigType with specified disabled value', () => {
const auditConfigType = AuditConfigType({ disabled: true });
expect(auditConfigType.disabled()).to.be.true;
});

it('considers allAuditsDisabled flag', () => {
const auditConfigType = AuditConfigType({}, true);
expect(auditConfigType.disabled()).to.be.true;
});
});

describe('disabled Method', () => {
it('returns true when audit is disabled', () => {
const auditConfigType = AuditConfigType({ disabled: true });
expect(auditConfigType.disabled()).to.be.true;
});

it('returns false when audit is not disabled', () => {
const auditConfigType = AuditConfigType({ disabled: false });
expect(auditConfigType.disabled()).to.be.false;
});

it('returns true if allAuditsDisabled is true regardless of data.disabled', () => {
const auditConfigType = AuditConfigType({ disabled: false }, true);
expect(auditConfigType.disabled()).to.be.true;
});
});

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;
});
});

describe('toDynamoItem Static Method', () => {
it('correctly converts to DynamoDB item format', () => {
const auditConfigType = AuditConfigType({ disabled: true });
const dynamoItem = AuditConfigType.toDynamoItem(auditConfigType);
expect(dynamoItem.disabled).to.be.true;
});
});
});
Loading