Skip to content

Commit

Permalink
Replace limited OpenSSL options with full HTTP configurability (#322)
Browse files Browse the repository at this point in the history
* Expose HTTP options

* Use separate Jira and Xray HTTP clients if needed

* Make root HTTP options common to both clients

* Update TSDoc

* Update TSDoc

* Update TSDoc

* Update TSDoc
  • Loading branch information
csvtuda authored May 9, 2024
1 parent 4ca9a61 commit 807d4ff
Show file tree
Hide file tree
Showing 31 changed files with 617 additions and 322 deletions.
6 changes: 3 additions & 3 deletions index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ describe("the plugin exports should work", () => {
};
expect(options.plugin).to.exist;
});
it("openSSL", () => {
it("http", () => {
const options: CypressXrayPluginOptions = {
jira: {
projectKey: "CYP-123",
url: "https://example.org",
},
["openSSL"]: {},
http: {},
};
expect(options.openSSL).to.exist;
expect(options.http).to.exist;
});
});
});
8 changes: 5 additions & 3 deletions src/authentication/credentials.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AxiosResponse } from "axios";
import { REST } from "../https/requests";
import { AxiosRestClient } from "../https/requests";
import { LOG, Level } from "../logging/logging";
import { StringMap } from "../types/util";
import { encode } from "../util/base64";
Expand Down Expand Up @@ -88,11 +88,13 @@ export class JwtCredentials implements HttpCredentials {
* @param clientId - the client ID
* @param clientSecret - the client secret
* @param authenticationUrl - the authentication URL/token endpoint
* @param httpClient - the HTTP client to use for fetching the token
*/
constructor(
private readonly clientId: string,
private readonly clientSecret: string,
private readonly authenticationUrl: string
private readonly authenticationUrl: string,
private readonly httpClient: AxiosRestClient
) {
this.token = undefined;
}
Expand Down Expand Up @@ -125,7 +127,7 @@ export class JwtCredentials implements HttpCredentials {
});
try {
LOG.message(Level.INFO, `Authenticating to: ${this.authenticationUrl}...`);
const tokenResponse: AxiosResponse<string> = await REST.post(
const tokenResponse: AxiosResponse<string> = await this.httpClient.post(
this.authenticationUrl,
{
["client_id"]: this.clientId,
Expand Down
9 changes: 8 additions & 1 deletion src/client/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { HttpCredentials } from "../authentication/credentials";
import { AxiosRestClient } from "../https/requests";
import { LOG, Level } from "../logging/logging";
import { startInterval } from "../util/time";

Expand All @@ -14,16 +15,22 @@ export abstract class Client {
* The credentials to use for authentication.
*/
protected readonly credentials: HttpCredentials;
/**
* The HTTP client to use for dispatching requests.
*/
protected readonly httpClient: AxiosRestClient;

/**
* Construct a new client using the provided credentials.
*
* @param apiBaseUrl - the base URL for all HTTP requests
* @param credentials - the credentials to use during authentication
* @param httpClient - the HTTP client to use for dispatching requests
*/
constructor(apiBaseUrl: string, credentials: HttpCredentials) {
constructor(apiBaseUrl: string, credentials: HttpCredentials, httpClient: AxiosRestClient) {
this.apiBaseUrl = apiBaseUrl;
this.credentials = credentials;
this.httpClient = httpClient;
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/client/jira/jiraClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ describe("the jira clients", () => {
clientType === "server"
? new JiraClientServer(
"https://example.org",
new BasicAuthCredentials("user", "token")
new BasicAuthCredentials("user", "token"),
restClient
)
: new JiraClientCloud(
"https://example.org",
new BasicAuthCredentials("user", "token")
new BasicAuthCredentials("user", "token"),
restClient
);
});

Expand Down
11 changes: 5 additions & 6 deletions src/client/jira/jiraClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { AxiosResponse } from "axios";
import FormData from "form-data";
import fs from "fs";
import { REST } from "../../https/requests";
import { LOG, Level } from "../../logging/logging";
import { SearchRequest } from "../../types/jira/requests/search";
import { Attachment } from "../../types/jira/responses/attachment";
Expand Down Expand Up @@ -113,7 +112,7 @@ export abstract class AbstractJiraClient extends Client implements JiraClient {
LOG.message(Level.DEBUG, "Attaching files:", ...files);
const progressInterval = this.startResponseInterval(this.apiBaseUrl);
try {
const response: AxiosResponse<Attachment[]> = await REST.post(
const response: AxiosResponse<Attachment[]> = await this.httpClient.post(
this.getUrlAddAttachment(issueIdOrKey),
form,
{
Expand Down Expand Up @@ -147,7 +146,7 @@ export abstract class AbstractJiraClient extends Client implements JiraClient {
LOG.message(Level.DEBUG, "Getting issue types...");
const progressInterval = this.startResponseInterval(this.apiBaseUrl);
try {
const response: AxiosResponse<IssueTypeDetails[]> = await REST.get(
const response: AxiosResponse<IssueTypeDetails[]> = await this.httpClient.get(
this.getUrlGetIssueTypes(),
{
headers: {
Expand Down Expand Up @@ -194,7 +193,7 @@ export abstract class AbstractJiraClient extends Client implements JiraClient {
LOG.message(Level.DEBUG, "Getting fields...");
const progressInterval = this.startResponseInterval(this.apiBaseUrl);
try {
const response: AxiosResponse<FieldDetail[]> = await REST.get(
const response: AxiosResponse<FieldDetail[]> = await this.httpClient.get(
this.getUrlGetFields(),
{
headers: {
Expand Down Expand Up @@ -239,7 +238,7 @@ export abstract class AbstractJiraClient extends Client implements JiraClient {
...request,
startAt: startAt,
};
const response: AxiosResponse<SearchResults> = await REST.post(
const response: AxiosResponse<SearchResults> = await this.httpClient.post(
this.getUrlPostSearch(),
paginatedRequest,
{
Expand Down Expand Up @@ -277,7 +276,7 @@ export abstract class AbstractJiraClient extends Client implements JiraClient {
LOG.message(Level.DEBUG, "Editing issue...");
const progressInterval = this.startResponseInterval(this.apiBaseUrl);
try {
await REST.put(this.getUrlEditIssue(issueIdOrKey), issueUpdateData, {
await this.httpClient.put(this.getUrlEditIssue(issueIdOrKey), issueUpdateData, {
headers: {
...header,
},
Expand Down
6 changes: 3 additions & 3 deletions src/client/jira/jiraClientCloud.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/// <reference types="cypress" />

import { expect } from "chai";
import { getMockedRestClient } from "../../../test/mocks";
import { BasicAuthCredentials } from "../../authentication/credentials";
import { JiraClientCloud } from "./jiraClientCloud";

describe("the jira cloud client", () => {
const client: JiraClientCloud = new JiraClientCloud(
"https://example.org",
new BasicAuthCredentials("user", "token")
new BasicAuthCredentials("user", "token"),
getMockedRestClient()
);

describe("the urls", () => {
Expand Down
6 changes: 3 additions & 3 deletions src/client/jira/jiraClientServer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/// <reference types="cypress" />

import { expect } from "chai";
import { getMockedRestClient } from "../../../test/mocks";
import { BasicAuthCredentials } from "../../authentication/credentials";
import { JiraClientServer } from "./jiraClientServer";

describe("the jira server client", () => {
const client: JiraClientServer = new JiraClientServer(
"https://example.org",
new BasicAuthCredentials("user", "token")
new BasicAuthCredentials("user", "token"),
getMockedRestClient()
);

describe("the urls", () => {
Expand Down
7 changes: 4 additions & 3 deletions src/client/xray/xrayClient.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect } from "chai";
import { getMockedJwtCredentials, getMockedLogger } from "../../../test/mocks";
import { getMockedJwtCredentials, getMockedLogger, getMockedRestClient } from "../../../test/mocks";
import { BasicAuthCredentials } from "../../authentication/credentials";
import { Level } from "../../logging/logging";
import { AbstractXrayClient } from "./xrayClient";
Expand All @@ -18,9 +18,10 @@ describe("the xray clients", () => {
clientType === "server"
? new XrayClientServer(
"https://example.org",
new BasicAuthCredentials("user", "token")
new BasicAuthCredentials("user", "token"),
getMockedRestClient()
)
: new XrayClientCloud(credentials);
: new XrayClientCloud(credentials, getMockedRestClient());
});

describe("import execution", () => {
Expand Down
24 changes: 14 additions & 10 deletions src/client/xray/xrayClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AxiosResponse, HttpStatusCode, isAxiosError } from "axios";
import FormData from "form-data";
import fs from "fs";
import { REST, RequestConfigPost } from "../../https/requests";
import { RequestConfigPost } from "../../https/requests";
import { LOG, Level } from "../../logging/logging";
import { XrayTestExecutionResults } from "../../types/xray/importTestExecutionResults";
import { CucumberMultipartFeature } from "../../types/xray/requests/importExecutionCucumberMultipart";
Expand Down Expand Up @@ -94,7 +94,7 @@ export abstract class AbstractXrayClient extends Client implements XrayClient {
try {
const response: AxiosResponse<
ImportExecutionResponseServer | ImportExecutionResponseCloud
> = await REST.post(this.getUrlImportExecution(), execution, {
> = await this.httpClient.post(this.getUrlImportExecution(), execution, {
headers: {
...authorizationHeader,
},
Expand All @@ -120,7 +120,7 @@ export abstract class AbstractXrayClient extends Client implements XrayClient {
LOG.message(Level.DEBUG, "Exporting Cucumber tests...");
const progressInterval = this.startResponseInterval(this.apiBaseUrl);
try {
const response: AxiosResponse<string> = await REST.get(
const response: AxiosResponse<string> = await this.httpClient.get(
this.getUrlExportCucumber(keys, filter),
{
headers: {
Expand Down Expand Up @@ -165,12 +165,16 @@ export abstract class AbstractXrayClient extends Client implements XrayClient {

const response: AxiosResponse<
ImportFeatureResponseServer | ImportFeatureResponseCloud
> = await REST.post(this.getUrlImportFeature(projectKey, projectId, source), form, {
headers: {
...authorizationHeader,
...form.getHeaders(),
},
});
> = await this.httpClient.post(
this.getUrlImportFeature(projectKey, projectId, source),
form,
{
headers: {
...authorizationHeader,
...form.getHeaders(),
},
}
);
return this.handleResponseImportFeature(response.data);
} finally {
clearInterval(progressInterval);
Expand Down Expand Up @@ -220,7 +224,7 @@ export abstract class AbstractXrayClient extends Client implements XrayClient {
try {
const response: AxiosResponse<
ImportExecutionResponseServer | ImportExecutionResponseCloud
> = await REST.post(request.url, request.data, request.config);
> = await this.httpClient.post(request.url, request.data, request.config);
const key = this.handleResponseImportExecutionCucumberMultipart(response.data);
LOG.message(
Level.DEBUG,
Expand Down
2 changes: 1 addition & 1 deletion src/client/xray/xrayClientCloud.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ describe("the xray cloud client", () => {
beforeEach(() => {
const credentials = getMockedJwtCredentials();
credentials.getAuthorizationHeader.resolves({ ["Authorization"]: "ey12345" });
client = new XrayClientCloud(credentials);
restClient = getMockedRestClient();
client = new XrayClientCloud(credentials, restClient);
});

describe("import execution", () => {
Expand Down
9 changes: 5 additions & 4 deletions src/client/xray/xrayClientCloud.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AxiosResponse } from "axios";
import FormData from "form-data";
import { JwtCredentials } from "../../authentication/credentials";
import { RequestConfigPost, REST } from "../../https/requests";
import { AxiosRestClient, RequestConfigPost } from "../../https/requests";
import { Level, LOG } from "../../logging/logging";
import { StringMap } from "../../types/util";
import { CucumberMultipartFeature } from "../../types/xray/requests/importExecutionCucumberMultipart";
Expand Down Expand Up @@ -51,9 +51,10 @@ export class XrayClientCloud extends AbstractXrayClient implements HasTestTypes
* Construct a new Xray cloud client using the provided credentials.
*
* @param credentials - the credentials to use during authentication
* @param httpClient - the HTTP client to use for dispatching requests
*/
constructor(credentials: JwtCredentials) {
super(XrayClientCloud.URL, credentials);
constructor(credentials: JwtCredentials, httpClient: AxiosRestClient) {
super(XrayClientCloud.URL, credentials, httpClient);
}

public getUrlImportExecution(): string {
Expand Down Expand Up @@ -135,7 +136,7 @@ export class XrayClientCloud extends AbstractXrayClient implements HasTestTypes
},
};
const response: AxiosResponse<GetTestsResponse<GetTestsJiraData>> =
await REST.post(XrayClientCloud.URL_GRAPHQL, paginatedRequest, {
await this.httpClient.post(XrayClientCloud.URL_GRAPHQL, paginatedRequest, {
headers: {
...authorizationHeader,
},
Expand Down
10 changes: 6 additions & 4 deletions src/client/xray/xrayClientServer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import { dedent } from "../../util/dedent";
import { XrayClientServer } from "./xrayClientServer";

describe("the xray server client", () => {
const client: XrayClientServer = new XrayClientServer(
"https://example.org",
new BasicAuthCredentials("user", "xyz")
);
let restClient: SinonStubbedInstance<AxiosRestClient>;
let client: XrayClientServer;

beforeEach(() => {
restClient = getMockedRestClient();
client = new XrayClientServer(
"https://example.org",
new BasicAuthCredentials("user", "xyz"),
restClient
);
});

describe("import execution", () => {
Expand Down
Loading

0 comments on commit 807d4ff

Please sign in to comment.