Skip to content

Commit

Permalink
Merge 6fdc081 into 1a0c294
Browse files Browse the repository at this point in the history
  • Loading branch information
Bill7zz committed May 29, 2019
2 parents 1a0c294 + 6fdc081 commit 3e47118
Show file tree
Hide file tree
Showing 9 changed files with 974 additions and 256 deletions.
1 change: 1 addition & 0 deletions lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"libraries/botframework-config",
"libraries/botframework-connector",
"libraries/botframework-schema",
"libraries/functional-tests",
"libraries/testbot",
"transcripts"
],
Expand Down
18 changes: 18 additions & 0 deletions libraries/functional-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "functional-tests",
"version": "1.0.0",
"description": "Test that hits services",
"main": "",
"dependencies": {
"swagger-client": "^2.1.18"
},
"directories": {
"test": "tests"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT"
}
61 changes: 61 additions & 0 deletions libraries/functional-tests/tests/directLine.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const assert = require('assert');
const directLineSpec = require('./directline-swagger.json');
const Swagger = require('swagger-client');

const directLineClientName = 'DirectLineClient';
const userMessage = 'Contoso';
const directLineSecret = process.env.DIRECT_LINE_KEY || null;

const auths = {
AuthorizationBotConnector: new Swagger.ApiKeyAuthorization('Authorization', 'BotConnector ' + directLineSecret, 'header'),
};

function getDirectLineClient() {
return new Swagger({
spec: directLineSpec,
usePromise: true,
authorizations: auths
});
}

async function sendMessage(client, conversationId) {
let status;
do{
await client.Conversations.Conversations_PostMessage({
conversationId: conversationId,
message: {
from: directLineClientName,
text: userMessage
}
}).then((result) => {
status = result.status;
}).catch((err)=>{
status = err.status;
});
}while(status == 502);
}

function getMessages(client, conversationId) {
let watermark = null;
return client.Conversations.Conversations_GetMessages({ conversationId: conversationId, watermark: watermark })
.then((response) => {
return response.obj.messages.filter((message) => message.from !== directLineClientName);
});
}

function getConversationId(client) {
return client.Conversations.Conversations_NewConversation()
.then((response) => response.obj.conversationId);
}

describe('Test Azure Bot', function(){
this.timeout(60000);
it('Check deployed bot answer', async function(){
const directLineClient = await getDirectLineClient();
const conversationId = await getConversationId(directLineClient);
await sendMessage(directLineClient, conversationId);
const messages = await getMessages(directLineClient, conversationId);
const result = messages.filter((message) => message.text.includes('you said'));
assert(result[0].text == `you said "${ userMessage }" 0`, `test fail`);
});
});
304 changes: 304 additions & 0 deletions libraries/functional-tests/tests/directline-swagger.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
{
"swagger": "2.0",
"info": {
"version": "v1",
"title": "Bot Connector - Direct Line API - V1.0",
"description": "Direct Line\r\n===========\r\n\r\n\r\nThe Direct Line API is a simple REST API for connecting directly to a single bot. This API is intended for developers\r\nwriting their own client applications, web chat controls, or mobile apps that will talk to their bot.\r\n\r\nCredentials for the Direct Line API may be obtained from the Bot Framework developer portal, and will only allow the\r\ncaller to connect to the bot for which they were generated. If you are writing a server-to-server application,\r\nthe Direct Line secret may be used directly against the API. If instead you are writing an application where a client\r\nconnects directly (and possibly insecurely) to the Direct Line API, you may exchange the secret for a token that will\r\nwork only for a single conversation and only for a limited amount of time. Tokens expire by default after 30 minutes\r\nalthough they may be renewed up until their expiration.\r\n\r\nThe secret or token (depending on the authorization model) are supplied as basic auth with the \"BotConnector\" scheme\r\nand no further encoding. Example auth header:\r\n\r\n -- connect to directline.botframework.com --\r\n GET /api/tokens\r\n Authorization: BotConnector RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0\r\n\r\nDon't include the Ocp-Apim-Subscription-Key header. The contents of this header are your bot's secret key. The\r\nbot's secret key is not necessary when using the Direct Line API.\r\n\r\nEach conversation on the Direct Line channel must be explicitly started using a POST to the\r\nhttps://directline.botframework.com/api/conversations endpoint.\r\nIf the call was authorized with a token, the conversation ID is the conversation ID in the scoped token. If a\r\nsecret was used to start the conversation, the conversation will be started with a new, random ID.\r\n\r\nThe client may send messages to the bot by calling POST on https://directline.botframework.com/api/conversations/{conversationId}/messages.\r\n\r\nThe client may retrieve messages sent by the bot by calling GET on https://directline.botframework.com/api/conversations/{conversationId}/messages.\r\nThe JSON structure returned contains a watermark that can be sent on subsequent requests to skip old messages.\r\n\r\nThe Direct Line API does not store messages indefinitely. Your client application must pick them up quickly before\r\nthey are deleted.\r\n\r\n# Client libraries for the Direct Line API\r\n\r\n* [Direct Line Nuget package](https://www.nuget.org/packages/Microsoft.Bot.Connector.DirectLine)\r\n* Generate your own from the [Direct Line Swagger file](swagger.json)\r\n",
"termsOfService": "https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/default.aspx",
"contact": {
"name": "Bot Framework",
"url": "https://botframework.com",
"email": "botframework@microsoft.com"
},
"license": {
"name": "The MIT License (MIT)",
"url": "https://opensource.org/licenses/MIT"
}
},
"host": "directline.botframework.com",
"schemes": [ "https" ],
"paths": {
"/api/tokens/{conversationId}/renew": {
"get": {
"tags": [ "Tokens" ],
"summary": "Renew a token for a conversation",
"operationId": "Tokens_RenewToken",
"consumes": [ ],
"produces": [ "application/json", "text/json", "text/html", "application/xml", "text/xml" ],
"parameters": [
{
"name": "conversationId",
"in": "path",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "A string is returned\r\n",
"schema": { "type": "string" }
},
"401": { "description": "No content is returned with this status code.\r\n\r\nThe BasicAuth header is missing for this request.\r\n" },
"403": { "description": "You are forbidden from performing this action because your token or secret is invalid.\r\n\r\n" },
"404": { "description": "The response is an ErrorMessage response. Look at the Code field for a breakdown and message field for description of the error.\r\n\r\nresource was not found" }
},
"deprecated": false
}
},
"/api/tokens/conversation": {
"post": {
"tags": [ "Tokens" ],
"summary": "Generate a token for a new conversation",
"operationId": "Tokens_GenerateTokenForNewConversation",
"consumes": [ ],
"produces": [ "application/json", "text/json", "text/html", "application/xml", "text/xml" ],
"responses": {
"200": {
"description": "A string is returned\r\n",
"schema": { "type": "string" }
},
"401": { "description": "No content is returned with this status code.\r\n\r\nThe BasicAuth header is missing for this request.\r\n" },
"403": { "description": "You are forbidden from performing this action because your token or secret is invalid.\r\n\r\n" },
"404": { "description": "The response is an ErrorMessage response. Look at the Code field for a breakdown and message field for description of the error.\r\n\r\nresource was not found" }
},
"deprecated": false
}
},
"/api/conversations": {
"post": {
"tags": [ "Conversations" ],
"summary": "Start a new conversation",
"operationId": "Conversations_NewConversation",
"consumes": [ ],
"produces": [ "application/json", "text/json", "text/html", "application/xml", "text/xml" ],
"responses": {
"200": {
"description": "A conversation object is returned\r\n",
"schema": { "$ref": "#/definitions/Conversation" }
},
"401": { "description": "No content is returned with this status code.\r\n\r\nThe BasicAuth header is missing for this request.\r\n" },
"403": { "description": "You are forbidden from performing this action because your token or secret is invalid.\r\n\r\n" },
"404": { "description": "The response is an ErrorMessage response. Look at the Code field for a breakdown and message field for description of the error.\r\n\r\nresource was not found" },
"409": { "description": "You are trying to create an object that already exists." }
},
"deprecated": false
}
},
"/api/conversations/{conversationId}/messages": {
"get": {
"tags": [ "Conversations" ],
"summary": "Get messages in this conversation. This method is paged with the 'watermark' parameter.",
"operationId": "Conversations_GetMessages",
"consumes": [ ],
"produces": [ "application/json", "text/json", "text/html", "application/xml", "text/xml" ],
"parameters": [
{
"name": "conversationId",
"in": "path",
"description": "Conversation ID",
"required": true,
"type": "string"
},
{
"name": "watermark",
"in": "query",
"description": "(Optional) only returns messages newer than this watermark",
"required": false,
"type": "string"
}
],
"responses": {
"200": {
"description": "A set of messages is returned",
"schema": { "$ref": "#/definitions/MessageSet" }
},
"401": { "description": "No content is returned with this status code.\r\n\r\nThe BasicAuth header is missing for this request.\r\n" },
"403": { "description": "You are forbidden from performing this action because your token or secret is invalid.\r\n\r\n" },
"404": { "description": "The response is an ErrorMessage response. Look at the Code field for a breakdown and message field for description of the error.\r\n\r\nresource was not found" }
},
"deprecated": false
},
"post": {
"tags": [ "Conversations" ],
"summary": "Send a message",
"operationId": "Conversations_PostMessage",
"consumes": [ "application/json", "text/json", "text/html", "application/xml", "text/xml", "application/x-www-form-urlencoded" ],
"produces": [ ],
"parameters": [
{
"name": "conversationId",
"in": "path",
"description": "Conversation ID",
"required": true,
"type": "string"
},
{
"name": "message",
"in": "body",
"description": "Message to send",
"required": true,
"schema": { "$ref": "#/definitions/Message" }
}
],
"responses": {
"204": {
"description": "Success - no content",
"schema": { "$ref": "#/definitions/ErrorMessage" }
},
"401": { "description": "No content is returned with this status code.\r\n\r\nThe BasicAuth header is missing for this request.\r\n" },
"403": { "description": "You are forbidden from performing this action because your token or secret is invalid.\r\n\r\n" },
"404": { "description": "The response is an ErrorMessage response. Look at the Code field for a breakdown and message field for description of the error.\r\n\r\nresource was not found" }
},
"deprecated": false
}
},
"/api/conversations/{conversationId}/upload": {
"post": {
"tags": [ "Conversations" ],
"summary": "Upload file(s) and send as attachment(s)",
"operationId": "Conversations_Upload",
"consumes": [ ],
"produces": [ ],
"parameters": [
{
"name": "conversationId",
"in": "path",
"description": "",
"required": true,
"type": "string"
}
],
"responses": {
"204": { "description": "Success - no content" },
"401": { "description": "No content is returned with this status code.\r\n\r\nThe BasicAuth header is missing for this request.\r\n" },
"403": { "description": "You are forbidden from performing this action because your token or secret is invalid.\r\n\r\n" },
"404": { "description": "The response is an ErrorMessage response. Look at the Code field for a breakdown and message field for description of the error.\r\n\r\nresource was not found" }
},
"deprecated": false
}
}
},
"definitions": {
"Conversation": {
"description": "A conversation object returned by POST /api/conversations",
"type": "object",
"properties": {
"conversationId": {
"description": "ID for this conversation",
"type": "string"
},
"token": {
"description": "Token scoped to this conversation",
"type": "string"
},
"eTag": { "type": "string" }
}
},
"MessageSet": {
"description": "A collection of messages",
"type": "object",
"properties": {
"messages": {
"description": "Messages",
"type": "array",
"items": { "$ref": "#/definitions/Message" }
},
"watermark": {
"description": "Maximum watermark included in this set of messages",
"type": "string"
},
"eTag": { "type": "string" }
}
},
"Message": {
"description": "A communication message sent to/from Direct Line",
"type": "object",
"properties": {
"id": {
"description": "ID for this message",
"type": "string"
},
"conversationId": {
"description": "Conversation ID for this message",
"type": "string"
},
"created": {
"format": "date-time",
"description": "UTC timestamp when this message was created",
"type": "string"
},
"from": {
"description": "Identity of the sender of this message",
"type": "string"
},
"text": {
"description": "Text in this message",
"type": "string"
},
"channelData": {
"$ref": "#/definitions/Object",
"description": "Opaque block of data passed to/from bot via the ChannelData field"
},
"images": {
"description": "Array of URLs for images included in this message",
"type": "array",
"items": { "type": "string" }
},
"attachments": {
"description": "Array of non-image attachments included in this message",
"type": "array",
"items": { "$ref": "#/definitions/Attachment" }
},
"eTag": { "type": "string" }
}
},
"Object": {
"type": "object",
"properties": { }
},
"Attachment": {
"description": "An attachment",
"type": "object",
"properties": {
"url": {
"description": "URL for this attachment",
"type": "string"
},
"contentType": {
"description": "Content type for this attachment",
"type": "string"
}
}
},
"ErrorMessage": {
"description": "A standardized message error payload",
"type": "object",
"properties": { "error": { "$ref": "#/definitions/Error" } }
},
"Error": {
"type": "object",
"properties": {
"code": {
"description": "Error code",
"enum": [ "MissingProperty", "MalformedData", "NotFound", "ServiceError", "Internal", "InvalidRange", "NotSupported", "NotAllowed", "BadCertificate" ],
"type": "string"
},
"message": {
"description": "Error message",
"type": "string"
},
"statusCode": {
"format": "int32",
"description": "Status code",
"type": "integer"
}
}
}
},
"securityDefinitions": {
"basic": {
"type": "basic",
"description": "Basic HTTP Authentication using BotConnector auth scheme and secret/token as password"
}
}
}
2 changes: 2 additions & 0 deletions libraries/testbot/deployment-scripts/windows/.deployment
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[config]
command = deploy.cmd

0 comments on commit 3e47118

Please sign in to comment.