Skip to content
This repository was archived by the owner on Apr 13, 2020. It is now read-only.

Commit c4adc54

Browse files
authored
Fix test in serviceEndpoint (#334)
* Fix test in serviceEndpoint * fix typo
1 parent bc1725f commit c4adc54

File tree

2 files changed

+232
-46
lines changed

2 files changed

+232
-46
lines changed

src/lib/pipelines/serviceEndpoint.test.ts

Lines changed: 227 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,127 @@ jest.mock("azure-devops-node-api");
33
jest.mock("../../config");
44
jest.mock("../azdoClient");
55

6-
// Imports
6+
import { IRequestOptions, IRestResponse, RestClient } from "typed-rest-client";
77
import uuid from "uuid/v4";
88
import { Config, readYaml } from "../../config";
9-
import {
10-
disableVerboseLogging,
11-
enableVerboseLogging,
12-
logger
13-
} from "../../logger";
14-
import { IVariableGroupData } from "../../types";
9+
import { deepClone } from "../../lib/util";
10+
import { disableVerboseLogging, enableVerboseLogging } from "../../logger";
11+
import { IServiceEndpointData, IVariableGroupData } from "../../types";
12+
import * as azdoClient from "../azdoClient";
13+
import { IServiceEndpoint } from "./azdoInterfaces";
1514
import {
1615
addServiceEndpoint,
17-
createServiceEndPointParams
16+
createServiceEndpointIfNotExists,
17+
createServiceEndPointParams,
18+
getServiceEndpointByName
1819
} from "./serviceEndpoint";
20+
import * as serviceEndpoint from "./serviceEndpoint";
1921

20-
// Tests
2122
const serviceEndpointName: string = uuid();
2223
const subscriptionId: string = uuid();
2324
const subscriptionName: string = uuid();
2425
const servicePrincipalId: string = uuid();
2526
const servicePrincipalSecret: string = uuid();
2627
const tenantId: string = uuid();
2728

29+
const mockedConfig = {
30+
azure_devops: {
31+
orrg: uuid()
32+
}
33+
};
34+
35+
const mockedYaml = {
36+
description: "mydesc",
37+
key_vault_provider: {
38+
name: "vault",
39+
service_endpoint: {
40+
name: serviceEndpointName,
41+
service_principal_id: servicePrincipalId,
42+
service_principal_secret: servicePrincipalSecret,
43+
subscription_id: subscriptionId,
44+
subscription_name: subscriptionName,
45+
tenant_id: tenantId
46+
}
47+
},
48+
name: "myvg"
49+
};
50+
51+
const mockedMatchServiceEndpointResponse = {
52+
result: {
53+
count: 1,
54+
value: [
55+
{
56+
authorization: {
57+
parameters: {
58+
authenticationType: "authenticationType",
59+
serviceprincipalid: "serviceprincipalid",
60+
serviceprincipalkey: "serviceprincipalkey",
61+
tenantid: "tenantid"
62+
},
63+
scheme: "ssh"
64+
},
65+
createdBy: {
66+
_links: {
67+
avatar: {
68+
href: "https://person.com"
69+
}
70+
},
71+
descriptor: "test",
72+
displayName: "tester",
73+
id: "test",
74+
imageUrl: "https://www.test.com",
75+
uniqueName: "test",
76+
url: "https://www.tester.com"
77+
},
78+
data: {
79+
creationMode: "creationMode",
80+
environment: "environment",
81+
scopeLevel: "scopeLevel",
82+
subscriptionId: "subscriptionId",
83+
subscriptionName: "subscriptionName"
84+
},
85+
id: "test",
86+
isReady: true,
87+
isShared: false,
88+
name: "test",
89+
owner: "tester",
90+
type: "test",
91+
url: "https://www.test.com"
92+
}
93+
]
94+
},
95+
statusCode: 200
96+
};
97+
98+
const mockedNonMatchServiceEndpointResponse = {
99+
result: {
100+
count: 0,
101+
value: []
102+
},
103+
statusCode: 200
104+
};
105+
106+
const mockedInvalidServiceEndpointResponse = {
107+
result: {
108+
count: 2,
109+
value: []
110+
},
111+
statusCode: 200
112+
};
113+
114+
const createServiceEndpointInput: IServiceEndpointData = {
115+
name: serviceEndpointName,
116+
service_principal_id: servicePrincipalId,
117+
service_principal_secret: servicePrincipalSecret,
118+
subscription_id: subscriptionId,
119+
subscription_name: subscriptionName,
120+
tenant_id: tenantId
121+
};
122+
123+
const getCreateServiceEndpointInput = (): IServiceEndpointData => {
124+
return deepClone(createServiceEndpointInput);
125+
};
126+
28127
beforeAll(() => {
29128
enableVerboseLogging();
30129
});
@@ -208,38 +307,128 @@ describe("Validate service endpoint parameters creation", () => {
208307
});
209308
});
210309

211-
describe("addServiceEndpoint", () => {
212-
test("should pass when service endpoint config is set", async () => {
213-
(Config as jest.Mock).mockReturnValue({
214-
azure_devops: {
215-
orrg: uuid()
216-
}
217-
});
310+
const testAddServiceEndpoint = async (
311+
positive = true,
312+
getRestClientThrowException = false
313+
) => {
314+
(Config as jest.Mock).mockReturnValueOnce(mockedConfig);
315+
(readYaml as jest.Mock).mockReturnValueOnce(mockedYaml);
218316

219-
(readYaml as jest.Mock).mockReturnValue({
220-
description: "mydesc",
221-
key_vault_provider: {
222-
name: "vault",
223-
service_endpoint: {
224-
name: serviceEndpointName,
225-
service_principal_id: servicePrincipalId,
226-
service_principal_secret: servicePrincipalSecret,
227-
subscription_id: subscriptionId,
228-
subscription_name: subscriptionName,
229-
tenant_id: tenantId
317+
jest.spyOn(azdoClient, "getRestClient").mockReturnValueOnce(
318+
Promise.resolve({
319+
create: async (
320+
resource: string,
321+
resources: any,
322+
options?: IRequestOptions
323+
): Promise<IRestResponse<{ [key: string]: string }>> => {
324+
if (getRestClientThrowException) {
325+
return new Promise((_, reject) => {
326+
reject(new Error("fake"));
327+
});
230328
}
231-
},
232-
name: "myvg"
329+
return new Promise(resolve => {
330+
resolve({
331+
result: {
332+
status: "OK"
333+
},
334+
statusCode: positive ? 200 : 400
335+
});
336+
});
337+
}
338+
} as RestClient)
339+
);
340+
341+
const input = readYaml<IVariableGroupData>("");
342+
return await addServiceEndpoint(input.key_vault_provider!.service_endpoint);
343+
};
344+
345+
describe("test addServiceEndpoint function", () => {
346+
it("+ve: should pass when service endpoint config is set", async () => {
347+
const result = await testAddServiceEndpoint();
348+
expect(result).toStrictEqual({
349+
status: "OK"
233350
});
234-
const input = readYaml<IVariableGroupData>("");
351+
});
352+
it("-ve: create API returns non 200 status code", async () => {
353+
await expect(testAddServiceEndpoint(false)).rejects.toThrow();
354+
});
355+
it("-ve: create API throw exection", async () => {
356+
await expect(testAddServiceEndpoint(true, true)).rejects.toThrow();
357+
});
358+
});
235359

236-
let invalidGroupError: Error | undefined;
237-
try {
238-
logger.info("calling add variable group");
239-
await addServiceEndpoint(input.key_vault_provider!.service_endpoint);
240-
} catch (err) {
241-
invalidGroupError = err;
242-
}
243-
expect(invalidGroupError).toBeDefined();
360+
const testGetServiceEndpointByName = async (positive = true, more = false) => {
361+
(Config as jest.Mock).mockReturnValueOnce(mockedConfig);
362+
(readYaml as jest.Mock).mockReturnValueOnce(mockedYaml);
363+
364+
jest.spyOn(azdoClient, "getRestClient").mockReturnValueOnce(
365+
Promise.resolve({
366+
get: async (
367+
resource: string,
368+
options?: IRequestOptions
369+
): Promise<
370+
IRestResponse<{
371+
count: number;
372+
value: IServiceEndpoint[];
373+
}>
374+
> => {
375+
return new Promise(resolve => {
376+
if (more) {
377+
resolve(mockedInvalidServiceEndpointResponse);
378+
} else if (positive) {
379+
resolve(mockedMatchServiceEndpointResponse);
380+
} else {
381+
resolve(mockedNonMatchServiceEndpointResponse);
382+
}
383+
});
384+
}
385+
} as RestClient)
386+
);
387+
388+
const input = readYaml<IVariableGroupData>("");
389+
return await getServiceEndpointByName("dummy");
390+
};
391+
392+
describe("test getServiceEndpointByName function", () => {
393+
it("positive test", async () => {
394+
const result = await testGetServiceEndpointByName();
395+
expect(result?.id).toBe("test");
396+
});
397+
it("negative test: no match", async () => {
398+
const result = await testGetServiceEndpointByName(false);
399+
expect(result).toBeNull();
400+
});
401+
it("negative test: too many matches", async () => {
402+
await expect(testGetServiceEndpointByName(true, true)).rejects.toThrow();
403+
});
404+
});
405+
406+
describe("test createServiceEndpointIfNotExists function", () => {
407+
it("+ve", async () => {
408+
jest
409+
.spyOn(serviceEndpoint, "getServiceEndpointByName")
410+
.mockReturnValueOnce(Promise.resolve(null));
411+
jest
412+
.spyOn(serviceEndpoint, "addServiceEndpoint")
413+
.mockReturnValueOnce(
414+
Promise.resolve(mockedMatchServiceEndpointResponse.result.value[0])
415+
);
416+
const endpoint = await createServiceEndpointIfNotExists(
417+
createServiceEndpointInput
418+
);
419+
expect(endpoint).toStrictEqual(
420+
mockedMatchServiceEndpointResponse.result.value[0]
421+
);
422+
});
423+
it("-ve: missing endpoint", async () => {
424+
jest
425+
.spyOn(serviceEndpoint, "getServiceEndpointByName")
426+
.mockReturnValueOnce(Promise.resolve(null));
427+
jest
428+
.spyOn(serviceEndpoint, "addServiceEndpoint")
429+
.mockReturnValueOnce(Promise.reject(new Error("fake")));
430+
await expect(
431+
createServiceEndpointIfNotExists(createServiceEndpointInput)
432+
).rejects.toThrow();
244433
});
245434
});

src/lib/pipelines/serviceEndpoint.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,9 @@ export const createServiceEndpointIfNotExists = async (
4040
serviceEndpoint = await addServiceEndpoint(serviceEndpointData!, opts);
4141
}
4242

43-
if (serviceEndpoint === null || serviceEndpoint === undefined) {
44-
throw new Error(
45-
"Either unable to find a existing service endpoint by name or create a new service endpoint"
46-
);
47-
}
48-
43+
// addServiceEndpoint always return a value of type, IServiceEndpoint
44+
// it will never return null or undefined.
45+
// it does throw exception
4946
return serviceEndpoint;
5047
} catch (err) {
5148
logger.error(
@@ -89,8 +86,8 @@ export const addServiceEndpoint = async (
8986
);
9087
logger.info(`Creating ${message}`);
9188

92-
const client: RestClient = await getRestClient(opts);
93-
const resource: string = `${orgUrl}/${project}/${apiUrl}?${apiVersion}`;
89+
const client = await getRestClient(opts);
90+
const resource = `${orgUrl}/${project}/${apiUrl}?${apiVersion}`;
9491
logger.debug(` addServiceEndpoint:Resource: ${resource}`);
9592

9693
resp = await client.create(resource, endPointParams);

0 commit comments

Comments
 (0)