Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions src/deploy/hosting/uploader.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { expect } from "chai";
import * as sinon from "sinon";
import * as fs from "fs";
import * as zlib from "zlib";
import { Uploader } from "./uploader";
import { Client } from "../../apiv2";
import * as hashcache from "./hashcache";
import { PassThrough, Readable } from "stream";

describe("deploy/hosting/uploader", () => {
let clientPostStub: sinon.SinonStub;
let clientRequestStub: sinon.SinonStub;

class MockQueue<T> {
public handler: (item: T) => Promise<void>;
private promises: Promise<void>[] = [];
constructor(options: { handler: (item: T) => Promise<void> }) {
this.handler = options.handler;
}
add(item: T) {

Check warning on line 20 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
const p = Promise.resolve(this.handler(item));
this.promises.push(p);
}
process() {

Check warning on line 24 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
// do nothing
}
async wait() {

Check warning on line 27 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
await Promise.all(this.promises);
return Promise.resolve();
}
close() {

Check warning on line 31 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
// do nothing
}
stats() {

Check warning on line 34 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
return { total: 0, complete: 0, cursor: 0 };
}
}

beforeEach(() => {
sinon.stub(fs, "statSync");
sinon.stub(fs, "createReadStream");
sinon.stub(zlib, "createGzip");
clientPostStub = sinon.stub(Client.prototype, "post");
clientRequestStub = sinon.stub(Client.prototype, "request");
sinon.stub(hashcache, "load").returns(new Map());
sinon.stub(hashcache, "dump");
});

afterEach(() => {
sinon.restore();
});

it("should initialize correctly", () => {
const uploader = new Uploader({
version: "v1",
projectRoot: "root",
files: ["file1.txt"],
public: "public",
});
expect(uploader).to.be.instanceOf(Uploader);
});

it("should hash files and populate version", async () => {
const uploader = new Uploader({
version: "v1",
projectRoot: "root",
files: ["file1.txt", "file2.txt"],
public: "public",
});
(uploader as any).hashQueue = new MockQueue({

Check warning on line 70 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type

Check warning on line 70 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe member access .hashQueue on an `any` value
handler: (uploader as any).hashHandler.bind(uploader),

Check warning on line 71 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe call of an `any` typed value

Check warning on line 71 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe member access .hashHandler on an `any` value

Check warning on line 71 in src/deploy/hosting/uploader.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe assignment of an `any` value
});
(uploader as any).populateQueue = new MockQueue({
handler: (uploader as any).populateHandler.bind(uploader),
});
(uploader as any).uploadQueue = new MockQueue({
handler: (uploader as any).uploadHandler.bind(uploader),
});

(fs.statSync as sinon.SinonStub).returns({ mtime: new Date(), size: 100 });

// Mock stream for file1.txt
const mockStream1 = new Readable({
read() {
this.push(Buffer.from("hash1"));
this.push(null);
},
});
// Mock stream for file2.txt
const mockStream2 = new Readable({
read() {
this.push(Buffer.from("hash2"));
this.push(null);
},
});

(zlib.createGzip as sinon.SinonStub).callsFake(() => new PassThrough());
(fs.createReadStream as sinon.SinonStub).callsFake((filePath: string) => {
if (filePath.includes("file1.txt")) {
return mockStream1;
}
if (filePath.includes("file2.txt")) {
return mockStream2;
}
return new PassThrough();
});

clientPostStub.resolves({
body: {
uploadUrl: "https://upload.url",
uploadRequiredHashes: [
"af316ecb91a8ee7ae99210702b2d4758f30cdde3bf61e3d8e787d74681f90a6e", // hash for "hash1"
"e7bf382f6e5915b3f88619b866223ebf1d51c4c5321cccde2e9ff700a3259086", // hash for "hash2"
],
},
});
clientRequestStub.resolves({ status: 200, response: { text: sinon.stub().resolves("") } });

await uploader.start();

expect(clientPostStub.calledWithMatch(/\/v1:populateFiles/)).to.be.true;
expect(clientPostStub.firstCall.args[1].files).to.have.property("/file1.txt");
expect(clientPostStub.firstCall.args[1].files).to.have.property("/file2.txt");
expect(clientRequestStub.calledTwice).to.be.true;
});
});
Loading