Add unit tests for 'download-file' command
Reviewed By: mweststrate Differential Revision: D32926830 fbshipit-source-id: fbd4dcb910ffdcdc365f5f0b4c401423f0256824
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6aa0cef927
commit
9436c32ce9
@@ -41,7 +41,11 @@
|
|||||||
"xdg-basedir": "^4.0.0"
|
"xdg-basedir": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^15.12.5"
|
"@types/memorystream": "^0.3.0",
|
||||||
|
"@types/node": "^15.12.5",
|
||||||
|
"@types/tmp": "^0.2.2",
|
||||||
|
"memorystream": "^0.3.1",
|
||||||
|
"tmp": "^0.2.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {},
|
"peerDependencies": {},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -231,7 +231,6 @@ export class FlipperServerImpl implements FlipperServer {
|
|||||||
'node-api-fs-unlink': unlink,
|
'node-api-fs-unlink': unlink,
|
||||||
'node-api-fs-mkdir': mkdir,
|
'node-api-fs-mkdir': mkdir,
|
||||||
'node-api-fs-copyFile': copyFile,
|
'node-api-fs-copyFile': copyFile,
|
||||||
// TODO: Unit tests
|
|
||||||
// TODO: Do we need API to cancel an active download?
|
// TODO: Do we need API to cancel an active download?
|
||||||
'download-file-start': commandDownloadFileStartFactory(
|
'download-file-start': commandDownloadFileStartFactory(
|
||||||
this.emit.bind(this),
|
this.emit.bind(this),
|
||||||
|
|||||||
@@ -0,0 +1,220 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import MemoryStream from 'memorystream';
|
||||||
|
import {dirSync} from 'tmp';
|
||||||
|
import * as uuid from 'uuid';
|
||||||
|
import {commandDownloadFileStartFactory} from '../DownloadFile';
|
||||||
|
|
||||||
|
describe('commands', () => {
|
||||||
|
describe('DownloadFile', () => {
|
||||||
|
let commandDownloadFileStart: ReturnType<
|
||||||
|
typeof commandDownloadFileStartFactory
|
||||||
|
>;
|
||||||
|
let emit: jest.Mock<any>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
emit = jest.fn();
|
||||||
|
commandDownloadFileStart = commandDownloadFileStartFactory(emit);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('downloads file and reports the progress', async () => {
|
||||||
|
const fakeDownloadStream = new MemoryStream();
|
||||||
|
const fakeFileSize = 10;
|
||||||
|
const fakeHeaders = {
|
||||||
|
'content-length': fakeFileSize.toString(),
|
||||||
|
};
|
||||||
|
const fakeStatus = 200;
|
||||||
|
const fakeStatusText = 'Flipper rocks';
|
||||||
|
|
||||||
|
const requestSpy = jest
|
||||||
|
.spyOn(axios, 'request')
|
||||||
|
.mockImplementation(async () => ({
|
||||||
|
headers: fakeHeaders,
|
||||||
|
status: fakeStatus,
|
||||||
|
statusText: fakeStatusText,
|
||||||
|
data: fakeDownloadStream,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const {name: tmpDirName} = dirSync({
|
||||||
|
unsafeCleanup: true,
|
||||||
|
});
|
||||||
|
const dest = `${tmpDirName}/flipperTest`;
|
||||||
|
|
||||||
|
expect(requestSpy).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
const fakeDownloadURL = 'https://flipper.rocks';
|
||||||
|
const fakeUuid = 'flipper42';
|
||||||
|
jest.spyOn(uuid, 'v4').mockImplementation(() => fakeUuid);
|
||||||
|
|
||||||
|
const downloadFileDescriptor = await commandDownloadFileStart(
|
||||||
|
fakeDownloadURL,
|
||||||
|
dest,
|
||||||
|
{
|
||||||
|
overwrite: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(requestSpy).toBeCalledTimes(1);
|
||||||
|
// Expect first argument of the first fn call to amtch object
|
||||||
|
expect(requestSpy.mock.calls[0][0]).toMatchObject({
|
||||||
|
method: 'GET',
|
||||||
|
url: fakeDownloadURL,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(downloadFileDescriptor.headers).toBe(fakeHeaders);
|
||||||
|
expect(downloadFileDescriptor.status).toBe(fakeStatus);
|
||||||
|
expect(downloadFileDescriptor.statusText).toBe(fakeStatusText);
|
||||||
|
expect(downloadFileDescriptor.id).toBe(fakeUuid);
|
||||||
|
|
||||||
|
expect(emit).toBeCalledTimes(0);
|
||||||
|
await new Promise((resolve) => fakeDownloadStream.write('Luke', resolve));
|
||||||
|
expect(emit).toBeCalledTimes(1);
|
||||||
|
expect(emit).toBeCalledWith('download-file-update', {
|
||||||
|
id: fakeUuid,
|
||||||
|
downloaded: 4,
|
||||||
|
totalSize: fakeFileSize,
|
||||||
|
status: 'downloading',
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((resolve) => fakeDownloadStream.write('Obi', resolve));
|
||||||
|
expect(emit).toBeCalledTimes(2);
|
||||||
|
expect(emit).toBeCalledWith('download-file-update', {
|
||||||
|
id: fakeUuid,
|
||||||
|
downloaded: 7,
|
||||||
|
totalSize: fakeFileSize,
|
||||||
|
status: 'downloading',
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastFileUpdateCalled = new Promise((resolve) =>
|
||||||
|
emit.mockImplementationOnce(resolve),
|
||||||
|
);
|
||||||
|
|
||||||
|
fakeDownloadStream.end();
|
||||||
|
|
||||||
|
await lastFileUpdateCalled;
|
||||||
|
|
||||||
|
expect(emit).toBeCalledTimes(3);
|
||||||
|
expect(emit).toBeCalledWith('download-file-update', {
|
||||||
|
id: fakeUuid,
|
||||||
|
downloaded: 7,
|
||||||
|
totalSize: fakeFileSize,
|
||||||
|
status: 'success',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rejects "complete" promise if download file readable stream errors', async () => {
|
||||||
|
const fakeDownloadStream = new MemoryStream();
|
||||||
|
const fakeFileSize = 10;
|
||||||
|
const fakeHeaders = {
|
||||||
|
'content-length': fakeFileSize.toString(),
|
||||||
|
};
|
||||||
|
const fakeStatus = 200;
|
||||||
|
const fakeStatusText = 'Flipper rocks';
|
||||||
|
|
||||||
|
jest.spyOn(axios, 'request').mockImplementation(async () => ({
|
||||||
|
headers: fakeHeaders,
|
||||||
|
status: fakeStatus,
|
||||||
|
statusText: fakeStatusText,
|
||||||
|
data: fakeDownloadStream,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const {name: tmpDirName} = dirSync({
|
||||||
|
unsafeCleanup: true,
|
||||||
|
});
|
||||||
|
const dest = `${tmpDirName}/flipperTest`;
|
||||||
|
|
||||||
|
const fakeDownloadURL = 'https://flipper.rocks';
|
||||||
|
const fakeUuid = 'flipper42';
|
||||||
|
jest.spyOn(uuid, 'v4').mockImplementation(() => fakeUuid);
|
||||||
|
|
||||||
|
await commandDownloadFileStart(fakeDownloadURL, dest, {
|
||||||
|
overwrite: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastFileUpdateCalled = new Promise((resolve) =>
|
||||||
|
emit.mockImplementationOnce(resolve),
|
||||||
|
);
|
||||||
|
|
||||||
|
const fakeError = new Error('Ooops');
|
||||||
|
fakeDownloadStream.destroy(fakeError);
|
||||||
|
|
||||||
|
await lastFileUpdateCalled;
|
||||||
|
|
||||||
|
expect(emit).toBeCalledTimes(1);
|
||||||
|
expect(emit).toBeCalledWith('download-file-update', {
|
||||||
|
id: fakeUuid,
|
||||||
|
downloaded: 0,
|
||||||
|
totalSize: fakeFileSize,
|
||||||
|
status: 'error',
|
||||||
|
message: 'Ooops',
|
||||||
|
stack: expect.anything(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rejects "complete" promise if writeable stream errors', async () => {
|
||||||
|
const fakeDownloadStream = new MemoryStream();
|
||||||
|
const fakeFileSize = 10;
|
||||||
|
const fakeHeaders = {
|
||||||
|
'content-length': fakeFileSize.toString(),
|
||||||
|
};
|
||||||
|
const fakeStatus = 200;
|
||||||
|
const fakeStatusText = 'Flipper rocks';
|
||||||
|
|
||||||
|
jest.spyOn(axios, 'request').mockImplementation(async () => ({
|
||||||
|
headers: fakeHeaders,
|
||||||
|
status: fakeStatus,
|
||||||
|
statusText: fakeStatusText,
|
||||||
|
data: fakeDownloadStream,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const {name: tmpDirName, removeCallback: removeTmpDir} = dirSync({
|
||||||
|
unsafeCleanup: true,
|
||||||
|
});
|
||||||
|
const dest = `${tmpDirName}/flipperTest`;
|
||||||
|
|
||||||
|
const fakeDownloadURL = 'https://flipper.rocks';
|
||||||
|
const fakeUuid = 'flipper42';
|
||||||
|
jest.spyOn(uuid, 'v4').mockImplementation(() => fakeUuid);
|
||||||
|
|
||||||
|
await commandDownloadFileStart(fakeDownloadURL, dest, {
|
||||||
|
overwrite: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastFileUpdateCalled = new Promise<void>((resolve) =>
|
||||||
|
emit.mockImplementation(
|
||||||
|
(_event, {status}) => status === 'error' && resolve(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// We remove the end file to cause an error
|
||||||
|
removeTmpDir();
|
||||||
|
fakeDownloadStream.write('Obi');
|
||||||
|
|
||||||
|
await lastFileUpdateCalled;
|
||||||
|
|
||||||
|
expect(emit).toBeCalledTimes(2);
|
||||||
|
expect(emit).toHaveBeenNthCalledWith(1, 'download-file-update', {
|
||||||
|
id: fakeUuid,
|
||||||
|
downloaded: 3,
|
||||||
|
totalSize: fakeFileSize,
|
||||||
|
status: 'downloading',
|
||||||
|
});
|
||||||
|
expect(emit).toHaveBeenNthCalledWith(2, 'download-file-update', {
|
||||||
|
id: fakeUuid,
|
||||||
|
downloaded: 3,
|
||||||
|
totalSize: fakeFileSize,
|
||||||
|
status: 'error',
|
||||||
|
message: expect.stringContaining('ENOENT'),
|
||||||
|
stack: expect.anything(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
"extends": "../tsconfig.base.json",
|
"extends": "../tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "lib",
|
"outDir": "lib",
|
||||||
"rootDir": "src"
|
"rootDir": "src",
|
||||||
|
"esModuleInterop": true
|
||||||
},
|
},
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2795,6 +2795,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/unist" "*"
|
"@types/unist" "*"
|
||||||
|
|
||||||
|
"@types/memorystream@^0.3.0":
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/memorystream/-/memorystream-0.3.0.tgz#7616df4c42a479805d052a058d990b879d5e368f"
|
||||||
|
integrity sha512-gzh6mqZcLryYHn4g2MuMWjo9J1+Py/XYwITyZmUxV7ZoBIi7bTbBgSiuC5tcm3UL3gmaiYssQFDlXr/3fK94cw==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/mime@*":
|
"@types/mime@*":
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a"
|
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a"
|
||||||
@@ -3147,6 +3154,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.1.tgz#83ecf4ec22a8c218c71db25f316619fe5b986011"
|
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.1.tgz#83ecf4ec22a8c218c71db25f316619fe5b986011"
|
||||||
integrity sha512-7cTXwKP/HLOPVgjg+YhBdQ7bMiobGMuoBmrGmqwIWJv8elC6t1DfVc/mn4fD9UE1IjhwmhaQ5pGVXkmXbH0rhg==
|
integrity sha512-7cTXwKP/HLOPVgjg+YhBdQ7bMiobGMuoBmrGmqwIWJv8elC6t1DfVc/mn4fD9UE1IjhwmhaQ5pGVXkmXbH0rhg==
|
||||||
|
|
||||||
|
"@types/tmp@^0.2.2":
|
||||||
|
version "0.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.2.tgz#424537a3b91828cb26aaf697f21ae3cd1b69f7e7"
|
||||||
|
integrity sha512-MhSa0yylXtVMsyT8qFpHA1DLHj4DvQGH5ntxrhHSh8PxUVNi35Wk+P5hVgqbO2qZqOotqr9jaoPRL+iRjWYm/A==
|
||||||
|
|
||||||
"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3":
|
"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3":
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
|
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
|
||||||
@@ -9388,6 +9400,11 @@ media-typer@0.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
|
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
|
||||||
integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
|
integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
|
||||||
|
|
||||||
|
memorystream@^0.3.1:
|
||||||
|
version "0.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
|
||||||
|
integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI=
|
||||||
|
|
||||||
merge-descriptors@1.0.1:
|
merge-descriptors@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||||
|
|||||||
Reference in New Issue
Block a user