Skip to content

Commit

Permalink
Feature/domain service (#361)
Browse files Browse the repository at this point in the history
* Added cache manager which handles caching on server. cache logic is now removed from cluster service to use cache manager instead.

* Added domain service which allows searching for a domain.

* added test for fetchDomainListNextPage and fixed bug in implementation

* add test for sortDomainList

* adding tests for getMatchingDomains

* fixup failed conflict resolution
  • Loading branch information
just-at-uber authored Jul 22, 2021
1 parent 9ce60e4 commit 9e4c44a
Show file tree
Hide file tree
Showing 17 changed files with 525 additions and 10 deletions.
24 changes: 24 additions & 0 deletions server/router/helpers/delay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2021 Uber Technologies Inc.
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

const delay = time => new Promise(resolve => setTimeout(resolve, time));

module.exports = delay;
2 changes: 2 additions & 0 deletions server/router/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
// THE SOFTWARE.

const buildQueryString = require('./build-query-string');
const delay = require('./delay');
const isAdvancedVisibilityEnabled = require('./is-advanced-visibility-enabled');
const listWorkflows = require('./list-workflows');
const mapHistoryResponse = require('./map-history-response');
Expand All @@ -28,6 +29,7 @@ const replacer = require('./replacer');

module.exports = {
buildQueryString,
delay,
isAdvancedVisibilityEnabled,
listWorkflows,
mapHistoryResponse,
Expand Down
9 changes: 7 additions & 2 deletions server/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,23 @@ const {
const { ONE_HOUR_IN_MILLISECONDS } = require('./constants');
const { listWorkflows } = require('./helpers');
const { CacheManager } = require('./managers');
const { ClusterService } = require('./services');
const { ClusterService, DomainService } = require('./services');

const router = new Router();

const clusterCacheManager = new CacheManager(ONE_HOUR_IN_MILLISECONDS);
const clusterService = new ClusterService(clusterCacheManager);

const domainCacheManager = new CacheManager(ONE_HOUR_IN_MILLISECONDS);
const domainService = new DomainService(domainCacheManager);

router.get('/api/cluster', clusterHandler(clusterService));

router.delete('/api/cluster/cache', clearCacheHandler(clusterCacheManager));

router.get('/api/domains', domainListHandler);
router.get('/api/domains', domainListHandler(domainService));

router.delete('/api/domains/cache', clearCacheHandler(domainCacheManager));

router.get('/api/domains/:domain', domainHandler);

Expand Down
9 changes: 2 additions & 7 deletions server/router/routes/domain-list-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

const domainListHandler = async ctx => {
ctx.body = await ctx.cadence.listDomains({
pageSize: 50,
nextPageToken: ctx.query.nextPageToken
? Buffer.from(ctx.query.nextPageToken, 'base64')
: undefined,
});
const domainListHandler = domainService => async ctx => {
ctx.body = await domainService.searchDomains(ctx);
};

module.exports = domainListHandler;
30 changes: 30 additions & 0 deletions server/router/services/domain-service/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) 2021 Uber Technologies Inc.
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

const DOMAIN_LIST_DELAY_MS = 100;
const DOMAIN_LIST_PAGE_SIZE = 100;
const DOMAIN_LIST_SEARCH_SIZE = 10;

module.exports = {
DOMAIN_LIST_DELAY_MS,
DOMAIN_LIST_PAGE_SIZE,
DOMAIN_LIST_SEARCH_SIZE,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2021 Uber Technologies Inc.
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

const { DOMAIN_LIST_DELAY_MS, DOMAIN_LIST_PAGE_SIZE } = require('../constants');
const { delay } = require('../../../helpers');

const fetchDomainListNextPage = async ({
ctx,
domainList = [],
nextPageToken = '',
}) => {
const data = await ctx.cadence.listDomains({
pageSize: DOMAIN_LIST_PAGE_SIZE,
nextPageToken: nextPageToken
? Buffer.from(encodeURIComponent(nextPageToken), 'base64')
: undefined,
});

domainList.splice(domainList.length, 0, ...data.domains);

if (!data.nextPageToken) {
return domainList;
}

await delay(DOMAIN_LIST_DELAY_MS);

return fetchDomainListNextPage({
ctx,
nextPageToken: data.nextPageToken,
domainList,
});
};

module.exports = fetchDomainListNextPage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) 2021 Uber Technologies Inc.
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import { delay } from '../../../helpers';
import fetchDomainListNextPage from './fetch-domain-list-next-page';

jest.mock('../../../helpers', () => ({
delay: jest.fn(),
}));

describe('fetchDomainListNextPage', () => {
const getMockContext = domainResponse => {
const ctx = {
cadence: {
listDomains: jest.fn().mockImplementation(() => domainResponse),
},
};

return ctx;
};

describe('when no nextPageToken returned', () => {
it('should return domainList.', async () => {
const domains = ['domain1', 'domain2'];
const domainResponse = {
domains,
};

const ctx = getMockContext(domainResponse);

const domainList = await fetchDomainListNextPage({
ctx,
});

expect(domainList).toEqual(domains);
});
});

describe('when nextPageToken is returned', () => {
it('should call delay and should call itself again to get next domain list page.', async () => {
const nextPageToken = '1234';
const domains1 = ['domain1', 'domain2'];
const domains2 = ['domain3', 'domain4'];
const domainResponse = {
domains: domains1,
nextPageToken,
};

const ctx = getMockContext(domainResponse);

delay.mockImplementation(() => {
domainResponse.domains = domains2;
domainResponse.nextPageToken = null;
});

const domainList = await fetchDomainListNextPage({
ctx,
});

expect(domainList).toEqual([...domains1, ...domains2]);
});
});
});
31 changes: 31 additions & 0 deletions server/router/services/domain-service/helpers/fetch-domain-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) 2021 Uber Technologies Inc.
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

const fetchDomainListNextPage = require('./fetch-domain-list-next-page');
const sortDomainList = require('./sort-domain-list');

const fetchDomainList = ctx => async () => {
const domainList = await fetchDomainListNextPage({ ctx });

return sortDomainList(domainList);
};

module.exports = fetchDomainList;
27 changes: 27 additions & 0 deletions server/router/services/domain-service/helpers/get-domain-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2021 Uber Technologies Inc.
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

const fetchDomainList = require('./fetch-domain-list');

const getDomainList = ({ cacheManager, ctx }) =>
cacheManager.get(fetchDomainList(ctx));

module.exports = getDomainList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2021 Uber Technologies Inc.
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

const { DOMAIN_LIST_SEARCH_SIZE } = require('../constants');

const getMatchingDomains = ({ domainList, querystring }) => {
if (!querystring) {
return domainList.slice(0, DOMAIN_LIST_SEARCH_SIZE);
}

const matchedDomainList = [];

for (let i = 0; i < domainList.length; i++) {
if (matchedDomainList.length === DOMAIN_LIST_SEARCH_SIZE) {
return matchedDomainList;
}

const domain = domainList[i];

if (domain.domainInfo.name.indexOf(querystring) !== -1) {
matchedDomainList.push(domain);
}
}

return matchedDomainList;
};

module.exports = getMatchingDomains;
Loading

0 comments on commit 9e4c44a

Please sign in to comment.