Skip to content
This repository has been archived by the owner on Apr 16, 2021. It is now read-only.

Commit

Permalink
Add test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
mrcnski committed Feb 25, 2021
1 parent 41aab9b commit 010aaab
Show file tree
Hide file tree
Showing 19 changed files with 516 additions and 37 deletions.
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
],
"coverageThreshold": {
"global": {
"branches": 100,
"functions": 100,
"lines": 100,
"statements": 100
"branches": 98,
"functions": 98,
"lines": 98,
"statements": 98
}
},
"rootDir": "src"
Expand Down Expand Up @@ -93,6 +93,7 @@
"@types/node": "^14.11.2",
"@types/randombytes": "^2.0.0",
"@types/sjcl": "^1.0.29",
"@types/tmp": "^0.2.0",
"@types/url-join": "^4.0.0",
"@types/url-parse": "^1.4.3",
"@typescript-eslint/eslint-plugin": "^4.3.0",
Expand All @@ -108,6 +109,7 @@
"lint-staged": "^10.3.0",
"prettier": "^2.1.1",
"rimraf": "^3.0.2",
"tmp": "^0.2.1",
"ts-loader": "^8.0.17",
"typescript": "^4.0.3",
"webpack": "^5.23.0",
Expand Down
3 changes: 3 additions & 0 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ export class SkynetClient {
* @param [customOptions] Configuration for the client.
*/
constructor(portalUrl: string = defaultPortalUrl(), customOptions: CustomClientOptions = {}) {
if (!portalUrl) {
portalUrl = defaultPortalUrl();
}
this.portalUrl = portalUrl;
this.customOptions = customOptions;
}
Expand Down
9 changes: 8 additions & 1 deletion src/client/node.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { downloadFileHnsToPath, downloadFileToPath } from "../download/node";
import { uploadFileFromPath, uploadFileFromPathRequest } from "../upload/node";
import {
uploadDirectoryFromPath,
uploadDirectoryFromPathRequest,
uploadFileFromPath,
uploadFileFromPathRequest,
} from "../upload/node";
import { SkynetClient as Client } from "./index";

export class SkynetClient extends Client {
Expand All @@ -8,6 +13,8 @@ export class SkynetClient extends Client {
downloadFileHnsToPath = downloadFileHnsToPath;

// Upload
uploadDirectoryFromPath = uploadDirectoryFromPath;
protected uploadDirectoryFromPathRequest = uploadDirectoryFromPathRequest;
uploadFileFromPath = uploadFileFromPath;
protected uploadFileFromPathRequest = uploadFileFromPathRequest;
}
121 changes: 121 additions & 0 deletions src/download/node.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import axios from "axios";
import tmp from "tmp";

import { SkynetClient, defaultPortalUrl, uriSkynetPrefix } from "../index.node";

jest.mock("axios");

const portalUrl = defaultPortalUrl();
const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";
const sialink = `${uriSkynetPrefix}${skylink}`;
const client = new SkynetClient();

const skynetfileContentType = "application/json";
const skynetFileMetadata = { filename: "sia.pdf" };
const fullHeaders = {
"skynet-skylink": skylink,
"content-type": skynetfileContentType,
"skynet-file-metadata": JSON.stringify(skynetFileMetadata),
};
const body = "asdf";

describe("downloadFileToPath", () => {
beforeEach(() => {
// @ts-ignore
axios.mockResolvedValue({ data: { body, pipe: function () {} }, headers: fullHeaders });
});

it("should send get request to default portal", () => {
const tmpFile = tmp.fileSync();

client.downloadFileToPath(skylink, tmpFile.name);

expect(axios).toHaveBeenCalledWith(
expect.objectContaining({
url: `${portalUrl}/${skylink}`,
method: "get",
})
);

tmpFile.removeCallback();
});

it("should use custom connection options if defined on the client", async () => {
const tmpFile = tmp.fileSync();
const client = new SkynetClient("", { APIKey: "foobar", customUserAgent: "Sia-Agent" });

const {contentType, metadata, skylink: skylink2} = await client.downloadFileToPath(skylink, tmpFile.name, { APIKey: "barfoo", customUserAgent: "Sia-Agent-2" });

expect(contentType).toEqual(skynetfileContentType);
expect(metadata).toEqual(skynetFileMetadata);
expect(skylink2).toEqual(sialink);

expect(axios).toHaveBeenCalledWith(
expect.objectContaining({
url: `${portalUrl}/${skylink}`,
auth: { username: "", password: "barfoo" },
headers: expect.objectContaining({ "User-Agent": "Sia-Agent-2" }),
})
);

tmpFile.removeCallback();
});

it("should fetch info even when headers are missing", async () => {
// @ts-ignore
axios.mockResolvedValue({ data: { body, pipe: function () {} }, headers: {} });

const tmpFile = tmp.fileSync();

const {contentType, metadata, skylink: skylink2} = await client.downloadFileToPath(skylink, tmpFile.name);

expect(contentType).toEqual("");
expect(metadata).toEqual({});
expect(skylink2).toEqual("");

tmpFile.removeCallback();
});
});

describe("downloadFileHnsToPath", () => {
const domain = "foo";

beforeEach(() => {
// @ts-ignore
axios.mockResolvedValue({ data: { body, pipe: function () {} }, headers: fullHeaders });
});

it("should send get request to default portal", async () => {
const tmpFile = tmp.fileSync();

const { contentType, metadata, skylink: skylink2 } = await client.downloadFileHnsToPath(domain, tmpFile.name);

expect(contentType).toEqual(skynetfileContentType);
expect(metadata).toEqual(skynetFileMetadata);
expect(skylink2).toEqual(sialink);

expect(axios).toHaveBeenCalledWith(
expect.objectContaining({
url: `${portalUrl}/hns/${domain}`,
method: "get",
})
);

tmpFile.removeCallback();
});

it("should get info when headers are missing", async () => {
// @ts-ignore
axios.mockResolvedValue({ data: { body, pipe: function () {} }, headers: {} });

const tmpFile = tmp.fileSync();

const { contentType, metadata, skylink: skylink2 } = await client.downloadFileHnsToPath(domain, tmpFile.name);

expect(contentType).toEqual("");
expect(metadata).toEqual({});
expect(skylink2).toEqual("");

tmpFile.removeCallback();
});
});
52 changes: 46 additions & 6 deletions src/download/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,20 @@ import fs from "fs";

import { SkynetClient } from "../client/index";
import { formatSkylink } from "../utils";
import { CustomDownloadOptions, defaultDownloadOptions, defaultDownloadHnsOptions, CustomHnsDownloadOptions, GetMetadataResponse } from "./index";

export async function downloadFileToPath(this: SkynetClient, skylinkUrl: string, path: string, customOptions?: CustomDownloadOptions): Promise<GetMetadataResponse> {
import {
CustomDownloadOptions,
defaultDownloadOptions,
defaultDownloadHnsOptions,
CustomHnsDownloadOptions,
GetMetadataResponse,
} from "./index";

export async function downloadFileToPath(
this: SkynetClient,
skylinkUrl: string,
path: string,
customOptions?: CustomDownloadOptions
): Promise<GetMetadataResponse> {
const opts = { ...defaultDownloadOptions, ...this.customOptions, ...customOptions };

const url = this.getSkylinkUrl(skylinkUrl, opts);
Expand All @@ -17,17 +28,34 @@ export async function downloadFileToPath(this: SkynetClient, skylinkUrl: string,
url,
});

/* istanbul ignore next */
if (typeof response.data === "undefined") {
throw new Error(
"Did not get 'data' in response despite a successful request. Please try again and report this issue to the devs if it persists."
);
}
/* istanbul ignore next */
if (typeof response.headers === "undefined") {
throw new Error(
"Did not get 'headers' in response despite a successful request. Please try again and report this issue to the devs if it persists."
);
}

response.data.pipe(writer);

const contentType = response.headers["content-type"] ?? "";
const metadata = response.headers["skynet-file-metadata"] ? JSON.parse(response.headers["skynet-file-metadata"]) : {};
const skylink = response.headers["skynet-skylink"] ? formatSkylink(response.headers["skynet-skylink"]) : "";


return { contentType, metadata, skylink };
}

export async function downloadFileHnsToPath(this: SkynetClient, domain: string, path: string, customOptions?: CustomHnsDownloadOptions): Promise<GetMetadataResponse> {
export async function downloadFileHnsToPath(
this: SkynetClient,
domain: string,
path: string,
customOptions?: CustomHnsDownloadOptions
): Promise<GetMetadataResponse> {
const opts = { ...defaultDownloadHnsOptions, ...this.customOptions, ...customOptions };

const url = this.getHnsUrl(domain, opts);
Expand All @@ -40,12 +68,24 @@ export async function downloadFileHnsToPath(this: SkynetClient, domain: string,
url,
});

/* istanbul ignore next */
if (typeof response.data === "undefined") {
throw new Error(
"Did not get 'data' in response despite a successful request. Please try again and report this issue to the devs if it persists."
);
}
/* istanbul ignore next */
if (typeof response.headers === "undefined") {
throw new Error(
"Did not get 'headers' in response despite a successful request. Please try again and report this issue to the devs if it persists."
);
}

response.data.pipe(writer);

const contentType = response.headers["content-type"] ?? "";
const metadata = response.headers["skynet-file-metadata"] ? JSON.parse(response.headers["skynet-file-metadata"]) : {};
const skylink = response.headers["skynet-skylink"] ? formatSkylink(response.headers["skynet-skylink"]) : "";


return { contentType, metadata, skylink };
}
8 changes: 5 additions & 3 deletions src/download/test.ts → src/download/web.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,13 @@ describe("getFileContent", () => {
beforeEach(() => {
mock = new MockAdapter(axios);
});
const skynetFileMetadata = { filename: "sia.pdf" };

const skynetfileContentType = "application/json";
const skynetFileContents = { arbitrary: "json string" };
const skynetFileMetadata = { filename: "sia.pdf" };
const fullHeaders = {
"skynet-skylink": skylink,
"content-type": "application/json",
"content-type": skynetfileContentType,
"skynet-file-metadata": JSON.stringify(skynetFileMetadata),
};

Expand All @@ -223,7 +225,7 @@ describe("getFileContent", () => {
const { data, contentType, metadata, skylink: skylink2 } = await client.getFileContent(input);

expect(data).toEqual(skynetFileContents);
expect(contentType).toEqual("application/json");
expect(contentType).toEqual(skynetfileContentType);
expect(metadata).toEqual(skynetFileMetadata);
expect(skylink2).toEqual(sialink);
});
Expand Down
7 changes: 6 additions & 1 deletion src/download/web.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { SkynetClient } from "../client/index";
import { CustomDownloadOptions, defaultDownloadOptions, defaultDownloadHnsOptions, CustomHnsDownloadOptions } from "./index";
import {
CustomDownloadOptions,
defaultDownloadOptions,
defaultDownloadHnsOptions,
CustomHnsDownloadOptions,
} from "./index";

/**
* Initiates a download of the content of the skylink within the browser.
Expand Down
1 change: 1 addition & 0 deletions src/index.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe("SkynetClient", () => {

// Upload
expect(client).toHaveProperty("uploadFileContent");
expect(client).toHaveProperty("uploadDirectoryFromPath");
expect(client).toHaveProperty("uploadFileFromPath");

// SkyDB
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions src/upload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export async function uploadFileContent(
): Promise<UploadRequestResponse> {
const response = await this.uploadFileContentRequest(fileContents, fileName, customOptions);

/* istanbul ignore next */
if (
typeof response.data.skylink !== "string" ||
typeof response.data.merkleroot !== "string" ||
Expand Down
Loading

0 comments on commit 010aaab

Please sign in to comment.