-
Martin Lowe authored
To resolves this issue, the already existing org to API wrapper for installation mapping is used. We extract the keys from the mapping, and pass them along to the static team sync. This allows non-project managed organizations like eclipse-ide to still have EF service teams added. Resolves #291
Martin Lowe authoredTo resolves this issue, the already existing org to API wrapper for installation mapping is used. We extract the keys from the mapping, and pass them along to the static team sync. This allows non-project managed organizations like eclipse-ide to still have EF service teams added. Resolves #291
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
SyncTest.js 31.30 KiB
const chai = require('chai');
const ChaiAsPromised = require('chai-as-promised');
const expect = chai.expect;
// Chai deferred assertions break without this: https://github.com/domenic/chai-as-promised/issues/41#issuecomment-208068569
chai.should();
// set chai as promised into chai framework
chai.use(ChaiAsPromised);
const Wrapper = require('../src/GitWrapper.js');
const { GithubSync, NOT_FOUND_MESSAGE } = require('../src/Sync.js');
const { UserPermissionsOverride } = require('../src/teams/UserPermissionsOverride.js');
const { StaticTeamManager, ServiceTypes } = require('../src/teams/StaticTeamManager.js');
const { HttpWrapper } = require('../src/HttpWrapper.js');
const EclipseAPI = require('../src/EclipseAPI.js');
const { AxiosError } = require('axios');
const sampleUserStore = generateSampleUserStore();
describe('GithubSync', function () {
describe('#updateProjectTeam', function () {
describe('success', function () {
const baseProject = generateSampleProjects()[0];
const testOrgName = 'eclipsefdn-webdev';
const Sync = setupBasicSync();
afterEach(() => {
jest.restoreAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should update project team to be public', done => {
const grouping = 'committers';
const teamName = 'sample-committers';
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock([
{
login: 'epoirier'
}
]);
reposForOrgMock({ [testOrgName]: [{ name: 'spider-pig' }, { name: '.eclipsefdn' }] });
// do the assertions w/ some deferred to after the call completes
chai.expect(Sync.updateProjectTeam(testOrgName, baseProject, grouping)).fulfilled.then(function () {
chai.expect(updatedUsers).to.deep.equal(['malowe', 'epoirier']);
chai.expect(updatedTeams).to.deep.equal([teamName]);
chai.expect(removedUsers).to.be.empty;
chai.expect(teamUpdates[teamName]).to.deep.equal({
privacy: 'closed',
description: generateExpectedTeamDescription(baseProject, grouping)
});
}).should.notify(done);
});
it('should allow override project team name', done => {
const grouping = 'committers';
const defaultTeamName = 'sample-committers';
const overriddenTeamName = 'sample-team-name';
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock([
{
login: 'epoirier'
}
]);
reposForOrgMock({ [testOrgName]: [{ name: 'spider-pig' }, { name: '.eclipsefdn' }] });
// do the assertions w/ some deferred to after the call completes
chai.expect(Sync.updateProjectTeam(testOrgName, baseProject, grouping, overriddenTeamName)).fulfilled.then(function () {
chai.expect(updatedUsers).to.deep.equal(['malowe', 'epoirier']);
chai.expect(updatedTeams).to.deep.equal([overriddenTeamName]);
chai.expect(removedUsers).to.be.empty;
chai.expect(teamUpdates[overriddenTeamName]).to.deep.equal({
privacy: 'closed',
description: generateExpectedTeamDescription(baseProject, grouping)
});
chai.expect(teamUpdates[defaultTeamName]).to.be.undefined;
}).should.notify(done);
});
it('should support security_team processing', done => {
const grouping = 'security_team';
const teamName = 'sample-security_team';
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock();
reposForOrgMock({ [testOrgName]: [{ name: 'spider-pig' }, { name: '.eclipsefdn' }] });
// do the assertions w/ some deferred to after the call completes
chai.expect(Sync.updateProjectTeam(testOrgName, baseProject, grouping)).fulfilled.then(function () {
chai.expect(updatedUsers).to.deep.equal(['malowe', 'epoirier']);
chai.expect(updatedTeams).to.deep.equal([teamName]);
chai.expect(removedUsers).to.be.empty;
chai.expect(teamUpdates[teamName]).to.deep.equal({
privacy: 'closed',
description: generateExpectedTeamDescription(baseProject, grouping)
});
}).should.notify(done);
});
it('should keep team secret with no .eclipsefdn repo', done => {
const grouping = 'committers';
const teamName = 'sample-committers';
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock([
{
login: 'epoirier'
}
]);
reposForOrgMock({ [testOrgName]: [{ name: 'spider-pig' }] });
// do the assertions w/ some deferred to after the call completes
chai.expect(Sync.updateProjectTeam(testOrgName, baseProject, grouping)).fulfilled.then(function () {
chai.expect(updatedUsers).to.deep.equal(['malowe', 'epoirier']);
chai.expect(updatedTeams).to.deep.equal([teamName]);
chai.expect(removedUsers).to.be.empty;
chai.expect(teamUpdates[teamName]).to.deep.equal({
privacy: 'secret',
description: generateExpectedTeamDescription(baseProject, grouping)
});
}).should.notify(done);
});
});
});
describe('#updateTeam', function () {
describe('success', function () {
const baseProject = generateSampleProjects()[0];
const baseTeamName = 'sample-team';
const Sync = setupBasicSync();
afterEach(() => {
jest.restoreAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should update team on call', done => {
const teamProps = {
privacy: 'closed',
description: 'Sample description for team'
};
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock([]);
// do the assertions w/ some deferred to after the call completes
chai.expect(Sync.updateTeam('sample', { ...teamProps, teamName: baseTeamName }, [], baseProject)).fulfilled.then(function () {
chai.expect(updatedUsers).to.be.empty;
chai.expect(updatedTeams).to.be.empty;
chai.expect(removedUsers).to.be.empty;
chai.expect(teamUpdates[baseTeamName]).to.deep.equal(teamProps);
}).should.notify(done);
});
it('should add new team members', done => {
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock([]);
// do the assertions w/ some deferred to after the call completes
chai.expect(Sync.updateTeam('sample', {
privacy: 'closed',
description: 'Sample description for team',
teamName: baseTeamName
}, [{
username: 'test-user-1',
url: 'https://api.eclipse.org/account/profile/test-user-1',
}], baseProject)).fulfilled.then(function () {
chai.expect(updatedUsers).to.deep.equal(['test-user-1']);
chai.expect(updatedTeams).to.deep.equal([baseTeamName]);
chai.expect(removedUsers).to.be.empty;
}).should.notify(done);
});
it('should remove no longer present team members', done => {
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock([{
login: 'test-user-1'
}, {
login: 'test-user-2'
}]);
// do the assertions w/ some deferred to after the call completes
chai.expect(Sync.updateTeam('sample', {
privacy: 'closed',
description: 'Sample description for team',
teamName: baseTeamName
}, [{
username: 'test-user-1',
url: 'https://api.eclipse.org/account/profile/test-user-1',
}], baseProject)).fulfilled.then(function () {
chai.expect(updatedUsers).to.deep.equal(['test-user-1']);
chai.expect(updatedTeams).to.deep.equal([baseTeamName]);
chai.expect(removedUsers).to.deep.equal(['test-user-2']);
}).should.notify(done);
});
it('should remove expired team members', done => {
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock([{
login: 'test-user-1'
}, {
login: 'test-user-2'
}]);
// do the assertions w/ some deferred to after the call completes
chai.expect(Sync.updateTeam('sample', {
privacy: 'closed',
description: 'Sample description for team',
teamName: baseTeamName
}, [{
username: 'test-user-1',
url: 'https://api.eclipse.org/account/profile/test-user-1',
expiration: '2020-01-01'
}, {
username: 'test-user-2',
url: 'https://api.eclipse.org/account/profile/test-user-2',
expiration: '2099-01-01'
}], baseProject)).fulfilled.then(function () {
chai.expect(updatedUsers).to.deep.equal(['test-user-2']);
chai.expect(updatedTeams).to.deep.equal([baseTeamName]);
chai.expect(removedUsers).to.deep.equal(['test-user-1']);
}).should.notify(done);
});
it('should remove users when handled not found response is returned', done => {
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock([{
login: 'test-user-1'
}, {
login: 'no-matching-user'
}]);
// this test assumes that the 'no-matching-user' that returns was deleted account
chai.expect(Sync.updateTeam('sample', {
privacy: 'closed',
description: 'Sample description for team',
teamName: baseTeamName
}, [{
username: 'test-user-1',
url: 'https://api.eclipse.org/account/profile/test-user-1'
}, {
username: 'no-matching-user',
url: 'https://api.eclipse.org/account/profile/no-matching-user',
}], baseProject)).fulfilled.then(function () {
chai.expect(updatedUsers).to.deep.equal(['test-user-1']);
chai.expect(updatedTeams).to.deep.equal([baseTeamName]);
chai.expect(removedUsers).to.deep.equal(['no-matching-user']);
}).should.notify(done);
});
it('should skip removal of team members on errors', done => {
const { teamUpdates, removedUsers, updatedUsers, updatedTeams } = updateTeamCommonMock([{
login: 'test-user-1'
}, {
login: 'test-user-2'
}], false);
jest.spyOn(HttpWrapper.prototype, 'getRaw').mockImplementationOnce((url) => {
// close enough representation to the service being down
return new AxiosError('An error has occurred', '500', undefined, undefined, { data: { message: 'some error' } });
});
// do the assertions w/ some deferred to after the call completes
chai.expect(Sync.updateTeam('sample', {
privacy: 'closed',
description: 'Sample description for team',
teamName: baseTeamName
}, [{
username: 'test-user-1',
url: 'https://api.eclipse.org/account/profile/test-user-1',
}], baseProject)).fulfilled.then(function () {
chai.expect(updatedUsers).to.be.empty;
chai.expect(updatedTeams).to.be.empty;
chai.expect(removedUsers).to.be.empty;
}).should.notify(done);
});
});
});
describe('#removeOrgExternalContributors', function () {
describe('success', function () {
const testOrgName = 'eclipsefdn-webdev';
const sampleProjects = generateSampleProjects();
const Sync = setupBasicSync();
// required to clean up between tests
afterEach(() => {
jest.restoreAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should remove standard users on normal run', done => {
// set a few sample users as contributors
const usernames = removeOrgExternalContributorsMock([{ login: 'dummy' }, { login: 'doofenshmirtz' }]);
chai.expect(Sync.removeOrgExternalContributors(sampleProjects, testOrgName)).fulfilled.then(function () {
chai.expect(usernames).to.deep.equal(['dummy', 'doofenshmirtz']);
}).should.notify(done);
});
it('should remove users that are Project Leads', done => {
// set a few sample users as contributors
const usernames = removeOrgExternalContributorsMock([{ login: 'malowe' }, { login: 'doofenshmirtz' }]);
chai.expect(Sync.removeOrgExternalContributors(sampleProjects, testOrgName)).fulfilled.then(function () {
chai.expect(usernames).to.deep.equal(['malowe', 'doofenshmirtz']);
}).should.notify(done);
});
it('should not remove bot users', done => {
// set a few sample users as contributors
const usernames = removeOrgExternalContributorsMock([{ login: 'sample-bot' }, { login: 'doofenshmirtz' }]);
chai.expect(Sync.removeOrgExternalContributors(sampleProjects, testOrgName)).fulfilled.then(function () {
chai.expect(usernames).to.deep.equal(['doofenshmirtz']);
}).should.notify(done);
});
it('should remove no one when error fetching contributors', done => {
// set a few sample users as contributors
const usernames = removeOrgExternalContributorsMock(undefined);
chai.expect(Sync.removeOrgExternalContributors(sampleProjects, testOrgName)).fulfilled.then(function () {
chai.expect(usernames).to.be.empty;
}).should.notify(done);
});
it('should finish quietly if there is no contributors', done => {
// set a few sample users as contributors
const usernames = removeOrgExternalContributorsMock([]);
chai.expect(Sync.removeOrgExternalContributors(sampleProjects, testOrgName)).fulfilled.then(function () {
chai.expect(usernames).to.be.empty;
}).should.notify(done);
});
});
});
describe('#removeRepoExternalContributors', function () {
describe('success', function () {
const testOrgName = 'eclipsefdn-webdev';
const testRepo = 'spider-pig';
const sampleProject = generateSampleProjects()[0];
const Sync = setupBasicSync();
// required to clean up between tests
afterEach(() => {
jest.restoreAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should remove standard users on normal run', done => {
// set a few sample users as contributors
const usernames = removeRepoExternalContributorsMock([{ login: 'dummy' }, { login: 'doofenshmirtz' }]);
chai.expect(Sync.removeRepoExternalContributors(sampleProject, testOrgName, testRepo)).fulfilled.then(function () {
chai.expect(usernames).to.deep.equal({ [testRepo]: ['dummy', 'doofenshmirtz'] });
}).should.notify(done);
});
it('should keep users that are Project Leads', done => {
// set a few sample users as contributors
const usernames = removeRepoExternalContributorsMock([{ login: 'malowe' }, { login: 'doofenshmirtz' }]);
chai.expect(Sync.removeRepoExternalContributors(sampleProject, testOrgName, testRepo)).fulfilled.then(function () {
chai.expect(usernames).to.deep.equal({ [testRepo]: ['doofenshmirtz'] });
}).should.notify(done);
});
it('should not remove bot users', done => {
// set a few sample users as contributors
const usernames = removeRepoExternalContributorsMock([{ login: 'sample-bot' }, { login: 'doofenshmirtz' }]);
chai.expect(Sync.removeRepoExternalContributors(sampleProject, testOrgName, testRepo)).fulfilled.then(function () {
chai.expect(usernames).to.deep.equal({ [testRepo]: ['doofenshmirtz'] });
}).should.notify(done);
});
it('should not remove eclipsewebmaster', done => {
// set a few sample users as contributors
const usernames = removeRepoExternalContributorsMock([{ login: 'eclipsewebmaster' }, { login: 'doofenshmirtz' }]);
chai.expect(Sync.removeRepoExternalContributors(sampleProject, testOrgName, testRepo)).fulfilled.then(function () {
chai.expect(usernames).to.deep.equal({ [testRepo]: ['doofenshmirtz'] });
}).should.notify(done);
});
it('should remove no one when error fetching contributors', done => {
// set an effective error as the contributors
const usernames = removeRepoExternalContributorsMock(undefined);
chai.expect(Sync.removeRepoExternalContributors(sampleProject, testOrgName, testRepo)).fulfilled.then(function () {
chai.expect(usernames).to.be.empty;
}).should.notify(done);
});
it('should finish quietly if there is no contributors', done => {
// set a empty users as contributors
const usernames = removeRepoExternalContributorsMock([]);
chai.expect(Sync.removeRepoExternalContributors(sampleProject, testOrgName, testRepo)).fulfilled.then(function () {
chai.expect(usernames).to.be.empty;
}).should.notify(done);
});
it('should skip removal if there is a server error looking up the user', done => {
// set up the normal test, minus the user lookup
const usernames = removeRepoExternalContributorsMock([{ login: 'doofenshmirtz' }], false);
// manually setup the pseudo-error state for the user lookup mechanic
jest.spyOn(HttpWrapper.prototype, 'getRaw').mockImplementationOnce((url) => {
// close enough representation to the service being down
return new AxiosError('An error has occurred', '500', undefined, undefined, { data: { message: 'some error' } });
});
chai.expect(Sync.removeRepoExternalContributors(sampleProject, testOrgName, testRepo)).fulfilled.then(function () {
chai.expect(usernames).to.be.empty;
}).should.notify(done);
});
});
});
describe('#processProjects', function () {
describe('success', function () {
// setup with no overrides for base usage
const Sync = new GithubSync({
V: true,
d: false
});
Sync.upo = new UserPermissionsOverride(`${__dirname}/perms/empty_overrides.json`);
const baseProjects = generateSampleProjects();
let result;
beforeAll(async function () {
result = await Sync.processProjects(JSON.parse(JSON.stringify(baseProjects)));
});
it('should contain JSON data', function () {
expect(result).to.be.an('array');
});
it('should be the same size as the input', function () {
expect(result.length).equal(baseProjects.length);
});
it('should have not change users with no overrides', function () {
const firstResult = result[0];
const firstIn = baseProjects[0];
expect(firstResult.contributors).deep.equal(firstIn.contributors);
expect(firstResult.committers).deep.equal(firstIn.committers);
expect(firstResult.project_leads).deep.equal(firstIn.project_leads);
});
});
describe('success w/ user overrides', function () {
// setup with no overrides for base usage
const Sync = new GithubSync({
V: true,
d: false
});
Sync.upo = new UserPermissionsOverride(`${__dirname}/perms/test.json`);
const baseProjects = generateSampleProjects();
var result;
beforeAll(async function () {
result = await Sync.processProjects(JSON.parse(JSON.stringify(baseProjects)));
});
it('should contain JSON data', function () {
expect(result).to.be.an('array');
});
it('should be the same size as the input', function () {
expect(result.length).equal(baseProjects.length);
});
it('should remove excluded users', function () {
const firstResult = result[0];
const firstIn = baseProjects[0];
expect(firstIn.contributors).to.not.be.empty;
expect(firstResult.contributors).to.be.empty;
});
it('should update users with overridden permissions', function () {
const firstResult = result[0];
const firstIn = baseProjects[0];
const expectedLeads = [
...firstIn.project_leads,
{
username: 'epoirier',
url: 'https://api.eclipse.org/account/profile/epoirier',
}
];
// should be 1 additional entry
expect(firstResult.project_leads.length).equal(expectedLeads.length);
expect(firstResult.project_leads).to.deep.equal(expectedLeads);
});
});
});
describe('#checkIfTeamCanBePublic', function () {
describe('success', function () {
const testOrgName = 'eclipsefdn-webdev';
const testRepo = 'spider-pig';
const sampleProject = generateSampleProjects()[0];
const Sync = setupBasicSync();
// required to clean up between tests
afterEach(() => {
jest.restoreAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should indicate true when eclipsefdn repo is present', async () => {
// this is a "good enough" mocking as we only check what is present by name
reposForOrgMock({ [testOrgName]: [{ name: 'spider-pig' }, { name: '.eclipsefdn' }] });
chai.expect(await Sync.checkIfTeamCanBePublic(testOrgName)).to.equal(true);
});
it('should indicate false when eclipsefdn repo is not present', async () => {
// this is a "good enough" mocking as we only check what is present by name
reposForOrgMock({ [testOrgName]: [{ name: 'spider-pig' }] });
chai.expect(await Sync.checkIfTeamCanBePublic(testOrgName)).to.equal(false);
});
it('should indicate false when no repos are found', async () => {
// this is a "good enough" mocking as we only check what is present by name
reposForOrgMock({ [testOrgName]: [{ name: 'spider-pig' }] });
chai.expect(await Sync.checkIfTeamCanBePublic('invalid-org-name')).to.equal(false);
});
});
});
describe('#checkIfUserIsMissing', function () {
describe('success', function () {
const Sync = setupBasicSync();
const baseResponse = {
status: 404,
data:new Array(NOT_FOUND_MESSAGE)
};
// required to clean up between tests
afterEach(() => {
jest.restoreAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should return true if response message is in array format', () => {
chai.expect(Sync.checkIfUserIsMissing(baseResponse)).to.equal(true);
});
it('should return true if response message is in object format', () => {
chai.expect(Sync.checkIfUserIsMissing({ ...baseResponse, data: { message: NOT_FOUND_MESSAGE } })).to.equal(true);
});
it('should return false if response has any other response', () => {
chai.expect(Sync.checkIfUserIsMissing({ ...baseResponse, data: "<html><body><h1>Yay!</h1></body></html>" })).to.equal(false);
});
it('should return false if response isn\'t a 404', () => {
// show some example, as only the 404 status should match
chai.expect(Sync.checkIfUserIsMissing({ ...baseResponse, status: 200 })).to.equal(false);
chai.expect(Sync.checkIfUserIsMissing({ ...baseResponse, status: 400 })).to.equal(false);
chai.expect(Sync.checkIfUserIsMissing({ ...baseResponse, status: 500 })).to.equal(false);
});
});
});
describe('#filterDuplicateRepositories', function () {
describe('success', function () {
const goodRepos = [{ 'org': '1', 'repo': 'sample' }, { 'org': '2', 'repo': 'test' }, { 'org': '1', 'repo': 'example' }];
const Sync = setupBasicSync();
// required to clean up between tests
afterEach(() => {
jest.restoreAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should not modify a unique list of repos', async () => {
// none should be removed from the base list
chai.expect(Sync.filterDuplicateRepositories(goodRepos)).to.deep.equal(goodRepos);
});
it('should remove duplicate repos based on name and organization', async () => {
const testRepos = [...goodRepos, goodRepos[1]];
// should remove the added duplicate
chai.expect(Sync.filterDuplicateRepositories(testRepos)).to.deep.equal(goodRepos);
});
it('should retain repos with duplicated names in different organizations', async () => {
const tweakedRepo = { ...goodRepos[0] };
tweakedRepo.org = 'other';
const testRepos = [...goodRepos, tweakedRepo];
// should not remove the tweaked repo as it's in a different org even if repo name is same
chai.expect(Sync.filterDuplicateRepositories(testRepos)).to.deep.equal(testRepos);
});
});
});
});
function setupBasicSync() {
const Sync = new GithubSync({
V: true,
d: false
});
Sync.wrap = new Wrapper('secret');
Sync.cHttp = new HttpWrapper();
Sync.stm = new StaticTeamManager();
Sync.eclipseApi = new EclipseAPI();
Sync.bots = {
'sample': ['sample-bot'],
'other-project': ['project-bot']
};
Sync.upo = new UserPermissionsOverride(`${__dirname}/perms/empty_overrides.json`);
return Sync;
}
function reposForOrgMock(repoMapping) {
jest.spyOn(Wrapper.prototype, 'getReposForOrg').mockImplementation((org) => {
return repoMapping[org];
});
}
function removeOrgExternalContributorsMock(contributors) {
jest.spyOn(Wrapper.prototype, 'getOrgCollaborators').mockImplementationOnce((org) => {
return contributors;
});
const usernames = [];
jest.spyOn(Wrapper.prototype, 'removeUserAsOutsideCollaborator').mockImplementation((org, username) => {
usernames.push(username);
});
return usernames;
}
function removeRepoExternalContributorsMock(contributors, includeEclipseAccountMocking = true) {
jest.spyOn(Wrapper.prototype, 'getRepoCollaborators').mockImplementationOnce((org) => {
return contributors;
});
const usernames = {};
jest.spyOn(Wrapper.prototype, 'removeUserAsCollaborator').mockImplementation((org, repo, username) => {
if (usernames[repo] === undefined) {
usernames[repo] = [];
}
usernames[repo].push(username);
});
if (includeEclipseAccountMocking) {
jest.spyOn(HttpWrapper.prototype, 'getRaw').mockImplementationOnce((url) => {
if (sampleUserStore[url] !== undefined) {
return { data: sampleUserStore[url] };
}
// error returned by EF API when user is missing
return new AxiosError('', 404, undefined, undefined, { data: ['User not found.'], status: 404 });
});
}
return usernames;
}
/**
* Some of the unchanging mock calls, made to simplify the tests
* @returns
*/
function updateTeamCommonMock(teamMembers, includeEclipseAccountMocking = true) {
jest.spyOn(Wrapper.prototype, 'addTeam').mockImplementation((org, teamName) => {
return {};
});
const updatedUsers = [];
const updatedTeams = [];
jest.spyOn(Wrapper.prototype, 'inviteUserToTeam').mockImplementation((org, teamName, user) => {
// will be gh handle, not EF username
updatedUsers.push(user);
if (updatedTeams.indexOf(teamName) === -1) {
updatedTeams.push(teamName);
}
});
const removedUsers = [];
jest.spyOn(Wrapper.prototype, 'removeUserFromTeam').mockImplementation((org, teamName, user) => {
removedUsers.push(user);
if (updatedTeams.indexOf(teamName) === -1) {
updatedTeams.push(teamName);
}
});
const teamUpdates = {};
jest.spyOn(Wrapper.prototype, 'editTeam').mockImplementation((org, team, options) => {
teamUpdates[team] = options;
});
jest.spyOn(Wrapper.prototype, 'getTeamMembers').mockImplementation((org, team) => {
// uses passed param to allow for different team setups to be tested
return teamMembers;
});
if (includeEclipseAccountMocking) {
jest.spyOn(HttpWrapper.prototype, 'getRaw').mockImplementation((url) => {
if (sampleUserStore[url] !== undefined) {
return { data: sampleUserStore[url] };
}
// error returned by EF API when user is missing
return new AxiosError('', 404, undefined, undefined, { data: ['User not found.'], status: 404 });
});
}
return { teamUpdates, updatedUsers, updatedTeams, removedUsers };
}
function generateExpectedTeamDescription(project, grouping) {
return `The ${grouping} access team for the ${project.name} (${project.project_id}) project: ${project.url}`;
}
/**
* Generates fake users to be used in HTTP stubbing in tests.
*/
function generateSampleUserStore() {
return {
'https://api.eclipse.org/account/profile/test-user-1': generateSampleUser('test-user-1'),
'https://api.eclipse.org/account/profile/test-user-2': generateSampleUser('test-user-2'),
'https://api.eclipse.org/account/profile/epoirier': generateSampleUser('epoirier'),
'https://api.eclipse.org/account/profile/malowe': generateSampleUser('malowe'),
'https://api.eclipse.org/github/profile/malowe': generateSampleUser('malowe'),
'https://api.eclipse.org/github/profile/epoirier': generateSampleUser('epoirier'),
'https://api.eclipse.org/github/profile/doofenshmirtz': generateSampleUser('doofenshmirtz')
};
}
function generateSampleUser(uname, ghHandle, hasSignedECA = true, isCommitter = true) {
return {
"uid": "",
"name": uname,
"picture": "",
"mail": `${uname}@eclipse-foundation.org`,
"eca": {
"signed": hasSignedECA,
"can_contribute_spec_project": hasSignedECA
},
"is_committer": isCommitter,
"first_name": "Sample",
"last_name": "Test1",
"full_name": "Sample Test1",
"publisher_agreements": {
"open-vsx": { "version": "1" }
},
"github_handle": ghHandle || uname,
"twitter_handle": "",
"org": "EF Sample 01",
"org_id": 1660,
"job_title": "Software Developer",
"website": "",
"country": {
"code": null,
"name": null
}, "bio": null,
"interests": ["Music", "Video games", "cats", "Accessibility"],
"working_groups_interests": [],
"public_fields": [],
"mail_history": [],
"mail_alternate": [],
"eca_url": `https://api.eclipse.org/account/profile/${uname}/eca`,
"projects_url": `https://api.eclipse.org/account/profile/${uname}/projects`,
"gerrit_url": `https://api.eclipse.org/account/profile/${uname}/gerrit`,
"mailinglist_url": `https://api.eclipse.org/account/profile/${uname}/mailing-list`,
"mpc_favorites_url": `https://api.eclipse.org/marketplace/favorites?name=${uname}`
};
}
function generateSampleProjects() {
return [
{
project_id: 'sample',
short_project_id: 'sample',
pp_orgs: ['eclipsefdn-webdev'],
github_repos: [{
url: 'https://github.com/eclipsefdn-webdev/spider-pig',
}],
github: {
org: 'eclipsefdn-webdev',
ignored_repos: [],
},
contributors: [{
username: 'webdev_2',
url: 'https://api.eclipse.org/account/profile/webdev_2',
}],
committers: [{
username: 'malowe',
url: 'https://api.eclipse.org/account/profile/malowe',
}, {
username: 'epoirier',
url: 'https://api.eclipse.org/account/profile/epoirier',
}],
project_leads: [{
username: 'malowe',
url: 'https://api.eclipse.org/account/profile/malowe',
}, {
username: 'cguindon',
url: 'https://api.eclipse.org/account/profile/cguindon',
}],
working_groups: [{
name: 'Cloud Development Tools',
id: 'cloud-development-tools',
}],
spec_project_working_group: [],
state: 'Regular',
security_team: {
individual_members: [],
groups: {
include_committers: true,
include_project_leads: false
}
},
}
];
}