Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(3266): make changes to models banner to include scope and scopeId #639

Merged
merged 11 commits into from
Jan 23, 2025
66 changes: 65 additions & 1 deletion lib/bannerFactory.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

const BaseFactory = require('./baseFactory');
const PipelineFactory = require('./pipelineFactory');
const BuildFactory = require('./buildFactory');
const Banner = require('./banner');

let instance;
Expand Down Expand Up @@ -33,21 +35,83 @@ class BannerFactory extends BaseFactory {
* @param {String} config.createdBy The username of the associated user
* @param {Boolean} [config.isActive=false] Whether the banner is active
* @param {String} [config.type='info'] Type of banner (info|warn|etc)
* @param {String} [config.scope='GLOBAL'] Scope of the banner (GLOBAL|PIPELINE|BUILD)
* @memberof BannerFactory
*/
create(config) {
async create(config) {
if (!config.type) {
config.type = 'info';
}
if (!config.isActive) {
config.isActive = false;
}
if (!config.scope) {
config.scope = 'GLOBAL';
config.scopeId = null;
}
if ((config.scope === 'PIPELINE' || config.scope === 'BUILD') && !config.scopeId) {
throw new Error(`scopeId is required when scope is ${config.scope}`);
}
if (config.scope === 'PIPELINE') {
const pipeline = await PipelineFactory.getInstance().get(config.scopeId);

if (!pipeline) {
throw new Error(`Pipeline ${config.scopeId} does not exist`);
}
}
if (config.scope === 'BUILD') {
const build = await BuildFactory.getInstance().get(config.scopeId);

if (!build) {
throw new Error(`Build ${config.scopeId} does not exist`);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we refactor the duplicate code block into a reusable function to validate the scopeId by choosing the appropriate factory based on the scope


config.createTime = new Date().toISOString();

return super.create(config);
}

/**
* Helper function to ensure scope and scopeId are set
* @param {Object} banner
* @return {Object} banner
*/
_setScopeDefaults(banner) {
if (!banner.scope) {
banner.scope = 'GLOBAL';
}
if (!banner.scopeId) {
banner.scopeId = null;
}

return banner;
}

/**
* Retrieves a banner by its ID and sets default scope values.
*
* @param {number|string} id - The ID of the banner to retrieve.
* @returns {Promise<Object>} A promise that resolves to the banner object with default scope values set.
*/
async get(id) {
const response = await super.get(id);

return this._setScopeDefaults(response);
}

/**
* Retrieves a list of banners and sets default scope values for each banner.
*
* @param {Object} config - The configuration object for the list request.
* @returns {Promise<Array>} A promise that resolves to an array of banners with default scope values set.
*/
async list(config) {
const response = await super.list(config);

return response.map(banner => this._setScopeDefaults(banner));
}

/**
* Get an instance of BannerFactory
* @method getInstance
Expand Down
92 changes: 89 additions & 3 deletions test/lib/bannerFactory.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const { assert } = require('chai');
const sinon = require('sinon');
const rewiremock = require('rewiremock/node');

sinon.assert.expose(assert, { prefix: '' });

Expand All @@ -14,20 +15,30 @@ describe('Banner Factory', () => {
id: bannerId,
message,
type,
isActive
isActive,
scope: 'GLOBAL',
scopeId: null
};

let BannerFactory;
let datastore;
let factory;
let Banner;
let pipelineFactoryMock;

beforeEach(() => {
pipelineFactoryMock = {
get: sinon.stub()
};
rewiremock('../../lib/pipelineFactory').with({
getInstance: sinon.stub().returns(pipelineFactoryMock)
});
rewiremock.enable();

datastore = {
save: sinon.stub(),
get: sinon.stub()
};

/* eslint-disable global-require */
Banner = require('../../lib/banner');
BannerFactory = require('../../lib/bannerFactory');
Expand All @@ -36,6 +47,10 @@ describe('Banner Factory', () => {
factory = new BannerFactory({ datastore });
});

afterEach(() => {
rewiremock.disable();
});

describe('createClass', () => {
it('should return a Collection', () => {
const model = factory.createClass(bannerData);
Expand All @@ -45,7 +60,7 @@ describe('Banner Factory', () => {
});

describe('create', () => {
it('should create a Banner', () => {
it('should create a Banner with GLOBAL scope', () => {
datastore.save.resolves(bannerData);

return factory
Expand Down Expand Up @@ -126,6 +141,77 @@ describe('Banner Factory', () => {
});
});
});

it('should throw error when creating a Banner with invalid scopeId', () => {
return factory
.create({
message,
type,
isActive,
scope: 'PIPELINE'
})
.then(() => {
assert.fail('nope');
})
.catch(err => {
assert.equal('scopeId is required when scope is PIPELINE', err.message);
});
});

it('should throw error when pipeline ID does not exist', () => {
const dataWithDefaults = { ...bannerData };

dataWithDefaults.scope = 'PIPELINE';
dataWithDefaults.scopeId = '1234';
datastore.save.resolves(dataWithDefaults);
pipelineFactoryMock.get.returns(null);

return factory
.create({
message,
type,
isActive,
scope: 'PIPELINE',
scopeId: '1234'
})
.then(() => {
assert.fail('nope');
})
.catch(err => {
assert.isTrue(pipelineFactoryMock.get.calledOnce);
assert.equal('Pipeline 1234 does not exist', err.message);
});
});

it('should create banner with scope: PIPELINE and scopeId: 1234', () => {
const dataWithDefaults = { ...bannerData };

dataWithDefaults.scope = 'PIPELINE';
dataWithDefaults.scopeId = '1234';
datastore.save.resolves(dataWithDefaults);
pipelineFactoryMock.get.returns({ id: '1234' });

return factory
.create({
message,
type,
isActive,
scope: 'PIPELINE',
scopeId: '1234'
})
.then(model => {
assert.isTrue(datastore.save.calledOnce);
assert.isTrue(pipelineFactoryMock.get.calledOnce);
assert.instanceOf(model, Banner);

Object.keys(bannerData).forEach(key => {
assert.strictEqual(model[key], dataWithDefaults[key]);
});
})
.catch(() => {
assert.fail('should not have failed');
});
});
});

describe('get', () => {
Expand Down