Skip to content

Commit

Permalink
feat: add get and search task smapi commands
Browse files Browse the repository at this point in the history
  • Loading branch information
kakha urigashvili authored and RonWang committed May 1, 2020
1 parent 069b219 commit fb881d6
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 0 deletions.
20 changes: 20 additions & 0 deletions lib/commands/option-model.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,25 @@
"description": "The client-id when registering LWA application, uses CLI's default if not set",
"alias": null,
"stringInput": "REQUIRED"
},
"task-name": {
"name": "task-name",
"description": "Name of a task.",
"stringInput": "REQUIRED"
},
"task-version": {
"name": "task-version",
"description": "Version of a task. For example: 1, 2, 3 and so on.",
"stringInput": "REQUIRED"
},
"provider-skill-id": {
"name": "provider-skill-id",
"description": "Task provider skill id. When this is specified, we will only fetch the tasks from this given skill ID.",
"stringInput": "OPTIONAL"
},
"keywords": {
"name": "keywords",
"description": "Keywords can be description of tasks, task name or tags in task definition.\n[MULTIPLE]: Values can be separated by comma.",
"stringInput": "OPTIONAL"
}
}
47 changes: 47 additions & 0 deletions lib/commands/smapi/appended-commands/get-task/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const { AbstractCommand } = require('@src/commands/abstract-command');
const jsonView = require('@src/view/json-view');
const Messenger = require('@src/view/messenger');
const optionModel = require('@src/commands/option-model');
const profileHelper = require('@src/utils/profile-helper');
const SmapiClient = require('@src/clients/smapi-client');


class GetTaskCommand extends AbstractCommand {
name() {
return 'get-task';
}

description() {
return 'Get the task definition details specified by the taskName and version.';
}

requiredOptions() {
return ['skill-id', 'task-name', 'task-version'];
}

optionalOptions() {
return ['profile', 'debug'];
}

handle(cmd, cb) {
const { skillId, taskName, taskVersion, profile, debug } = cmd;
const smapiClient = new SmapiClient({
profile: profileHelper.runtimeProfile(profile),
doDebug: debug
});
smapiClient.task.getTask(skillId, taskName, taskVersion, (err, result) => {
if (err || result.statusCode >= 400) {
const error = err || jsonView.toString(result.body);
Messenger.getInstance().error(error);
cb(error);
} else {
const res = jsonView.toString(JSON.parse(result.body.definition));
Messenger.getInstance().info(res);
cb(null, res);
}
});
}
}

module.exports = GetTaskCommand;
module.exports.createCommand = new GetTaskCommand(optionModel).createCommand();
60 changes: 60 additions & 0 deletions lib/commands/smapi/appended-commands/search-task/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const R = require('ramda');

const { AbstractCommand } = require('@src/commands/abstract-command');
const jsonView = require('@src/view/json-view');
const Messenger = require('@src/view/messenger');
const optionModel = require('@src/commands/option-model');
const profileHelper = require('@src/utils/profile-helper');
const SmapiClient = require('@src/clients/smapi-client');


class SearchTaskCommand extends AbstractCommand {
name() {
return 'search-task';
}

description() {
return 'List the tasks summary information based on keywords or provider skillId. '
+ 'If both keywords and provider skillId are not specified, will list all the tasks '
+ 'summary information accessible by the skillId.';
}

requiredOptions() {
return ['skill-id'];
}

optionalOptions() {
return ['next-token', 'max-results', 'provider-skill-id', 'keywords', 'profile', 'debug'];
}

static encodeSpaces(keywords) {
return keywords ? keywords.replace(/\s/g, '%20') : keywords;
}

handle(cmd, cb) {
const { skillId, providerSkillId, maxResults, nextToken, profile, debug } = cmd;
const keywords = SearchTaskCommand.encodeSpaces(cmd.keywords);
const queryParams = R.reject(R.isNil, { maxResults, nextToken });

const smapiClient = new SmapiClient({
profile: profileHelper.runtimeProfile(profile),
doDebug: debug
});

smapiClient.task.searchTask(skillId, keywords, providerSkillId, queryParams, (err, result) => {
if (err || result.statusCode >= 400) {
const error = err || jsonView.toString(result.body);
Messenger.getInstance().error(error);
cb(error);
} else {
const res = jsonView.toString(result.body);
Messenger.getInstance().info(res);
cb(null, res);
}
});
}
}


module.exports = SearchTaskCommand;
module.exports.createCommand = new SearchTaskCommand(optionModel).createCommand();
4 changes: 4 additions & 0 deletions lib/commands/smapi/smapi-commander.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const { apiToCommanderMap } = require('@src/commands/smapi/customizations/parame

const uploadCatalog = require('./appended-commands/upload-catalog');
const exportPackage = require('./appended-commands/export-package');
const getTask = require('./appended-commands/get-task');
const searchTask = require('./appended-commands/search-task');


const defaultOptions = [{
Expand Down Expand Up @@ -93,6 +95,8 @@ const makeSmapiCommander = () => {
// register hand-written appended commands
uploadCatalog.createCommand(program);
exportPackage.createCommand(program);
getTask.createCommand(program);
searchTask.createCommand(program);

program._name = 'ask smapi';
program
Expand Down
76 changes: 76 additions & 0 deletions test/unit/commands/smapi/appended-commands/get-task/index-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const { expect } = require('chai');
const sinon = require('sinon');

const AuthorizationController = require('@src/controllers/authorization-controller');
const GetTaskCommand = require('@src/commands/smapi/appended-commands/get-task');
const httpClient = require('@src/clients/http-client');
const jsonView = require('@src/view/json-view');
const Messenger = require('@src/view/messenger');
const optionModel = require('@src/commands/option-model');
const profileHelper = require('@src/utils/profile-helper');


describe('Command get-task test ', () => {
let infoStub;
let errorStub;
let instance;
const cmdOptions = {
skillId: 'test',
taskName: 'test',
taskVersion: 'test'
};

beforeEach(() => {
infoStub = sinon.stub();
errorStub = sinon.stub();
sinon.stub(Messenger, 'getInstance').returns({
info: infoStub,
error: errorStub,
});
sinon.stub(AuthorizationController.prototype, 'tokenRefreshAndRead').callsArgWith(1);
sinon.stub(profileHelper, 'runtimeProfile').returns('test');
instance = new GetTaskCommand(optionModel);
});

it('| should have options configured', () => {
expect(instance.name()).be.a('string');
expect(instance.description()).be.a('string');
expect(instance.requiredOptions()).be.a('array');
expect(instance.optionalOptions()).be.a('array');
});

it('| should display task definition', (done) => {
const definition = '{ "x":"y", "b": "z"}';
const expectedOutput = jsonView.toString(JSON.parse(definition));
sinon.stub(httpClient, 'request').yields(null, { body: { definition }, statusCode: 200 });

instance.handle(cmdOptions, () => {
expect(infoStub.calledOnceWith(expectedOutput)).eql(true);
done();
});
});

it('| should display error thrown by smapi client', (done) => {
const testError = 'testError';
sinon.stub(httpClient, 'request').yields(new Error(testError));

instance.handle(cmdOptions, (err) => {
expect(err.message).eql(testError);
done();
});
});

it('| should display error thrown by smapi server', (done) => {
const body = { message: 'Bad request.' };
sinon.stub(httpClient, 'request').yields(null, { body, statusCode: 400 });

instance.handle(cmdOptions, (err) => {
expect(err).includes('"message": "Bad request."');
done();
});
});

afterEach(() => {
sinon.restore();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const { expect } = require('chai');
const sinon = require('sinon');

const AuthorizationController = require('@src/controllers/authorization-controller');
const SearchTaskCommand = require('@src/commands/smapi/appended-commands/search-task');
const httpClient = require('@src/clients/http-client');
const jsonView = require('@src/view/json-view');
const Messenger = require('@src/view/messenger');
const optionModel = require('@src/commands/option-model');
const profileHelper = require('@src/utils/profile-helper');


describe('Command search-task test ', () => {
let infoStub;
let errorStub;
let instance;
const cmdOptions = {
skillId: 'test',
providerSkillId: 'test',
maxResults: 'test',
nextToken: 'test'
};

beforeEach(() => {
infoStub = sinon.stub();
errorStub = sinon.stub();
sinon.stub(Messenger, 'getInstance').returns({
info: infoStub,
error: errorStub,
});
sinon.stub(AuthorizationController.prototype, 'tokenRefreshAndRead').callsArgWith(1);
sinon.stub(profileHelper, 'runtimeProfile').returns('test');
instance = new SearchTaskCommand(optionModel);
});

it('| should have options configured', () => {
expect(instance.name()).be.a('string');
expect(instance.description()).be.a('string');
expect(instance.requiredOptions()).be.a('array');
expect(instance.optionalOptions()).be.a('array');
});

it('| should display task list', (done) => {
const body = {
taskSummaryList: [
{
description: 'y',
name: 'x',
version: '1'
}
],
totalCount: 1
};
const expectedOutput = jsonView.toString(body);
sinon.stub(httpClient, 'request').yields(null, { body, statusCode: 200 });

instance.handle(cmdOptions, () => {
expect(infoStub.calledOnceWith(expectedOutput)).eql(true);
done();
});
});

it('| should encode spaces', () => {
const input = 'Test, TestTwo, Three,Four';
const expected = 'Test,%20TestTwo,%20Three,Four';
const result = SearchTaskCommand.encodeSpaces(input);
expect(result).eql(expected);
});

it('| should display error thrown by smapi client', (done) => {
const testError = 'testError';
sinon.stub(httpClient, 'request').yields(new Error(testError));

instance.handle(cmdOptions, (err) => {
expect(err.message).eql(testError);
done();
});
});

it('| should display error thrown by smapi server', (done) => {
const body = { message: 'Bad request.' };
sinon.stub(httpClient, 'request').yields(null, { body, statusCode: 400 });

instance.handle(cmdOptions, (err) => {
expect(err).includes('"message": "Bad request."');
done();
});
});

afterEach(() => {
sinon.restore();
});
});
5 changes: 5 additions & 0 deletions test/unit/run-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ require('module-alias/register');
// command - smapi - export-package
'@test/unit/commands/smapi/appended-commands/export-package/index-test.js',
'@test/unit/commands/smapi/appended-commands/export-package/helper-test.js',
// command - smapi - get-task
'@test/unit/commands/smapi/appended-commands/get-task/index-test.js',
// command - smapi - search-task
'@test/unit/commands/smapi/appended-commands/search-task/index-test.js',

// command - util
'@test/unit/commands/util/upgrade-project/index-test',
'@test/unit/commands/util/upgrade-project/ui-test',
Expand Down

0 comments on commit fb881d6

Please sign in to comment.