From 555987d48556b2ed0fa5a987d0fe1e59163a8c48 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Fri, 6 Oct 2023 20:41:45 +0530 Subject: [PATCH 01/12] feat: :sparkles: taxonomy and terms implementation for typescript --- types/stack/taxonomy/index.d.ts | 22 ++++++++++++++++++++++ types/stack/taxonomy/terms/index.d.ts | 19 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 types/stack/taxonomy/index.d.ts create mode 100644 types/stack/taxonomy/terms/index.d.ts diff --git a/types/stack/taxonomy/index.d.ts b/types/stack/taxonomy/index.d.ts new file mode 100644 index 00000000..845d9b1b --- /dev/null +++ b/types/stack/taxonomy/index.d.ts @@ -0,0 +1,22 @@ +import { AnyProperty, SystemFields } from "../../utility/fields"; +import { Creatable, Queryable, SystemFunction } from "../../utility/operations"; +import { Term, Terms } from "../taxonomy/terms" + +export interface Taxonomy extends SystemFields, SystemFunction { + term(): Terms + term(uid: string): Term +} + +export interface Taxonomy extends SystemFields, SystemFunction { +} + +export interface Taxonomies extends Queryable { +} + +export interface Taxonomies extends Creatable { +} + +export interface TaxonomyData extends AnyProperty { + name: string + taxonomy_uid: string +} diff --git a/types/stack/taxonomy/terms/index.d.ts b/types/stack/taxonomy/terms/index.d.ts new file mode 100644 index 00000000..1334636d --- /dev/null +++ b/types/stack/taxonomy/terms/index.d.ts @@ -0,0 +1,19 @@ +import { AnyProperty, SystemFields } from "../../../utility/fields"; +import { Creatable, Queryable, SystemFunction } from "../../../utility/operations"; + +export interface Term extends SystemFields, SystemFunction { + ancestors(data: {term_uid: TermData, include_children_count: boolean, include_referenced_entries_count: boolean, include_count: boolean, skip: number, limit: number}): Promise +} + +export interface Term extends Creatable { +} + +export interface Terms extends Queryable { +} + +export interface TermData extends AnyProperty { + name: string + term_uid: string + taxonomy_uid: string + parent_uid?: string +} From 851dd364b34ec351424f4503607bc118a6a19d40 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Mon, 9 Oct 2023 12:25:01 +0530 Subject: [PATCH 02/12] fix: :bug: taxonomy bug fix --- lib/stack/taxonomy/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stack/taxonomy/index.js b/lib/stack/taxonomy/index.js index ffd13b79..b9d03df5 100644 --- a/lib/stack/taxonomy/index.js +++ b/lib/stack/taxonomy/index.js @@ -116,7 +116,7 @@ export function Taxonomy (http, data = {}) { } } export function TaxonomyCollection (http, data) { - const obj = cloneDeep(data.taxonomy) || [] + const obj = cloneDeep(data.taxonomies) || [] const taxonomyCollection = obj.map((userdata) => { return new Taxonomy(http, { taxonomy: userdata, stackHeaders: data.stackHeaders }) }) From 35ae01764a1a5020a74eee206be990d017993170 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Mon, 9 Oct 2023 18:23:46 +0530 Subject: [PATCH 03/12] feat: :sparkles: terms implementaion with descendants and move function --- types/stack/index.d.ts | 4 ++++ types/stack/taxonomy/index.d.ts | 4 +--- types/stack/taxonomy/terms/index.d.ts | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/types/stack/index.d.ts b/types/stack/index.d.ts index 913585ec..adf0d85d 100644 --- a/types/stack/index.d.ts +++ b/types/stack/index.d.ts @@ -18,6 +18,7 @@ import { Release, Releases } from "./release"; import { Role, Roles } from "./role"; import { Webhook, Webhooks } from "./webhook"; import { Workflow, Workflows } from "./workflow"; +import { Taxonomy, Taxonomies } from "./taxonomy"; export interface StackConfig { api_key:string @@ -92,4 +93,7 @@ export interface Stack extends SystemFields { unShare(email: string): Promise role(): Roles role(uid: string): Role + + taxonomy(): Taxonomy + taxonomies(uid: string): Taxonomies } diff --git a/types/stack/taxonomy/index.d.ts b/types/stack/taxonomy/index.d.ts index 845d9b1b..6c265ddb 100644 --- a/types/stack/taxonomy/index.d.ts +++ b/types/stack/taxonomy/index.d.ts @@ -6,9 +6,6 @@ export interface Taxonomy extends SystemFields, SystemFunction { term(): Terms term(uid: string): Term } - -export interface Taxonomy extends SystemFields, SystemFunction { -} export interface Taxonomies extends Queryable { } @@ -19,4 +16,5 @@ export interface Taxonomies extends Creatable { ancestors(data: {term_uid: TermData, include_children_count: boolean, include_referenced_entries_count: boolean, include_count: boolean, skip: number, limit: number}): Promise + descendants(data: {term_uid: TermData, include_children_count: boolean, include_referenced_entries_count: boolean, include_count: boolean, skip: number, limit: number}): Promise + move(data: {term_uid: TermData, force: boolean}): Promise } export interface Term extends Creatable { @@ -14,6 +16,6 @@ export interface Terms extends Queryable { export interface TermData extends AnyProperty { name: string term_uid: string - taxonomy_uid: string parent_uid?: string + order: number } From e383a947076b5c66443e509119a74945549b749c Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Mon, 9 Oct 2023 19:10:48 +0530 Subject: [PATCH 04/12] fix: :bug: taxonomy bug fix in query unit test case --- test/unit/taxonomy-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/taxonomy-test.js b/test/unit/taxonomy-test.js index b9435185..b5f09386 100644 --- a/test/unit/taxonomy-test.js +++ b/test/unit/taxonomy-test.js @@ -44,7 +44,7 @@ describe('Contentstack Taxonomy test', () => { it('Taxonomies query test', done => { var mock = new MockAdapter(Axios) mock.onGet('/taxonomies').reply(200, { - taxonomy: [ + taxonomies: [ taxonomyMock ] }) From ee4ffed1e57bb484d6a52685175ec50ddb600a11 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Mon, 9 Oct 2023 19:43:27 +0530 Subject: [PATCH 05/12] fix: taxonomy and terms fixes --- types/stack/index.d.ts | 4 ++-- types/stack/taxonomy/terms/index.d.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/types/stack/index.d.ts b/types/stack/index.d.ts index adf0d85d..a1363af3 100644 --- a/types/stack/index.d.ts +++ b/types/stack/index.d.ts @@ -94,6 +94,6 @@ export interface Stack extends SystemFields { role(): Roles role(uid: string): Role - taxonomy(): Taxonomy - taxonomies(uid: string): Taxonomies + taxonomy(): Taxonomies + taxonomy(uid: string): Taxonomy } diff --git a/types/stack/taxonomy/terms/index.d.ts b/types/stack/taxonomy/terms/index.d.ts index c96e1de7..f61a860f 100644 --- a/types/stack/taxonomy/terms/index.d.ts +++ b/types/stack/taxonomy/terms/index.d.ts @@ -2,9 +2,9 @@ import { AnyProperty, SystemFields } from "../../../utility/fields"; import { Creatable, Queryable, SystemFunction } from "../../../utility/operations"; export interface Term extends SystemFields, SystemFunction { - ancestors(data: {term_uid: TermData, include_children_count: boolean, include_referenced_entries_count: boolean, include_count: boolean, skip: number, limit: number}): Promise - descendants(data: {term_uid: TermData, include_children_count: boolean, include_referenced_entries_count: boolean, include_count: boolean, skip: number, limit: number}): Promise - move(data: {term_uid: TermData, force: boolean}): Promise + ancestors(data: { include_children_count?: boolean, include_referenced_entries_count?: boolean, include_count?: boolean, skip?: number, limit?: number}): Promise + descendants(data: { include_children_count?: boolean, include_referenced_entries_count?: boolean, include_count?: boolean, skip?: number, limit?: number}): Promise + move(data: { term: { parent_uid?: string, order: number } }, force?: boolean): Promise } export interface Term extends Creatable { From 0abd9509333415e9f20dc2e7a038c39aaeac9e3d Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Wed, 11 Oct 2023 16:57:58 +0530 Subject: [PATCH 06/12] fix: :bug: error message fix on refresh token error --- lib/core/concurrency-queue.js | 6 +- lib/stack/roles/index.js | 2 - test/unit/concurrency-Queue-test.js | 648 ++++++++++++++-------------- 3 files changed, 337 insertions(+), 319 deletions(-) diff --git a/lib/core/concurrency-queue.js b/lib/core/concurrency-queue.js index 21e3fef3..321383af 100644 --- a/lib/core/concurrency-queue.js +++ b/lib/core/concurrency-queue.js @@ -147,13 +147,13 @@ export function ConcurrencyQueue ({ axios, config }) { axios.httpClientParams.headers.authtoken = token.authtoken this.config.authtoken = token.authtoken } - }).catch(() => { + }).catch((error) => { this.queue.forEach(queueItem => { queueItem.reject({ errorCode: '401', - errorMessage: 'Unable to refresh token', + errorMessage: (error instanceof Error) ? error.message : error, code: 'Unauthorized', - message: 'Request failed with status code 401', + message: 'Unable to refresh token', name: 'Token Error', config: queueItem.request }) diff --git a/lib/stack/roles/index.js b/lib/stack/roles/index.js index 31ff38eb..483440ad 100644 --- a/lib/stack/roles/index.js +++ b/lib/stack/roles/index.js @@ -1,7 +1,5 @@ import cloneDeep from 'lodash/cloneDeep' import { create, update, deleteEntity, fetch, query, fetchAll } from '../../entity' -import ContentstackCollection from '../../contentstackCollection' -import error from '../../core/contentstackError' /** * A role is a collection of permissions that will be applicable to all the users who are assigned this role. Read more about Roles. * @namespace Role diff --git a/test/unit/concurrency-Queue-test.js b/test/unit/concurrency-Queue-test.js index 8d52fa7e..767d248f 100644 --- a/test/unit/concurrency-Queue-test.js +++ b/test/unit/concurrency-Queue-test.js @@ -163,326 +163,346 @@ describe('Concurrency queue test', () => { .catch(done) }) - it('Initialize with bad axios instance', done => { - try { - new ConcurrencyQueue({ axios: undefined }) - expect.fail('Undefined axios should fail') - } catch (error) { - expect(error.message).to.be.equal('Axios instance is not present') - done() - } - }) - - it('Initialization with default config test', done => { - const queue = makeConcurrencyQueue() - expect(queue.config.maxRequests).to.be.equal(5) - expect(queue.config.retryLimit).to.be.equal(5) - expect(queue.config.retryDelay).to.be.equal(300) - expect(queue.queue.length).to.be.equal(0) - expect(queue.running.length).to.be.equal(0) - expect(queue.interceptors.request).to.be.equal(0) - expect(queue.interceptors.response).to.be.equal(0) - done() - }) - - it('Initialization with custom config test', done => { - const queue = makeConcurrencyQueue({ maxRequests: 20, retryLimit: 2, retryDelay: 1000 }) - expect(queue.config.maxRequests).to.be.equal(20) - expect(queue.config.retryLimit).to.be.equal(2) - expect(queue.config.retryDelay).to.be.equal(1000) - expect(queue.queue.length).to.be.equal(0) - expect(queue.running.length).to.be.equal(0) - done() - }) - - it('Detach interceptors test', done => { - const queue = makeConcurrencyQueue({ maxRequests: 20 }) - queue.detach() - expect(queue.config.maxRequests).to.be.equal(20) - expect(queue.config.retryLimit).to.be.equal(5) - expect(queue.config.retryDelay).to.be.equal(300) - expect(queue.interceptors.request).to.be.equal(null) - expect(queue.interceptors.response).to.be.equal(null) - done() - }) - - it('Initialization with custom config negative value test', done => { - try { - makeConcurrencyQueue({ maxRequests: -10 }) - expect.fail('Negative concurrency queue should fail') - } catch (error) { - expect(error.message).to.be.equal('Concurrency Manager Error: minimum concurrent requests is 1') - done() - } - }) - - it('Initialization with custom config retry limit negative value test', done => { - try { - makeConcurrencyQueue({ retryLimit: -10 }) - expect.fail('Negative retry limit should fail') - } catch (error) { - expect(error.message).to.be.equal('Retry Policy Error: minimum retry limit is 1') - done() - } - }) - - it('Initialization with custom config retry delay value test', done => { - try { - makeConcurrencyQueue({ retryDelay: 10 }) - expect.fail('Retry delay should be min 300ms') - } catch (error) { - expect(error.message).to.be.equal('Retry Policy Error: minimum retry delay for requests is 300') - done() - } - }) - - it('Concurrency with 100 passing requests Queue tests', done => { - Promise.all(sequence(100).map(() => api.get('/testReq'))) - .then((responses) => { - return responses.map(r => r.data) - }) - .then(objects => { - expect(objects.length).to.be.equal(100) - done() - }) - .catch(done) - }) - - it('Concurrency with 100 failing requests retry on error false tests', done => { - Promise.all(sequence(100).map(() => wrapPromise(api.get('/fail')))) - .then((responses) => { - return responses.map(r => r.data) - }) - .then(objects => { - expect(objects.length).to.be.equal(100) - done() - }) - .catch(done) - }) - - it('Concurrency with 10 timeout requests', done => { - const client = Axios.create({ - baseURL: `${host}:${port}` - }) - const concurrency = new ConcurrencyQueue({ axios: client, config: { retryOnError: true, timeout: 250 } }) - client.get('http://localhost:4444/timeout', { - timeout: 250 - }).then(function (res) { - expect(res).to.be.equal(null) - done() - }).catch(function (err) { - concurrency.detach() - expect(err.response.status).to.be.equal(408) - expect(err.response.statusText).to.be.equal('timeout of 250ms exceeded') - done() - }).catch(done) - }) - it('Concurrency with 10 timeout requests retry', done => { - retryDelayOptionsStub.returns(5000) - const client = Axios.create({ - baseURL: `${host}:${port}` - }) - const concurrency = new ConcurrencyQueue({ axios: client, config: { retryCondition: (error) => { - if (error.response.status === 408) { - return true - } - return false - }, - logHandler: logHandlerStub, - retryDelayOptions: { - base: retryDelayOptionsStub() - }, - retryLimit: 2, - retryOnError: true, timeout: 250 } }) - client.get('http://localhost:4444/timeout', { - timeout: 250 - }).then(function (res) { - expect(res).to.be.equal(null) - done() - }).catch(function (err) { - concurrency.detach() - expect(err.response.status).to.be.equal(408) - expect(err.response.statusText).to.be.equal('timeout of 250ms exceeded') - done() - }).catch(done) - }) - - it('Concurrency with 100 failing requests retry on error with no retry condition tests', done => { - reconfigureQueue({ retryCondition: (error) => false }) - Promise.all(sequence(100).map(() => wrapPromise(api.get('/fail')))) - .then((responses) => { - return responses.map(r => r.data) - }) - .then(objects => { - expect(logHandlerStub.callCount).to.be.equal(0) - expect(objects.length).to.be.equal(100) - done() - }) - .catch(done) - }) - - it('Concurrency with 10 failing requests with retry tests', done => { - reconfigureQueue() - Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) - .then((responses) => { - return responses.map(r => r.data) - }) - .then(objects => { - expect(logHandlerStub.callCount).to.be.equal(50) - expect(objects.length).to.be.equal(10) - done() - }) - .catch(done) - }) - - it('Concurrency with 10 rate limit requests Queue tests', done => { - reconfigureQueue() - Promise.all(sequence(10).map(() => wrapPromise(api.get('/ratelimit')))) - .then((responses) => { - return responses.map(r => r.data) - }) - .then(objects => { - expect(logHandlerStub.callCount).to.be.equal(50) - expect(objects.length).to.be.equal(10) - done() - }) - .catch(done) - }) - - it('Concurrency with 10 asset upload with rate limit error', done => { - reconfigureQueue() - const fuc = (pathcontent) => { - return () => { - const formData = new FormData() - const uploadStream = createReadStream(path.join(__dirname, '../api/mock/upload.html')) - formData.append('asset[upload]', uploadStream) - return formData - } - } - - Promise.all(sequence(10).map(() => wrapPromise(api.post('/assetUpload', fuc())))) - .then((responses) => { - return responses.map(r => r.data) - }) - .then(objects => { - expect(logHandlerStub.callCount).to.be.equal(10) - expect(objects.length).to.be.equal(10) - done() - }) - .catch(done) - }) - - it('Concurrency with 20 request and 1 rate limit request tests', done => { - reconfigureQueue() - Promise.all( - [ - ...wrapPromiseInArray(api.get('/testReq'), 5), - ...wrapPromiseInArray(api.get('/ratelimit'), 1), - ...wrapPromiseInArray(api.get('/testReq'), 15) - ] - ) - .then((responses) => { - return responses.map(r => r.data) - }) - .then(objects => { - expect(logHandlerStub.callCount).to.be.equal(5) - expect(objects.length).to.be.equal(21) - done() - }) - .catch(done) - }) - - it('Concurrency with 20 request and 1 rate limit request tests', done => { - reconfigureQueue({ retryOnError: false }) - Promise.all(sequence(20).map(() => wrapPromise(api.get('/timeout')))) - .then((responses) => { - expect.fail('Should not get response') - }) - .catch(done) - setTimeout(() => { - concurrencyQueue.clear() - expect(concurrencyQueue.queue.length).to.equal(0) - done() - }, 1000) - }) - - it('Concurrency retry on custome backoff test', done => { - reconfigureQueue({ - retryCondition: retryConditionStub, - retryDelayOptions: { - customBackoff: retryDelayOptionsStub - } - }) - - retryConditionStub.returns(true) - retryDelayOptionsStub.onCall(0).returns(200) - retryDelayOptionsStub.onCall(1).returns(300) - retryDelayOptionsStub.onCall(2).returns(-1) - retryDelayOptionsStub.returns(200) - Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) - .then((responses) => { - return responses.map(r => r.data) - }) - .then(objects => { - expect(logHandlerStub.callCount).to.be.equal(45) - expect(objects.length).to.be.equal(10) - done() - }) - .catch(done) - }) - - it('Concurrency retry delay with base request test', done => { - retryConditionStub.returns(true) - retryDelayOptionsStub.returns(200) - - reconfigureQueue({ - retryCondition: retryConditionStub, - retryDelayOptions: { - base: retryDelayOptionsStub() + it('should give passed error message when refreshToken function fails', done => { + const axios = client({ + baseURL: `${host}:${port}`, + authorization: 'Bearer ', + logHandler: logHandlerStub, + refreshToken: () => { + return new Promise((resolve, reject) => { + reject(new Error('Rejected in Promise')) + }) } }) - - Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) - .then((responses) => { - return responses.map(r => r.data) - }) - .then(objects => { - expect(logHandlerStub.callCount).to.be.equal(50) - expect(objects.length).to.be.equal(10) - done() - }) - .catch(done) - }) - - it('Concurrency update authorization to not pass authtoken', done => { - api.get('/fail', { headers: { authorization: 'authorization' } }) - .then((response) => { - expect(response).to.equal(undefined) - done() - }) - .catch((error) => { - expect(error.config.headers.authtoken).to.equal(undefined) - expect(error.config.headers.authorization).to.equal('authorization') + Promise.all(sequence(3).map(() => axios.axiosInstance.get('/unauthorized'))) + .catch(err => { + expect(err.errorCode).to.equal('401') + expect(err.errorMessage).to.equal('Rejected in Promise') + expect(err.message).to.equal('Unable to refresh token') done() }) - .catch(done) }) - it('Request to fail with no response', done => { - reconfigureQueue() - const mock = new MockAdapter(api) - mock.onGet('/netError').networkError() - api.get('/netError') - .then((response) => { - expect(response).to.equal(undefined) - done() - }) - .catch((error) => { - expect(error.esponse).to.equal(undefined) - done() - }) - .catch(done) - }) + // it('Initialize with bad axios instance', done => { + // try { + // new ConcurrencyQueue({ axios: undefined }) + // expect.fail('Undefined axios should fail') + // } catch (error) { + // expect(error.message).to.be.equal('Axios instance is not present') + // done() + // } + // }) + + // it('Initialization with default config test', done => { + // const queue = makeConcurrencyQueue() + // expect(queue.config.maxRequests).to.be.equal(5) + // expect(queue.config.retryLimit).to.be.equal(5) + // expect(queue.config.retryDelay).to.be.equal(300) + // expect(queue.queue.length).to.be.equal(0) + // expect(queue.running.length).to.be.equal(0) + // expect(queue.interceptors.request).to.be.equal(0) + // expect(queue.interceptors.response).to.be.equal(0) + // done() + // }) + + // it('Initialization with custom config test', done => { + // const queue = makeConcurrencyQueue({ maxRequests: 20, retryLimit: 2, retryDelay: 1000 }) + // expect(queue.config.maxRequests).to.be.equal(20) + // expect(queue.config.retryLimit).to.be.equal(2) + // expect(queue.config.retryDelay).to.be.equal(1000) + // expect(queue.queue.length).to.be.equal(0) + // expect(queue.running.length).to.be.equal(0) + // done() + // }) + + // it('Detach interceptors test', done => { + // const queue = makeConcurrencyQueue({ maxRequests: 20 }) + // queue.detach() + // expect(queue.config.maxRequests).to.be.equal(20) + // expect(queue.config.retryLimit).to.be.equal(5) + // expect(queue.config.retryDelay).to.be.equal(300) + // expect(queue.interceptors.request).to.be.equal(null) + // expect(queue.interceptors.response).to.be.equal(null) + // done() + // }) + + // it('Initialization with custom config negative value test', done => { + // try { + // makeConcurrencyQueue({ maxRequests: -10 }) + // expect.fail('Negative concurrency queue should fail') + // } catch (error) { + // expect(error.message).to.be.equal('Concurrency Manager Error: minimum concurrent requests is 1') + // done() + // } + // }) + + // it('Initialization with custom config retry limit negative value test', done => { + // try { + // makeConcurrencyQueue({ retryLimit: -10 }) + // expect.fail('Negative retry limit should fail') + // } catch (error) { + // expect(error.message).to.be.equal('Retry Policy Error: minimum retry limit is 1') + // done() + // } + // }) + + // it('Initialization with custom config retry delay value test', done => { + // try { + // makeConcurrencyQueue({ retryDelay: 10 }) + // expect.fail('Retry delay should be min 300ms') + // } catch (error) { + // expect(error.message).to.be.equal('Retry Policy Error: minimum retry delay for requests is 300') + // done() + // } + // }) + + // it('Concurrency with 100 passing requests Queue tests', done => { + // Promise.all(sequence(100).map(() => api.get('/testReq'))) + // .then((responses) => { + // return responses.map(r => r.data) + // }) + // .then(objects => { + // expect(objects.length).to.be.equal(100) + // done() + // }) + // .catch(done) + // }) + + // it('Concurrency with 100 failing requests retry on error false tests', done => { + // Promise.all(sequence(100).map(() => wrapPromise(api.get('/fail')))) + // .then((responses) => { + // return responses.map(r => r.data) + // }) + // .then(objects => { + // expect(objects.length).to.be.equal(100) + // done() + // }) + // .catch(done) + // }) + + // it('Concurrency with 10 timeout requests', done => { + // const client = Axios.create({ + // baseURL: `${host}:${port}` + // }) + // const concurrency = new ConcurrencyQueue({ axios: client, config: { retryOnError: true, timeout: 250 } }) + // client.get('http://localhost:4444/timeout', { + // timeout: 250 + // }).then(function (res) { + // expect(res).to.be.equal(null) + // done() + // }).catch(function (err) { + // concurrency.detach() + // expect(err.response.status).to.be.equal(408) + // expect(err.response.statusText).to.be.equal('timeout of 250ms exceeded') + // done() + // }).catch(done) + // }) + // it('Concurrency with 10 timeout requests retry', done => { + // retryDelayOptionsStub.returns(5000) + // const client = Axios.create({ + // baseURL: `${host}:${port}` + // }) + // const concurrency = new ConcurrencyQueue({ axios: client, config: { retryCondition: (error) => { + // if (error.response.status === 408) { + // return true + // } + // return false + // }, + // logHandler: logHandlerStub, + // retryDelayOptions: { + // base: retryDelayOptionsStub() + // }, + // retryLimit: 2, + // retryOnError: true, timeout: 250 } }) + // client.get('http://localhost:4444/timeout', { + // timeout: 250 + // }).then(function (res) { + // expect(res).to.be.equal(null) + // done() + // }).catch(function (err) { + // concurrency.detach() + // expect(err.response.status).to.be.equal(408) + // expect(err.response.statusText).to.be.equal('timeout of 250ms exceeded') + // done() + // }).catch(done) + // }) + + // it('Concurrency with 100 failing requests retry on error with no retry condition tests', done => { + // reconfigureQueue({ retryCondition: (error) => false }) + // Promise.all(sequence(100).map(() => wrapPromise(api.get('/fail')))) + // .then((responses) => { + // return responses.map(r => r.data) + // }) + // .then(objects => { + // expect(logHandlerStub.callCount).to.be.equal(0) + // expect(objects.length).to.be.equal(100) + // done() + // }) + // .catch(done) + // }) + + // it('Concurrency with 10 failing requests with retry tests', done => { + // reconfigureQueue() + // Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) + // .then((responses) => { + // return responses.map(r => r.data) + // }) + // .then(objects => { + // expect(logHandlerStub.callCount).to.be.equal(50) + // expect(objects.length).to.be.equal(10) + // done() + // }) + // .catch(done) + // }) + + // it('Concurrency with 10 rate limit requests Queue tests', done => { + // reconfigureQueue() + // Promise.all(sequence(10).map(() => wrapPromise(api.get('/ratelimit')))) + // .then((responses) => { + // return responses.map(r => r.data) + // }) + // .then(objects => { + // expect(logHandlerStub.callCount).to.be.equal(50) + // expect(objects.length).to.be.equal(10) + // done() + // }) + // .catch(done) + // }) + + // it('Concurrency with 10 asset upload with rate limit error', done => { + // reconfigureQueue() + // const fuc = (pathcontent) => { + // return () => { + // const formData = new FormData() + // const uploadStream = createReadStream(path.join(__dirname, '../api/mock/upload.html')) + // formData.append('asset[upload]', uploadStream) + // return formData + // } + // } + + // Promise.all(sequence(10).map(() => wrapPromise(api.post('/assetUpload', fuc())))) + // .then((responses) => { + // return responses.map(r => r.data) + // }) + // .then(objects => { + // expect(logHandlerStub.callCount).to.be.equal(10) + // expect(objects.length).to.be.equal(10) + // done() + // }) + // .catch(done) + // }) + + // it('Concurrency with 20 request and 1 rate limit request tests', done => { + // reconfigureQueue() + // Promise.all( + // [ + // ...wrapPromiseInArray(api.get('/testReq'), 5), + // ...wrapPromiseInArray(api.get('/ratelimit'), 1), + // ...wrapPromiseInArray(api.get('/testReq'), 15) + // ] + // ) + // .then((responses) => { + // return responses.map(r => r.data) + // }) + // .then(objects => { + // expect(logHandlerStub.callCount).to.be.equal(5) + // expect(objects.length).to.be.equal(21) + // done() + // }) + // .catch(done) + // }) + + // it('Concurrency with 20 request and 1 rate limit request tests', done => { + // reconfigureQueue({ retryOnError: false }) + // Promise.all(sequence(20).map(() => wrapPromise(api.get('/timeout')))) + // .then((responses) => { + // expect.fail('Should not get response') + // }) + // .catch(done) + // setTimeout(() => { + // concurrencyQueue.clear() + // expect(concurrencyQueue.queue.length).to.equal(0) + // done() + // }, 1000) + // }) + + // it('Concurrency retry on custome backoff test', done => { + // reconfigureQueue({ + // retryCondition: retryConditionStub, + // retryDelayOptions: { + // customBackoff: retryDelayOptionsStub + // } + // }) + + // retryConditionStub.returns(true) + // retryDelayOptionsStub.onCall(0).returns(200) + // retryDelayOptionsStub.onCall(1).returns(300) + // retryDelayOptionsStub.onCall(2).returns(-1) + // retryDelayOptionsStub.returns(200) + // Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) + // .then((responses) => { + // return responses.map(r => r.data) + // }) + // .then(objects => { + // expect(logHandlerStub.callCount).to.be.equal(45) + // expect(objects.length).to.be.equal(10) + // done() + // }) + // .catch(done) + // }) + + // it('Concurrency retry delay with base request test', done => { + // retryConditionStub.returns(true) + // retryDelayOptionsStub.returns(200) + + // reconfigureQueue({ + // retryCondition: retryConditionStub, + // retryDelayOptions: { + // base: retryDelayOptionsStub() + // } + // }) + + // Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) + // .then((responses) => { + // return responses.map(r => r.data) + // }) + // .then(objects => { + // expect(logHandlerStub.callCount).to.be.equal(50) + // expect(objects.length).to.be.equal(10) + // done() + // }) + // .catch(done) + // }) + + // it('Concurrency update authorization to not pass authtoken', done => { + // api.get('/fail', { headers: { authorization: 'authorization' } }) + // .then((response) => { + // expect(response).to.equal(undefined) + // done() + // }) + // .catch((error) => { + // expect(error.config.headers.authtoken).to.equal(undefined) + // expect(error.config.headers.authorization).to.equal('authorization') + // done() + // }) + // .catch(done) + // }) + + // it('Request to fail with no response', done => { + // reconfigureQueue() + // const mock = new MockAdapter(api) + // mock.onGet('/netError').networkError() + // api.get('/netError') + // .then((response) => { + // expect(response).to.equal(undefined) + // done() + // }) + // .catch((error) => { + // expect(error.esponse).to.equal(undefined) + // done() + // }) + // .catch(done) + // }) }) function makeConcurrencyQueue (config) { From ea0468475616139e55551afc0c766853702548cc Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Wed, 11 Oct 2023 17:36:55 +0530 Subject: [PATCH 07/12] refactor: uncommented unit test cases --- test/unit/concurrency-Queue-test.js | 640 ++++++++++++++-------------- 1 file changed, 320 insertions(+), 320 deletions(-) diff --git a/test/unit/concurrency-Queue-test.js b/test/unit/concurrency-Queue-test.js index 767d248f..04a6fb58 100644 --- a/test/unit/concurrency-Queue-test.js +++ b/test/unit/concurrency-Queue-test.js @@ -183,326 +183,326 @@ describe('Concurrency queue test', () => { }) }) - // it('Initialize with bad axios instance', done => { - // try { - // new ConcurrencyQueue({ axios: undefined }) - // expect.fail('Undefined axios should fail') - // } catch (error) { - // expect(error.message).to.be.equal('Axios instance is not present') - // done() - // } - // }) - - // it('Initialization with default config test', done => { - // const queue = makeConcurrencyQueue() - // expect(queue.config.maxRequests).to.be.equal(5) - // expect(queue.config.retryLimit).to.be.equal(5) - // expect(queue.config.retryDelay).to.be.equal(300) - // expect(queue.queue.length).to.be.equal(0) - // expect(queue.running.length).to.be.equal(0) - // expect(queue.interceptors.request).to.be.equal(0) - // expect(queue.interceptors.response).to.be.equal(0) - // done() - // }) - - // it('Initialization with custom config test', done => { - // const queue = makeConcurrencyQueue({ maxRequests: 20, retryLimit: 2, retryDelay: 1000 }) - // expect(queue.config.maxRequests).to.be.equal(20) - // expect(queue.config.retryLimit).to.be.equal(2) - // expect(queue.config.retryDelay).to.be.equal(1000) - // expect(queue.queue.length).to.be.equal(0) - // expect(queue.running.length).to.be.equal(0) - // done() - // }) - - // it('Detach interceptors test', done => { - // const queue = makeConcurrencyQueue({ maxRequests: 20 }) - // queue.detach() - // expect(queue.config.maxRequests).to.be.equal(20) - // expect(queue.config.retryLimit).to.be.equal(5) - // expect(queue.config.retryDelay).to.be.equal(300) - // expect(queue.interceptors.request).to.be.equal(null) - // expect(queue.interceptors.response).to.be.equal(null) - // done() - // }) - - // it('Initialization with custom config negative value test', done => { - // try { - // makeConcurrencyQueue({ maxRequests: -10 }) - // expect.fail('Negative concurrency queue should fail') - // } catch (error) { - // expect(error.message).to.be.equal('Concurrency Manager Error: minimum concurrent requests is 1') - // done() - // } - // }) - - // it('Initialization with custom config retry limit negative value test', done => { - // try { - // makeConcurrencyQueue({ retryLimit: -10 }) - // expect.fail('Negative retry limit should fail') - // } catch (error) { - // expect(error.message).to.be.equal('Retry Policy Error: minimum retry limit is 1') - // done() - // } - // }) - - // it('Initialization with custom config retry delay value test', done => { - // try { - // makeConcurrencyQueue({ retryDelay: 10 }) - // expect.fail('Retry delay should be min 300ms') - // } catch (error) { - // expect(error.message).to.be.equal('Retry Policy Error: minimum retry delay for requests is 300') - // done() - // } - // }) - - // it('Concurrency with 100 passing requests Queue tests', done => { - // Promise.all(sequence(100).map(() => api.get('/testReq'))) - // .then((responses) => { - // return responses.map(r => r.data) - // }) - // .then(objects => { - // expect(objects.length).to.be.equal(100) - // done() - // }) - // .catch(done) - // }) - - // it('Concurrency with 100 failing requests retry on error false tests', done => { - // Promise.all(sequence(100).map(() => wrapPromise(api.get('/fail')))) - // .then((responses) => { - // return responses.map(r => r.data) - // }) - // .then(objects => { - // expect(objects.length).to.be.equal(100) - // done() - // }) - // .catch(done) - // }) - - // it('Concurrency with 10 timeout requests', done => { - // const client = Axios.create({ - // baseURL: `${host}:${port}` - // }) - // const concurrency = new ConcurrencyQueue({ axios: client, config: { retryOnError: true, timeout: 250 } }) - // client.get('http://localhost:4444/timeout', { - // timeout: 250 - // }).then(function (res) { - // expect(res).to.be.equal(null) - // done() - // }).catch(function (err) { - // concurrency.detach() - // expect(err.response.status).to.be.equal(408) - // expect(err.response.statusText).to.be.equal('timeout of 250ms exceeded') - // done() - // }).catch(done) - // }) - // it('Concurrency with 10 timeout requests retry', done => { - // retryDelayOptionsStub.returns(5000) - // const client = Axios.create({ - // baseURL: `${host}:${port}` - // }) - // const concurrency = new ConcurrencyQueue({ axios: client, config: { retryCondition: (error) => { - // if (error.response.status === 408) { - // return true - // } - // return false - // }, - // logHandler: logHandlerStub, - // retryDelayOptions: { - // base: retryDelayOptionsStub() - // }, - // retryLimit: 2, - // retryOnError: true, timeout: 250 } }) - // client.get('http://localhost:4444/timeout', { - // timeout: 250 - // }).then(function (res) { - // expect(res).to.be.equal(null) - // done() - // }).catch(function (err) { - // concurrency.detach() - // expect(err.response.status).to.be.equal(408) - // expect(err.response.statusText).to.be.equal('timeout of 250ms exceeded') - // done() - // }).catch(done) - // }) - - // it('Concurrency with 100 failing requests retry on error with no retry condition tests', done => { - // reconfigureQueue({ retryCondition: (error) => false }) - // Promise.all(sequence(100).map(() => wrapPromise(api.get('/fail')))) - // .then((responses) => { - // return responses.map(r => r.data) - // }) - // .then(objects => { - // expect(logHandlerStub.callCount).to.be.equal(0) - // expect(objects.length).to.be.equal(100) - // done() - // }) - // .catch(done) - // }) - - // it('Concurrency with 10 failing requests with retry tests', done => { - // reconfigureQueue() - // Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) - // .then((responses) => { - // return responses.map(r => r.data) - // }) - // .then(objects => { - // expect(logHandlerStub.callCount).to.be.equal(50) - // expect(objects.length).to.be.equal(10) - // done() - // }) - // .catch(done) - // }) - - // it('Concurrency with 10 rate limit requests Queue tests', done => { - // reconfigureQueue() - // Promise.all(sequence(10).map(() => wrapPromise(api.get('/ratelimit')))) - // .then((responses) => { - // return responses.map(r => r.data) - // }) - // .then(objects => { - // expect(logHandlerStub.callCount).to.be.equal(50) - // expect(objects.length).to.be.equal(10) - // done() - // }) - // .catch(done) - // }) - - // it('Concurrency with 10 asset upload with rate limit error', done => { - // reconfigureQueue() - // const fuc = (pathcontent) => { - // return () => { - // const formData = new FormData() - // const uploadStream = createReadStream(path.join(__dirname, '../api/mock/upload.html')) - // formData.append('asset[upload]', uploadStream) - // return formData - // } - // } - - // Promise.all(sequence(10).map(() => wrapPromise(api.post('/assetUpload', fuc())))) - // .then((responses) => { - // return responses.map(r => r.data) - // }) - // .then(objects => { - // expect(logHandlerStub.callCount).to.be.equal(10) - // expect(objects.length).to.be.equal(10) - // done() - // }) - // .catch(done) - // }) - - // it('Concurrency with 20 request and 1 rate limit request tests', done => { - // reconfigureQueue() - // Promise.all( - // [ - // ...wrapPromiseInArray(api.get('/testReq'), 5), - // ...wrapPromiseInArray(api.get('/ratelimit'), 1), - // ...wrapPromiseInArray(api.get('/testReq'), 15) - // ] - // ) - // .then((responses) => { - // return responses.map(r => r.data) - // }) - // .then(objects => { - // expect(logHandlerStub.callCount).to.be.equal(5) - // expect(objects.length).to.be.equal(21) - // done() - // }) - // .catch(done) - // }) - - // it('Concurrency with 20 request and 1 rate limit request tests', done => { - // reconfigureQueue({ retryOnError: false }) - // Promise.all(sequence(20).map(() => wrapPromise(api.get('/timeout')))) - // .then((responses) => { - // expect.fail('Should not get response') - // }) - // .catch(done) - // setTimeout(() => { - // concurrencyQueue.clear() - // expect(concurrencyQueue.queue.length).to.equal(0) - // done() - // }, 1000) - // }) - - // it('Concurrency retry on custome backoff test', done => { - // reconfigureQueue({ - // retryCondition: retryConditionStub, - // retryDelayOptions: { - // customBackoff: retryDelayOptionsStub - // } - // }) - - // retryConditionStub.returns(true) - // retryDelayOptionsStub.onCall(0).returns(200) - // retryDelayOptionsStub.onCall(1).returns(300) - // retryDelayOptionsStub.onCall(2).returns(-1) - // retryDelayOptionsStub.returns(200) - // Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) - // .then((responses) => { - // return responses.map(r => r.data) - // }) - // .then(objects => { - // expect(logHandlerStub.callCount).to.be.equal(45) - // expect(objects.length).to.be.equal(10) - // done() - // }) - // .catch(done) - // }) - - // it('Concurrency retry delay with base request test', done => { - // retryConditionStub.returns(true) - // retryDelayOptionsStub.returns(200) - - // reconfigureQueue({ - // retryCondition: retryConditionStub, - // retryDelayOptions: { - // base: retryDelayOptionsStub() - // } - // }) - - // Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) - // .then((responses) => { - // return responses.map(r => r.data) - // }) - // .then(objects => { - // expect(logHandlerStub.callCount).to.be.equal(50) - // expect(objects.length).to.be.equal(10) - // done() - // }) - // .catch(done) - // }) - - // it('Concurrency update authorization to not pass authtoken', done => { - // api.get('/fail', { headers: { authorization: 'authorization' } }) - // .then((response) => { - // expect(response).to.equal(undefined) - // done() - // }) - // .catch((error) => { - // expect(error.config.headers.authtoken).to.equal(undefined) - // expect(error.config.headers.authorization).to.equal('authorization') - // done() - // }) - // .catch(done) - // }) - - // it('Request to fail with no response', done => { - // reconfigureQueue() - // const mock = new MockAdapter(api) - // mock.onGet('/netError').networkError() - // api.get('/netError') - // .then((response) => { - // expect(response).to.equal(undefined) - // done() - // }) - // .catch((error) => { - // expect(error.esponse).to.equal(undefined) - // done() - // }) - // .catch(done) - // }) + it('Initialize with bad axios instance', done => { + try { + new ConcurrencyQueue({ axios: undefined }) + expect.fail('Undefined axios should fail') + } catch (error) { + expect(error.message).to.be.equal('Axios instance is not present') + done() + } + }) + + it('Initialization with default config test', done => { + const queue = makeConcurrencyQueue() + expect(queue.config.maxRequests).to.be.equal(5) + expect(queue.config.retryLimit).to.be.equal(5) + expect(queue.config.retryDelay).to.be.equal(300) + expect(queue.queue.length).to.be.equal(0) + expect(queue.running.length).to.be.equal(0) + expect(queue.interceptors.request).to.be.equal(0) + expect(queue.interceptors.response).to.be.equal(0) + done() + }) + + it('Initialization with custom config test', done => { + const queue = makeConcurrencyQueue({ maxRequests: 20, retryLimit: 2, retryDelay: 1000 }) + expect(queue.config.maxRequests).to.be.equal(20) + expect(queue.config.retryLimit).to.be.equal(2) + expect(queue.config.retryDelay).to.be.equal(1000) + expect(queue.queue.length).to.be.equal(0) + expect(queue.running.length).to.be.equal(0) + done() + }) + + it('Detach interceptors test', done => { + const queue = makeConcurrencyQueue({ maxRequests: 20 }) + queue.detach() + expect(queue.config.maxRequests).to.be.equal(20) + expect(queue.config.retryLimit).to.be.equal(5) + expect(queue.config.retryDelay).to.be.equal(300) + expect(queue.interceptors.request).to.be.equal(null) + expect(queue.interceptors.response).to.be.equal(null) + done() + }) + + it('Initialization with custom config negative value test', done => { + try { + makeConcurrencyQueue({ maxRequests: -10 }) + expect.fail('Negative concurrency queue should fail') + } catch (error) { + expect(error.message).to.be.equal('Concurrency Manager Error: minimum concurrent requests is 1') + done() + } + }) + + it('Initialization with custom config retry limit negative value test', done => { + try { + makeConcurrencyQueue({ retryLimit: -10 }) + expect.fail('Negative retry limit should fail') + } catch (error) { + expect(error.message).to.be.equal('Retry Policy Error: minimum retry limit is 1') + done() + } + }) + + it('Initialization with custom config retry delay value test', done => { + try { + makeConcurrencyQueue({ retryDelay: 10 }) + expect.fail('Retry delay should be min 300ms') + } catch (error) { + expect(error.message).to.be.equal('Retry Policy Error: minimum retry delay for requests is 300') + done() + } + }) + + it('Concurrency with 100 passing requests Queue tests', done => { + Promise.all(sequence(100).map(() => api.get('/testReq'))) + .then((responses) => { + return responses.map(r => r.data) + }) + .then(objects => { + expect(objects.length).to.be.equal(100) + done() + }) + .catch(done) + }) + + it('Concurrency with 100 failing requests retry on error false tests', done => { + Promise.all(sequence(100).map(() => wrapPromise(api.get('/fail')))) + .then((responses) => { + return responses.map(r => r.data) + }) + .then(objects => { + expect(objects.length).to.be.equal(100) + done() + }) + .catch(done) + }) + + it('Concurrency with 10 timeout requests', done => { + const client = Axios.create({ + baseURL: `${host}:${port}` + }) + const concurrency = new ConcurrencyQueue({ axios: client, config: { retryOnError: true, timeout: 250 } }) + client.get('http://localhost:4444/timeout', { + timeout: 250 + }).then(function (res) { + expect(res).to.be.equal(null) + done() + }).catch(function (err) { + concurrency.detach() + expect(err.response.status).to.be.equal(408) + expect(err.response.statusText).to.be.equal('timeout of 250ms exceeded') + done() + }).catch(done) + }) + it('Concurrency with 10 timeout requests retry', done => { + retryDelayOptionsStub.returns(5000) + const client = Axios.create({ + baseURL: `${host}:${port}` + }) + const concurrency = new ConcurrencyQueue({ axios: client, config: { retryCondition: (error) => { + if (error.response.status === 408) { + return true + } + return false + }, + logHandler: logHandlerStub, + retryDelayOptions: { + base: retryDelayOptionsStub() + }, + retryLimit: 2, + retryOnError: true, timeout: 250 } }) + client.get('http://localhost:4444/timeout', { + timeout: 250 + }).then(function (res) { + expect(res).to.be.equal(null) + done() + }).catch(function (err) { + concurrency.detach() + expect(err.response.status).to.be.equal(408) + expect(err.response.statusText).to.be.equal('timeout of 250ms exceeded') + done() + }).catch(done) + }) + + it('Concurrency with 100 failing requests retry on error with no retry condition tests', done => { + reconfigureQueue({ retryCondition: (error) => false }) + Promise.all(sequence(100).map(() => wrapPromise(api.get('/fail')))) + .then((responses) => { + return responses.map(r => r.data) + }) + .then(objects => { + expect(logHandlerStub.callCount).to.be.equal(0) + expect(objects.length).to.be.equal(100) + done() + }) + .catch(done) + }) + + it('Concurrency with 10 failing requests with retry tests', done => { + reconfigureQueue() + Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) + .then((responses) => { + return responses.map(r => r.data) + }) + .then(objects => { + expect(logHandlerStub.callCount).to.be.equal(50) + expect(objects.length).to.be.equal(10) + done() + }) + .catch(done) + }) + + it('Concurrency with 10 rate limit requests Queue tests', done => { + reconfigureQueue() + Promise.all(sequence(10).map(() => wrapPromise(api.get('/ratelimit')))) + .then((responses) => { + return responses.map(r => r.data) + }) + .then(objects => { + expect(logHandlerStub.callCount).to.be.equal(50) + expect(objects.length).to.be.equal(10) + done() + }) + .catch(done) + }) + + it('Concurrency with 10 asset upload with rate limit error', done => { + reconfigureQueue() + const fuc = (pathcontent) => { + return () => { + const formData = new FormData() + const uploadStream = createReadStream(path.join(__dirname, '../api/mock/upload.html')) + formData.append('asset[upload]', uploadStream) + return formData + } + } + + Promise.all(sequence(10).map(() => wrapPromise(api.post('/assetUpload', fuc())))) + .then((responses) => { + return responses.map(r => r.data) + }) + .then(objects => { + expect(logHandlerStub.callCount).to.be.equal(10) + expect(objects.length).to.be.equal(10) + done() + }) + .catch(done) + }) + + it('Concurrency with 20 request and 1 rate limit request tests', done => { + reconfigureQueue() + Promise.all( + [ + ...wrapPromiseInArray(api.get('/testReq'), 5), + ...wrapPromiseInArray(api.get('/ratelimit'), 1), + ...wrapPromiseInArray(api.get('/testReq'), 15) + ] + ) + .then((responses) => { + return responses.map(r => r.data) + }) + .then(objects => { + expect(logHandlerStub.callCount).to.be.equal(5) + expect(objects.length).to.be.equal(21) + done() + }) + .catch(done) + }) + + it('Concurrency with 20 request and 1 rate limit request tests', done => { + reconfigureQueue({ retryOnError: false }) + Promise.all(sequence(20).map(() => wrapPromise(api.get('/timeout')))) + .then((responses) => { + expect.fail('Should not get response') + }) + .catch(done) + setTimeout(() => { + concurrencyQueue.clear() + expect(concurrencyQueue.queue.length).to.equal(0) + done() + }, 1000) + }) + + it('Concurrency retry on custome backoff test', done => { + reconfigureQueue({ + retryCondition: retryConditionStub, + retryDelayOptions: { + customBackoff: retryDelayOptionsStub + } + }) + + retryConditionStub.returns(true) + retryDelayOptionsStub.onCall(0).returns(200) + retryDelayOptionsStub.onCall(1).returns(300) + retryDelayOptionsStub.onCall(2).returns(-1) + retryDelayOptionsStub.returns(200) + Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) + .then((responses) => { + return responses.map(r => r.data) + }) + .then(objects => { + expect(logHandlerStub.callCount).to.be.equal(45) + expect(objects.length).to.be.equal(10) + done() + }) + .catch(done) + }) + + it('Concurrency retry delay with base request test', done => { + retryConditionStub.returns(true) + retryDelayOptionsStub.returns(200) + + reconfigureQueue({ + retryCondition: retryConditionStub, + retryDelayOptions: { + base: retryDelayOptionsStub() + } + }) + + Promise.all(sequence(10).map(() => wrapPromise(api.get('/fail')))) + .then((responses) => { + return responses.map(r => r.data) + }) + .then(objects => { + expect(logHandlerStub.callCount).to.be.equal(50) + expect(objects.length).to.be.equal(10) + done() + }) + .catch(done) + }) + + it('Concurrency update authorization to not pass authtoken', done => { + api.get('/fail', { headers: { authorization: 'authorization' } }) + .then((response) => { + expect(response).to.equal(undefined) + done() + }) + .catch((error) => { + expect(error.config.headers.authtoken).to.equal(undefined) + expect(error.config.headers.authorization).to.equal('authorization') + done() + }) + .catch(done) + }) + + it('Request to fail with no response', done => { + reconfigureQueue() + const mock = new MockAdapter(api) + mock.onGet('/netError').networkError() + api.get('/netError') + .then((response) => { + expect(response).to.equal(undefined) + done() + }) + .catch((error) => { + expect(error.esponse).to.equal(undefined) + done() + }) + .catch(done) + }) }) function makeConcurrencyQueue (config) { From dff07de9eb421ea884b1a4f9b4c4b14bccf33c65 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Wed, 11 Oct 2023 17:47:18 +0530 Subject: [PATCH 08/12] test: :white_check_mark: taxonomy API test cases --- test/typescript/index.test.ts | 3 ++ test/typescript/taxonomy.ts | 68 +++++++++++++++++++++++++++++++++ types/stack/taxonomy/index.d.ts | 2 +- 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 test/typescript/taxonomy.ts diff --git a/test/typescript/index.test.ts b/test/typescript/index.test.ts index 635c46c7..17a124d7 100644 --- a/test/typescript/index.test.ts +++ b/test/typescript/index.test.ts @@ -17,6 +17,7 @@ import { createApp, deleteApp, fetchApp, installation, updateApp, updateAuth } f import { deployment, hosting } from './hosting'; import { orgAppRequest } from './app-request'; import { authorization } from './authorization'; +import { testTaxonomy } from './taxonomy'; dotenv.config() jest.setTimeout(10000); @@ -100,6 +101,8 @@ describe('Typescript API test', () => { deleteAsset(stack) queryOnAsset(stack) + testTaxonomy(stack) + deleteEnvironment(stack) logout(client) diff --git a/test/typescript/taxonomy.ts b/test/typescript/taxonomy.ts new file mode 100644 index 00000000..adf200e1 --- /dev/null +++ b/test/typescript/taxonomy.ts @@ -0,0 +1,68 @@ +import { expect } from "chai"; +import { Stack } from "../../types/stack"; + +var taxonomyUID = '' +export function testTaxonomy(stack: Stack) { + describe('Taxonomy API test', () => { + test('Create taxonomy', done => { + const taxonomy = { + uid: 'uid', + name: 'taxonomy', + description: 'Description for Taxonomy' + } + stack.taxonomy().create({taxonomy}) + .then((taxonomyResponse) => { + console.log(taxonomyResponse) + expect(taxonomyResponse.uid).to.be.equal(taxonomy.uid) + expect(taxonomyResponse.name).to.be.equal(taxonomy.name) + done() + }) + .catch(done) + }) + test('Fetch taxonomy from uid', done => { + stack.taxonomy(taxonomyUID).fetch() + .then((taxonomyResponse) => { + console.log(taxonomyResponse) + expect(taxonomyResponse.uid).to.be.equal(taxonomyUID) + expect(taxonomyResponse.name).not.to.be.equal('a') + done() + }) + .catch(done) + }) + test('Update taxonomy from uid', done => { + stack.taxonomy(taxonomyUID) + .fetch() + .then((taxonomyResponse) => { + taxonomyResponse.name = 'updated name' + return taxonomyResponse.update() + }) + .then((taxonomyResponse) => { + console.log(taxonomyResponse) + expect(taxonomyResponse.uid).to.be.equal(taxonomyUID) + expect(taxonomyResponse.name).to.be.equal('updated name') + done() + }) + .catch(done) + }) + test('Delete taxonomy from uid', done => { + stack.taxonomy(taxonomyUID) + .delete() + .then((taxonomyResponse) => { + expect(taxonomyResponse.notice).to.be.equal('Taxonomy deleted successfully.') + done() + }) + .catch(done) + }) + test('Query to get all taxonomies', async () => { + await stack.taxonomy() + .query() + .find() + .then((response) => { + response.items.forEach((taxonomyResponse) => { + expect(taxonomyResponse.uid).to.be.not.equal(null) + expect(taxonomyResponse.name).to.be.not.equal(null) + }) + }) + }) + }) +} diff --git a/types/stack/taxonomy/index.d.ts b/types/stack/taxonomy/index.d.ts index 6c265ddb..b23aaa42 100644 --- a/types/stack/taxonomy/index.d.ts +++ b/types/stack/taxonomy/index.d.ts @@ -15,6 +15,6 @@ export interface Taxonomies extends Creatable Date: Thu, 12 Oct 2023 17:24:10 +0530 Subject: [PATCH 09/12] test: :white_check_mark: terms api test cases and search implementation --- lib/stack/taxonomy/terms/index.js | 2 +- test/typescript/index.test.ts | 2 + test/typescript/terms.ts | 118 ++++++++++++++++++++++++++ types/stack/taxonomy/index.d.ts | 4 +- types/stack/taxonomy/terms/index.d.ts | 15 ++-- types/utility/operations.d.ts | 4 + 6 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 test/typescript/terms.ts diff --git a/lib/stack/taxonomy/terms/index.js b/lib/stack/taxonomy/terms/index.js index 8a98b5f7..cca55ca9 100644 --- a/lib/stack/taxonomy/terms/index.js +++ b/lib/stack/taxonomy/terms/index.js @@ -192,7 +192,7 @@ export function Terms (http, data) { const headers = { headers: { ...cloneDeep(this.stackHeaders), ...cloneDeep(params) } } - const response = await http.get(`taxonomies/${this.taxonomy_uid}/terms?term=${term}`, headers) + const response = await http.get(`taxonomies/$all/terms?typeahead=${term}`, headers) return parseData(response, this.stackHeaders) } catch (err) { console.error(err) diff --git a/test/typescript/index.test.ts b/test/typescript/index.test.ts index 17a124d7..51e48762 100644 --- a/test/typescript/index.test.ts +++ b/test/typescript/index.test.ts @@ -18,6 +18,7 @@ import { deployment, hosting } from './hosting'; import { orgAppRequest } from './app-request'; import { authorization } from './authorization'; import { testTaxonomy } from './taxonomy'; +import { testTerm } from './terms'; dotenv.config() jest.setTimeout(10000); @@ -102,6 +103,7 @@ describe('Typescript API test', () => { queryOnAsset(stack) testTaxonomy(stack) + testTerm(stack) deleteEnvironment(stack) diff --git a/test/typescript/terms.ts b/test/typescript/terms.ts new file mode 100644 index 00000000..ecf24dea --- /dev/null +++ b/test/typescript/terms.ts @@ -0,0 +1,118 @@ +import { expect } from "chai"; +import { Stack } from "../../types/stack"; +var taxonomyUID = '' +var termUID = '' +export function testTerm(stack: Stack) { + describe('Term API test', () => { + test('Create Term', done => { + const term = { + uid: 'term_uid', + name: 'term name', + parent_uid: 'parent_uid', + order: 1 + } + stack.taxonomy(taxonomyUID).terms().create({term}) + .then((termResponse) => { + expect(termResponse.uid).to.be.equal(term.uid) + expect(termResponse.name).to.be.equal(term.name) + done() + }) + .catch((err) => { + console.log(err) + }) + }) + test('Fetch term from uid', done => { + stack.taxonomy(taxonomyUID).terms(termUID).fetch() + .then((termResponse) => { + expect(termResponse.uid).to.be.equal(termUID) + expect(termResponse.name).not.to.be.equal(null) + done() + }) + .catch(done) + }) + test('Update term from uid', done => { + stack.taxonomy(taxonomyUID).terms(termUID) + .fetch() + .then((termResponse) => { + termResponse.name = 'Updated Name' + return termResponse.update() + }) + .then((termResponse) => { + expect(termResponse.uid).to.be.equal(termUID) + expect(termResponse.name).to.be.equal('Updated Name') + done() + }) + .catch(done) + }) + test('Delete term from uid', done => { + stack.taxonomy(taxonomyUID).terms(termUID) + .delete() + .then((termResponse) => { + expect(termResponse.notice).to.be.equal('Term deleted successfully.') + done() + }) + .catch(done) + }) + test('Query to get all Terms', done => { + stack.taxonomy(taxonomyUID).terms() + .query() + .find() + .then((response) => { + response.items.forEach((termResponse) => { + expect(termResponse.uid).to.be.not.equal(null) + expect(termResponse.name).to.be.not.equal(null) + }) + done() + }) + .catch(done) + }) + test('Ancestors of the term given', done => { + stack.taxonomy(taxonomyUID).terms(termUID) + .ancestors() + .then((termResponse) => { + expect(termResponse.terms[0].uid).not.to.be.equal(null) + expect(termResponse.terms[0].name).not.to.be.equal(null) + expect(termResponse.terms[0].created_by).not.to.be.equal(null) + expect(termResponse.terms[0].updated_by).not.to.be.equal(null) + done() + }) + .catch(done) + }) + test('Descendants of the term given', done => { + stack.taxonomy(taxonomyUID).terms(termUID) + .descendants() + .then((termResponse) => { + expect(termResponse.terms[0].uid).not.to.be.equal(null) + expect(termResponse.terms[0].name).not.to.be.equal(null) + expect(termResponse.terms[0].created_by).not.to.be.equal(null) + expect(termResponse.terms[0].updated_by).not.to.be.equal(null) + done() + }) + .catch(done) + }) + it('search term', done => { + const typeahead = 'term_string' + stack.taxonomy('$all').terms() + .search(typeahead) + .then((termResponse) => { + expect(termResponse.terms).to.be.an('array') + done() + }) + .catch((err) => {console.log(err)}) + + }) + it('move term', done => { + const term = { + parent_uid: 'parent_uid', + order: 2 + } + stack.taxonomy(taxonomyUID).terms(termUID) + .move({ term }) + .then((termResponse) => { + expect(termResponse.notice).to.be.equal('Term moved successfully.') + done() + }) + .catch(done) + }) + }) +} diff --git a/types/stack/taxonomy/index.d.ts b/types/stack/taxonomy/index.d.ts index b23aaa42..c0a23a22 100644 --- a/types/stack/taxonomy/index.d.ts +++ b/types/stack/taxonomy/index.d.ts @@ -3,8 +3,8 @@ import { Creatable, Queryable, SystemFunction } from "../../utility/operations"; import { Term, Terms } from "../taxonomy/terms" export interface Taxonomy extends SystemFields, SystemFunction { - term(): Terms - term(uid: string): Term + terms(): Terms + terms(uid: string): Term } export interface Taxonomies extends Queryable { diff --git a/types/stack/taxonomy/terms/index.d.ts b/types/stack/taxonomy/terms/index.d.ts index f61a860f..a95ab7c9 100644 --- a/types/stack/taxonomy/terms/index.d.ts +++ b/types/stack/taxonomy/terms/index.d.ts @@ -1,13 +1,16 @@ import { AnyProperty, SystemFields } from "../../../utility/fields"; -import { Creatable, Queryable, SystemFunction } from "../../../utility/operations"; +import { Creatable, Queryable, Searchable, SystemFunction } from "../../../utility/operations"; export interface Term extends SystemFields, SystemFunction { - ancestors(data: { include_children_count?: boolean, include_referenced_entries_count?: boolean, include_count?: boolean, skip?: number, limit?: number}): Promise - descendants(data: { include_children_count?: boolean, include_referenced_entries_count?: boolean, include_count?: boolean, skip?: number, limit?: number}): Promise - move(data: { term: { parent_uid?: string, order: number } }, force?: boolean): Promise + ancestors(data?: { include_children_count?: boolean, include_referenced_entries_count?: boolean, include_count?: boolean, skip?: number, limit?: number}): Promise + descendants(data?: { include_children_count?: boolean, include_referenced_entries_count?: boolean, include_count?: boolean, skip?: number, limit?: number}): Promise + move(data: { term: { parent_uid?: string, order: number } }, force?: boolean): Promise } -export interface Term extends Creatable { +export interface Terms extends Creatable { +} + +export interface Terms extends Searchable { } export interface Terms extends Queryable { @@ -15,7 +18,7 @@ export interface Terms extends Queryable { export interface TermData extends AnyProperty { name: string - term_uid: string + uid: string parent_uid?: string order: number } diff --git a/types/utility/operations.d.ts b/types/utility/operations.d.ts index 6e43cfed..89840f26 100644 --- a/types/utility/operations.d.ts +++ b/types/utility/operations.d.ts @@ -6,6 +6,10 @@ export interface Creatable { create(data: D, param?: AnyProperty): Promise } +export interface Searchable { + search(string: D, param?: AnyProperty): Promise +} + export interface SystemFunction { update(param?: AnyProperty): Promise fetch(param?: AnyProperty): Promise From b0d85b1726abda1a44104e6426582c2a5249363c Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Thu, 12 Oct 2023 17:33:10 +0530 Subject: [PATCH 10/12] test: :white_check_mark: changes in search unit test in terms --- lib/contentstack.js | 2 +- test/unit/terms-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/contentstack.js b/lib/contentstack.js index 5ecb13fa..b58e46c8 100644 --- a/lib/contentstack.js +++ b/lib/contentstack.js @@ -157,7 +157,7 @@ import httpClient from './core/contentstackHTTPClient.js' */ export function client (params = {}) { const defaultParameter = { - defaultHostName: 'api.contentstack.io' + defaultHostName: 'api.dev18-app.csnonprod.com.io' } const sdkAgent = `contentstack-management-javascript/${packages.version}` diff --git a/test/unit/terms-test.js b/test/unit/terms-test.js index 67e93420..39336346 100644 --- a/test/unit/terms-test.js +++ b/test/unit/terms-test.js @@ -169,7 +169,7 @@ describe('Contentstack Term test', () => { }) it('term search test', done => { var mock = new MockAdapter(Axios) - mock.onGet(`/taxonomies/taxonomy_uid/terms?term=UID`).reply(200, { + mock.onGet(`/taxonomies/$all/terms?typeahead=UID`).reply(200, { term: { ...termsMock } From f4642c46fbceed4e4649b3fd10e924e79872bdc2 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Thu, 12 Oct 2023 17:49:57 +0530 Subject: [PATCH 11/12] changed default host name --- lib/contentstack.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/contentstack.js b/lib/contentstack.js index b58e46c8..5ecb13fa 100644 --- a/lib/contentstack.js +++ b/lib/contentstack.js @@ -157,7 +157,7 @@ import httpClient from './core/contentstackHTTPClient.js' */ export function client (params = {}) { const defaultParameter = { - defaultHostName: 'api.dev18-app.csnonprod.com.io' + defaultHostName: 'api.contentstack.io' } const sdkAgent = `contentstack-management-javascript/${packages.version}` From 85fd19b519abee286f00c0ae4addc4d6d92e9f40 Mon Sep 17 00:00:00 2001 From: harshithad0703 Date: Tue, 17 Oct 2023 13:18:20 +0530 Subject: [PATCH 12/12] added entry on changelog file and changed version --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 435bb15c..1bdee9d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [v1.12.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.12.0) (2023-10-17) + - Feature + - Types support for Taxonomy feature + - Types support for Terms feature +- Fixes + - Correction in refreshToken error message ## [v1.11.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.11.0) (2023-09-03) - Fixes and Enhancements - Allows contenttype in asset upload diff --git a/package.json b/package.json index 3ab84b5e..9b6f911e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/management", - "version": "1.11.0", + "version": "1.12.0", "description": "The Content Management API is used to manage the content of your Contentstack account", "main": "./dist/node/contentstack-management.js", "browser": "./dist/web/contentstack-management.js",