-
Notifications
You must be signed in to change notification settings - Fork 73
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test dataplane related server.ts (#101)
* initial commit * Moved server build output to dist folder to avoid naming conflicts for tests
- Loading branch information
Showing
6 changed files
with
207 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/*********************************************************** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License | ||
**********************************************************/ | ||
import express = require('express'); | ||
import { generateDataPlaneRequestBody, API_VERSION, processDataPlaneResponse } from './dataPlaneHelper'; // note: remove auto-generated dataPlaneHelper.js in order to run this test | ||
|
||
describe('server', () => { | ||
const hostName = 'testHub.private.azure-devices-int.net'; | ||
it('generates data plane request with API version and query string specified in body', () => { | ||
const queryString = 'connectTimeoutInSeconds=20&responseTimeInSeconds=20'; | ||
const req = { | ||
body: { | ||
apiVersion: '2019-07-01-preview', | ||
hostName, | ||
httpMethod: 'POST', | ||
path: '/digitalTwins/testDevice/interfaces/sensor/commands/turnon', | ||
queryString, | ||
sharedAccessSignature: `SharedAccessSignature sr=${hostName}%2Fdevices%2Fquery&sig=123&se=456&skn=iothubowner` | ||
} | ||
}; | ||
const requestBody = generateDataPlaneRequestBody(req as express.Request); | ||
expect(requestBody).toEqual( | ||
{ | ||
body: undefined, | ||
headers: { | ||
'Accept': 'application/json', | ||
'Authorization': req.body.sharedAccessSignature, | ||
'Content-Type': 'application/json' | ||
}, | ||
method: 'POST', | ||
uri: `https://${hostName}/%2FdigitalTwins%2FtestDevice%2Finterfaces%2Fsensor%2Fcommands%2Fturnon?${queryString}&api-version=2019-07-01-preview`, | ||
} | ||
); | ||
}); | ||
|
||
it('generates data plane request without API version or query string specified in body', () => { | ||
const req = { | ||
body: { | ||
body: '{"query":"\\n SELECT deviceId as DeviceId,\\n status as Status,\\n FROM devices WHERE STARTSWITH(devices.deviceId, \'test\')"}', | ||
headers: { 'x-ms-max-item-count': 20 }, | ||
hostName, | ||
httpMethod: 'POST', | ||
path: 'devices/query', | ||
sharedAccessSignature: `SharedAccessSignature sr=${hostName}%2Fdevices%2Fquery&sig=123&se=456&skn=iothubowner` | ||
} | ||
}; | ||
const requestBody = generateDataPlaneRequestBody(req as express.Request); | ||
expect(requestBody).toEqual( | ||
{ | ||
body: '{"query":"\\n SELECT deviceId as DeviceId,\\n status as Status,\\n FROM devices WHERE STARTSWITH(devices.deviceId, \'test\')"}', | ||
headers: { | ||
'Accept': 'application/json', | ||
'Authorization': req.body.sharedAccessSignature, | ||
'Content-Type': 'application/json', | ||
'x-ms-max-item-count': 20 | ||
}, | ||
method: 'POST', | ||
uri: `https://${hostName}/devices%2Fquery?api-version=${API_VERSION}`, | ||
} | ||
); | ||
}); | ||
|
||
it('generates data plane response with success', () => { | ||
// tslint:disable | ||
const res: any = { | ||
headers: { | ||
'content-length': '10319', | ||
'content-type': 'application/json; charset=utf-8', | ||
vary: 'Origin', | ||
server: 'Microsoft-HTTPAPI/2.0', | ||
'iothub-errorcode': 'ServerError', | ||
date: 'Thu, 29 Aug 2019 00:49:10 GMT', | ||
connection: 'close' | ||
}, | ||
statusCode: 200 | ||
}; | ||
// tslint:enable | ||
const response = processDataPlaneResponse(res, null); | ||
// tslint:disable-next-line:no-magic-numbers | ||
expect(response.statusCode).toEqual(200); | ||
expect(response.body).toEqual({body: null, headers: res.headers}); | ||
}); | ||
|
||
it('generates data plane response with error', () => { | ||
// tslint:disable | ||
const res: any = { | ||
headers: { | ||
'content-length': '10319', | ||
'content-type': 'application/json; charset=utf-8', | ||
vary: 'Origin', | ||
server: 'Microsoft-HTTPAPI/2.0', | ||
'iothub-errorcode': 'ServerError', | ||
date: 'Thu, 29 Aug 2019 00:49:10 GMT', | ||
connection: 'close' | ||
}, | ||
statusCode: 500 | ||
}; | ||
// tslint:enable | ||
const response = processDataPlaneResponse(res, null); | ||
// tslint:disable-next-line:no-magic-numbers | ||
expect(response.statusCode).toEqual(500); | ||
expect(response.body).toEqual({body: null}); | ||
}); | ||
|
||
it('generates data plane response with no httpResponse', () => { | ||
const response = processDataPlaneResponse(null, null); | ||
expect(response.body).toEqual({body: null}); | ||
}); | ||
|
||
it('generates data plane response using device status code', () => { | ||
// tslint:disable | ||
const res: any = { | ||
headers: { | ||
'content-length': '10319', | ||
'content-type': 'application/json; charset=utf-8', | ||
vary: 'Origin', | ||
server: 'Microsoft-HTTPAPI/2.0', | ||
'iothub-errorcode': 'ServerError', | ||
date: 'Thu, 29 Aug 2019 00:49:10 GMT', | ||
connection: 'close', | ||
'x-ms-command-statuscode': '404' | ||
}, | ||
statusCode: 200 | ||
}; | ||
// tslint:enable | ||
const response = processDataPlaneResponse(res, null); | ||
// tslint:disable-next-line:no-magic-numbers | ||
expect(response.statusCode).toEqual(404); | ||
expect(response.body).toEqual({body: null}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/*********************************************************** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License | ||
**********************************************************/ | ||
import express = require('express'); | ||
import request = require('request'); | ||
export const API_VERSION = '2018-06-30'; | ||
const DEVICE_STATUS_HEADER = 'x-ms-command-statuscode'; | ||
const MULTIPLE_CHOICES = 300; | ||
const SUCCESS = 200; | ||
|
||
export const generateDataPlaneRequestBody = (req: express.Request) => { | ||
const headers = { | ||
'Accept': 'application/json', | ||
'Authorization': req.body.sharedAccessSignature, | ||
'Content-Type': 'application/json', | ||
...req.body.headers | ||
}; | ||
if (req.body.etag) { | ||
(headers as any)['If-Match'] = `"${req.body.etag}"`; // tslint:disable-line:no-any | ||
} | ||
|
||
const apiVersion = req.body.apiVersion || API_VERSION; | ||
const queryString = req.body.queryString ? `?${req.body.queryString}&api-version=${apiVersion}` : `?api-version=${apiVersion}`; | ||
|
||
return { | ||
body: req.body.body, | ||
headers, | ||
method: req.body.httpMethod.toUpperCase(), | ||
uri: `https://${req.body.hostName}/${encodeURIComponent(req.body.path)}${queryString}`, | ||
}; | ||
}; | ||
|
||
export const generateDataPlaneResponse = (httpRes: request.Response, body: any, res: express.Response) => { // tslint:disable-line:no-any | ||
const response = processDataPlaneResponse(httpRes, body); | ||
res.status(response.statusCode).send(response.body); | ||
}; | ||
|
||
// tslint:disable-next-line:cyclomatic-complexity | ||
export const processDataPlaneResponse = (httpRes: request.Response, body: any): {body: any, statusCode?: number} => { // tslint:disable-line:no-any | ||
if (httpRes) { | ||
if (httpRes.headers && httpRes.headers[DEVICE_STATUS_HEADER]) { // handles happy failure cases when error code is returned as a header | ||
return { | ||
body: {body: JSON.parse(body)}, | ||
statusCode: parseInt(httpRes.headers[DEVICE_STATUS_HEADER] as string) // tslint:disable-line:radix | ||
}; | ||
} | ||
else { | ||
if (httpRes.statusCode >= SUCCESS && httpRes.statusCode < MULTIPLE_CHOICES) { | ||
return { | ||
body: {body: JSON.parse(body), headers: httpRes.headers}, | ||
statusCode: httpRes.statusCode | ||
}; | ||
} else { | ||
return { | ||
body: {body: JSON.parse(body)}, | ||
statusCode: httpRes.statusCode | ||
}; | ||
} | ||
} | ||
} | ||
else { | ||
return { | ||
body: {body: JSON.parse(body)} | ||
}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters