Skip to content

Commit

Permalink
Add cli commands (#139)
Browse files Browse the repository at this point in the history
* Make change to assume dest folder. Delete 2 old tests that looked for old behavior, add 2 more tests that look for new behavior

* Sort files

* Update src/RokuDeploy.ts

Co-authored-by: Bronley Plumb <[email protected]>

* Removed redundant entry.dest is null situation

* Added a few commands, not all are working correctly

* Move commands to their own file

* More command files

* Change commands to help with tests

* Add testing suite for all cli (2 tests are not working)

* Updated cli file after adding in commands and tests

* Fixed a few test cases

* Change name and input of table helper

* Changed name of toTable

* Make test for objectToTable

* add yargs to pacjage.json

* add package-lock.json

* add new line at eof

* Add test for coverage, also remove an unncessary '?'

* Change function name

* last function name change

---------

Co-authored-by: Bronley Plumb <[email protected]>
  • Loading branch information
MilapNaik and TwitchBronBron authored Feb 6, 2024
1 parent 7a629e1 commit 8af51a1
Show file tree
Hide file tree
Showing 25 changed files with 859 additions and 71 deletions.
199 changes: 137 additions & 62 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"parse-ms": "^2.1.0",
"postman-request": "^2.88.1-postman.32",
"temp-dir": "^2.0.0",
"xml2js": "^0.5.0"
"xml2js": "^0.5.0",
"yargs": "^17.7.2"
},
"devDependencies": {
"@types/chai": "^4.2.22",
Expand All @@ -45,6 +46,7 @@
"@types/request": "^2.47.0",
"@types/sinon": "^10.0.4",
"@types/xml2js": "^0.4.5",
"@types/yargs": "^17.0.32",
"@typescript-eslint/eslint-plugin": "5.1.0",
"@typescript-eslint/parser": "5.1.0",
"chai": "^4.3.4",
Expand Down
2 changes: 1 addition & 1 deletion src/RokuDeploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ export class RokuDeploy {
* Centralizes getting output zip file path based on passed in options
* @param options
*/
public getOutputZipFilePath(options: GetOutputZipFilePathOptions) {
public getOutputZipFilePath(options?: GetOutputZipFilePathOptions) {
options = this.getOptions(options) as any;

let zipFileName = options.outFile;
Expand Down
331 changes: 331 additions & 0 deletions src/cli.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,331 @@
import * as childProcess from 'child_process';
import { cwd, expectPathExists, rootDir, stagingDir, tempDir, outDir } from './testUtils.spec';
import * as fsExtra from 'fs-extra';
import { expect } from 'chai';
import * as path from 'path';
import { createSandbox } from 'sinon';
import { rokuDeploy } from './index';
import { PublishCommand } from './commands/PublishCommand';
import { ConvertToSquashfsCommand } from './commands/ConvertToSquashfsCommand';
import { RekeyDeviceCommand } from './commands/RekeyDeviceCommand';
import { SignExistingPackageCommand } from './commands/SignExistingPackageCommand';
import { DeployCommand } from './commands/DeployCommand';
import { DeleteInstalledChannelCommand } from './commands/DeleteInstalledChannelCommand';
import { TakeScreenshotCommand } from './commands/TakeScreenshotCommand';
import { GetDeviceInfoCommand } from './commands/GetDeviceInfoCommand';
import { GetDevIdCommand } from './commands/GetDevIdCommand';
import { RetrieveSignedPackageCommand } from './commands/RetrieveSignedPackageCommand';

const sinon = createSandbox();

function execSync(command: string) {
const output = childProcess.execSync(command, { cwd: tempDir });
process.stdout.write(output);
return output;
}
describe('cli', () => {
before(function build() {
this.timeout(20000);
execSync('npm run build');
});
beforeEach(() => {
fsExtra.emptyDirSync(tempDir);
//most tests depend on a manifest file existing, so write an empty one
fsExtra.outputFileSync(`${rootDir}/manifest`, '');
sinon.restore();
});
afterEach(() => {
fsExtra.removeSync(tempDir);
sinon.restore();
});

it('Successfully runs prepublishToStaging', () => {
//make the files
fsExtra.outputFileSync(`${rootDir}/source/main.brs`, '');

expect(() => {
execSync(`node ${cwd}/dist/cli.js prepublishToStaging --stagingDir ${stagingDir} --rootDir ${rootDir}`);
}).to.not.throw();
});

it('Successfully copies rootDir folder to staging folder', () => {
fsExtra.outputFileSync(`${rootDir}/source/main.brs`, '');

execSync(`node ${cwd}/dist/cli.js prepublishToStaging --rootDir ${rootDir} --stagingDir ${stagingDir}`);

expectPathExists(`${stagingDir}/source/main.brs`);
});

it('Successfully uses zipPackage to create .zip', () => {
fsExtra.outputFileSync(`${stagingDir}/manifest`, '');

execSync(`node ${cwd}/dist/cli.js zipPackage --stagingDir ${stagingDir} --outDir ${outDir}`);
expectPathExists(`${outDir}/roku-deploy.zip`);
});

it('Successfully uses createPackage to create .pkg', () => {
execSync(`node ${cwd}/dist/cli.js createPackage --stagingDir ${stagingDir} --rootDir ${rootDir} --outDir ${outDir}`);
expectPathExists(`${outDir}/roku-deploy.zip`);
});

it('Publish passes proper options', async () => {
const stub = sinon.stub(rokuDeploy, 'publish').callsFake(async () => {
return Promise.resolve({
message: 'Publish successful',
results: {}
});
});

const command = new PublishCommand();
await command.run({
host: '1.2.3.4',
password: '5536',
outDir: outDir,
outFile: 'rokudeploy-outfile'
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4',
password: '5536',
outDir: outDir,
outFile: 'rokudeploy-outfile'
});
});

it('Converts to squashfs', async () => {
const stub = sinon.stub(rokuDeploy, 'convertToSquashfs').callsFake(async () => {
return Promise.resolve();
});

const command = new ConvertToSquashfsCommand();
await command.run({
host: '1.2.3.4',
password: '5536'
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4',
password: '5536'
});
});

it('Rekeys a device', async () => {
const stub = sinon.stub(rokuDeploy, 'rekeyDevice').callsFake(async () => {
return Promise.resolve();
});

const command = new RekeyDeviceCommand();
await command.run({
host: '1.2.3.4',
password: '5536',
rekeySignedPackage: `${tempDir}/testSignedPackage.pkg`,
signingPassword: '12345',
rootDir: rootDir,
devId: 'abcde'
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4',
password: '5536',
rekeySignedPackage: `${tempDir}/testSignedPackage.pkg`,
signingPassword: '12345',
rootDir: rootDir,
devId: 'abcde'
});
});

it('Signs an existing package', async () => {
const stub = sinon.stub(rokuDeploy, 'signExistingPackage').callsFake(async () => {
return Promise.resolve('');
});

const command = new SignExistingPackageCommand();
await command.run({
host: '1.2.3.4',
password: '5536',
signingPassword: undefined,
stagingDir: stagingDir
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4',
password: '5536',
signingPassword: undefined,
stagingDir: stagingDir
});
});

it('Retrieves a signed package', async () => {
const stub = sinon.stub(rokuDeploy, 'retrieveSignedPackage').callsFake(async () => {
return Promise.resolve('');
});

const command = new RetrieveSignedPackageCommand();
await command.run({
pathToPkg: 'path_to_pkg',
host: '1.2.3.4',
password: '5536',
outFile: 'roku-deploy-test'
});

expect(
stub.getCall(0).args
).to.eql(['path_to_pkg', {
host: '1.2.3.4',
password: '5536',
outFile: 'roku-deploy-test'
}]);
});

it('Deploys a package', async () => {
const stub = sinon.stub(rokuDeploy, 'deploy').callsFake(async () => {
return Promise.resolve({
message: 'Convert successful',
results: {}
});
});

const command = new DeployCommand();
await command.run({
host: '1.2.3.4',
password: '5536',
rootDir: rootDir
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4',
password: '5536',
rootDir: rootDir
});
});

it('Deletes an installed channel', async () => {
const stub = sinon.stub(rokuDeploy, 'deleteInstalledChannel').callsFake(async () => {
return Promise.resolve({ response: {}, body: {} });
});

const command = new DeleteInstalledChannelCommand();
await command.run({
host: '1.2.3.4',
password: '5536'
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4',
password: '5536'
});
});

it('Takes a screenshot', async () => {
const stub = sinon.stub(rokuDeploy, 'takeScreenshot').callsFake(async () => {
return Promise.resolve('');
});

const command = new TakeScreenshotCommand();
await command.run({
host: '1.2.3.4',
password: '5536'
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4',
password: '5536'
});
});

it('Gets output zip file path', () => {
let zipFilePath = execSync(`node ${cwd}/dist/cli.js getOutputZipFilePath --outFile "roku-deploy" --outDir ${outDir}`).toString();

expect(zipFilePath.trim()).to.equal(path.join(path.resolve(outDir), 'roku-deploy.zip'));
});

it('Gets output pkg file path', () => {
let pkgFilePath = execSync(`node ${cwd}/dist/cli.js getOutputPkgFilePath --outFile "roku-deploy" --outDir ${outDir}`).toString();

expect(pkgFilePath.trim()).to.equal(path.join(path.resolve(outDir), 'roku-deploy.pkg'));
});

it('Device info arguments are correct', async () => {
const stub = sinon.stub(rokuDeploy, 'getDeviceInfo').callsFake(async () => {
return Promise.resolve({
response: {},
body: {}
});
});

const command = new GetDeviceInfoCommand();
await command.run({
host: '1.2.3.4'
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4'
});
});

it('Prints device info to console', async () => {
let consoleOutput = '';
sinon.stub(console, 'log').callsFake((...args) => {
consoleOutput += args.join(' ') + '\n';
});
sinon.stub(rokuDeploy, 'getDeviceInfo').returns(Promise.resolve({
'device-id': '1234',
'serial-number': 'abcd'
}));
await new GetDeviceInfoCommand().run({
host: '1.2.3.4'
});

// const consoleOutputObject: Record<string, string> = {
// 'device-id': '1234',
// 'serial-number': 'abcd'
// };

expect(consoleOutput).to.eql([
'Name Value ',
'---------------------------',
'device-id 1234 ',
'serial-number abcd \n'
].join('\n'));
});

it('Gets dev id', async () => {
const stub = sinon.stub(rokuDeploy, 'getDevId').callsFake(async () => {
return Promise.resolve('');
});

const command = new GetDevIdCommand();
await command.run({
host: '1.2.3.4',
password: '5536'
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4'
});
});

it('Zips a folder', () => {
execSync(`node ${cwd}/dist/cli.js zipFolder --srcFolder ${rootDir} --zipFilePath "roku-deploy.zip"`);

expectPathExists(`${tempDir}/roku-deploy.zip`);
});
});
Loading

0 comments on commit 8af51a1

Please sign in to comment.