add server test; bug fix; date-time check (#235)
This commit is contained in:
Родитель
7020135347
Коммит
f78675ca03
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "azure-iot-explorer",
|
||||
"version": "0.10.15",
|
||||
"version": "0.10.16",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "azure-iot-explorer",
|
||||
"version": "0.10.15",
|
||||
"version": "0.10.16",
|
||||
"description": "This project welcomes contributions and suggestions. Most contributions require you to agree to a\r Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us\r the rights to use your contribution. For details, visit https://cla.microsoft.com.",
|
||||
"main": "public/electron.js",
|
||||
"build": {
|
||||
|
|
|
@ -12,6 +12,7 @@ export interface ParsedJsonSchema {
|
|||
enumNames?: string[];
|
||||
format?: string;
|
||||
items?: any; // tslint:disable-line: no-any
|
||||
pattern?: string;
|
||||
properties?: {};
|
||||
required?: string[];
|
||||
title?: string;
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from './selectors';
|
||||
import { getInitialState } from '../api/shared/testHelper';
|
||||
|
||||
describe('getDigitalTwinInterfacePropertiesSelector', () => {
|
||||
describe('getAzureResourceSelector', () => {
|
||||
const state = getInitialState();
|
||||
const hostName = 'testhub.azure-devices.net';
|
||||
state.azureResourceState = Record({
|
||||
|
|
|
@ -82,7 +82,7 @@ describe('parse interface model definition to Json schema', () => {
|
|||
|
||||
interfacePropertyDefinition.schema = 'datetime';
|
||||
expect(parseInterfacePropertyToJsonSchema(interfacePropertyDefinition).type).toEqual('string');
|
||||
expect(parseInterfacePropertyToJsonSchema(interfacePropertyDefinition).format).toEqual('date-time');
|
||||
expect(parseInterfacePropertyToJsonSchema(interfacePropertyDefinition).pattern).toEqual('^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$');
|
||||
|
||||
interfacePropertyDefinition.schema = 'integer';
|
||||
expect(parseInterfacePropertyToJsonSchema(interfacePropertyDefinition).type).toEqual('integer');
|
||||
|
|
|
@ -59,7 +59,7 @@ const parseInterfacePropertyHelper = (property: PropertyContent): ParsedJsonSch
|
|||
case 'datetime':
|
||||
return {
|
||||
description: getDescription(property),
|
||||
format: 'date-time',
|
||||
pattern: '^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$', // regex for ISO 8601
|
||||
title: property.name,
|
||||
type: 'string',
|
||||
};
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/***********************************************************
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License
|
||||
**********************************************************/
|
||||
import 'jest';
|
||||
import * as ServerBase from './serverBase';
|
||||
|
||||
describe('serverBase', () => {
|
||||
const mockRequest = (bodyData?: any) => { // tslint:disable-line:no-any
|
||||
return { body: bodyData } as any; // tslint:disable-line:no-any
|
||||
};
|
||||
|
||||
const mockResponse = () => {
|
||||
const res = {status: undefined, json: undefined, send: undefined};
|
||||
res.status = jest.fn().mockReturnValue(res);
|
||||
res.send = jest.fn().mockReturnValue(res);
|
||||
res.json = jest.fn().mockReturnValue(res);
|
||||
return res as any; // tslint:disable-line:no-any
|
||||
};
|
||||
|
||||
context('handleDataPlanePostRequest', () => {
|
||||
it('returns 400 if body is not provided', async () => {
|
||||
const req = mockRequest();
|
||||
const res = mockResponse();
|
||||
|
||||
await ServerBase.handleDataPlanePostRequest(req, res);
|
||||
expect(res.status).toHaveBeenCalledWith(400); // tslint:disable-line:no-magic-numbers
|
||||
});
|
||||
});
|
||||
|
||||
context('handlhandleCloudToDevicePostRequesteDataPlanePostRequest', () => {
|
||||
it('returns 400 if body is not provided', async () => {
|
||||
const req = mockRequest();
|
||||
const res = mockResponse();
|
||||
|
||||
await ServerBase.handleCloudToDevicePostRequest(req, res);
|
||||
expect(res.status).toHaveBeenCalledWith(400); // tslint:disable-line:no-magic-numbers
|
||||
});
|
||||
});
|
||||
|
||||
context('handleEventHubMonitorPostRequest', () => {
|
||||
it('returns 400 if body is not provided', async () => {
|
||||
const req = mockRequest();
|
||||
const res = mockResponse();
|
||||
|
||||
await ServerBase.handleEventHubMonitorPostRequest(req, res);
|
||||
expect(res.status).toHaveBeenCalledWith(400); // tslint:disable-line:no-magic-numbers
|
||||
});
|
||||
|
||||
it('calls eventHubProvider when body is provided', async () => {
|
||||
const req = mockRequest('testBody');
|
||||
const res = mockResponse();
|
||||
const promise = {then: jest.fn()} as any; // tslint:disable-line:no-any
|
||||
jest.spyOn(ServerBase, 'eventHubProvider').mockReturnValue(promise);
|
||||
|
||||
await ServerBase.handleEventHubMonitorPostRequest(req, res);
|
||||
expect(ServerBase.eventHubProvider).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context('handleEventHubStopPostRequest ', () => {
|
||||
it('returns 400 if body is not provided', async () => {
|
||||
const req = mockRequest();
|
||||
const res = mockResponse();
|
||||
|
||||
await ServerBase.handleEventHubStopPostRequest (req, res);
|
||||
expect(res.status).toHaveBeenCalledWith(400); // tslint:disable-line:no-magic-numbers
|
||||
});
|
||||
|
||||
it('calls stopClient when body is provided', async () => {
|
||||
const req = mockRequest('testBody');
|
||||
const res = mockResponse();
|
||||
const promise = {then: jest.fn()} as any; // tslint:disable-line:no-any
|
||||
jest.spyOn(ServerBase, 'stopClient').mockReturnValue(promise);
|
||||
|
||||
await ServerBase.handleEventHubStopPostRequest(req, res);
|
||||
expect(ServerBase.stopClient).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context('handleModelRepoPostRequest', () => {
|
||||
it('returns 400 if body is not provided', async () => {
|
||||
const req = mockRequest();
|
||||
const res = mockResponse();
|
||||
await ServerBase.handleModelRepoPostRequest(req, res);
|
||||
expect(res.status).toHaveBeenCalledWith(400); // tslint:disable-line:no-magic-numbers
|
||||
});
|
||||
|
||||
it('returns 500 if response is error', async () => {
|
||||
const req = mockRequest('test');
|
||||
const res = mockResponse();
|
||||
await ServerBase.handleModelRepoPostRequest(req, res);
|
||||
expect(res.status).toHaveBeenCalledWith(500); // tslint:disable-line:no-magic-numbers
|
||||
});
|
||||
});
|
||||
|
||||
context('addPropertiesToCloudToDeviceMessage', () => {
|
||||
it('add system properties to message', async () => {
|
||||
const message: any = {properties: new Map()}; // tslint:disable-line:no-any
|
||||
const properties = [
|
||||
{
|
||||
isSystemProperty: true,
|
||||
key: 'ack',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
isSystemProperty: true,
|
||||
key: 'contentType',
|
||||
value: 'json',
|
||||
},
|
||||
{
|
||||
isSystemProperty: true,
|
||||
key: 'correlationId',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
isSystemProperty: true,
|
||||
key: 'contentEncoding',
|
||||
value: '3',
|
||||
},
|
||||
{
|
||||
isSystemProperty: true,
|
||||
key: 'expiryTimeUtc',
|
||||
value: '4',
|
||||
},
|
||||
{
|
||||
isSystemProperty: true,
|
||||
key: 'messageId',
|
||||
value: '5',
|
||||
},
|
||||
{
|
||||
isSystemProperty: true,
|
||||
key: 'lockToken',
|
||||
value: '6',
|
||||
}
|
||||
];
|
||||
ServerBase.addPropertiesToCloudToDeviceMessage(message, properties);
|
||||
expect(message.ack).toEqual('1');
|
||||
expect(message.contentType).toEqual('json');
|
||||
expect(message.correlationId).toEqual('2');
|
||||
expect(message.contentEncoding).toEqual('3');
|
||||
expect(message.expiryTimeUtc).toEqual(4); // tslint:disable-line:no-magic-numbers
|
||||
expect(message.messageId).toEqual('5');
|
||||
expect(message.lockToken).toEqual('6');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -14,7 +14,8 @@ import { generateDataPlaneRequestBody, generateDataPlaneResponse } from './dataP
|
|||
const SERVER_ERROR = 500;
|
||||
const BAD_REQUEST = 400;
|
||||
const SUCCESS = 200;
|
||||
const NOT_FOUND = 400;
|
||||
const NOT_FOUND = 404;
|
||||
const CONFLICT = 409;
|
||||
const SERVER_WAIT = 3000; // how long we'll let the call for eventHub messages run in non-socket
|
||||
const receivers: ReceiveHandler[] = [];
|
||||
const IOTHUB_CONNECTION_DEVICE_ID = 'iothub-connection-device-id';
|
||||
|
@ -55,7 +56,7 @@ export default class ServerBase {
|
|||
}
|
||||
|
||||
const dataPlaneUri = '/api/DataPlane';
|
||||
const handleDataPlanePostRequest = (req: express.Request, res: express.Response) => {
|
||||
export const handleDataPlanePostRequest = (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
if (!req.body) {
|
||||
res.status(BAD_REQUEST).send();
|
||||
|
@ -75,7 +76,7 @@ const handleDataPlanePostRequest = (req: express.Request, res: express.Response)
|
|||
};
|
||||
|
||||
const cloudToDeviceUri = '/api/CloudToDevice';
|
||||
const handleCloudToDevicePostRequest = (req: express.Request, res: express.Response) => {
|
||||
export const handleCloudToDevicePostRequest = (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
if (!req.body) {
|
||||
res.status(BAD_REQUEST).send();
|
||||
|
@ -102,7 +103,7 @@ const handleCloudToDevicePostRequest = (req: express.Request, res: express.Respo
|
|||
};
|
||||
|
||||
const eventHubMonitorUri = '/api/EventHub/monitor';
|
||||
const handleEventHubMonitorPostRequest = (req: express.Request, res: express.Response) => {
|
||||
export const handleEventHubMonitorPostRequest = (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
if (!req.body) {
|
||||
res.status(BAD_REQUEST).send();
|
||||
|
@ -113,7 +114,7 @@ const handleEventHubMonitorPostRequest = (req: express.Request, res: express.Res
|
|||
res.status(SUCCESS).send(result);
|
||||
});
|
||||
} else {
|
||||
res.status(NOT_FOUND).send('Client currently stopping');
|
||||
res.status(CONFLICT).send('Client currently stopping');
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(SERVER_ERROR).send(error);
|
||||
|
@ -121,7 +122,7 @@ const handleEventHubMonitorPostRequest = (req: express.Request, res: express.Res
|
|||
};
|
||||
|
||||
const eventHubStopUri = '/api/EventHub/stop';
|
||||
const handleEventHubStopPostRequest = (req: express.Request, res: express.Response) => {
|
||||
export const handleEventHubStopPostRequest = (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
if (!req.body) {
|
||||
res.status(BAD_REQUEST).send();
|
||||
|
@ -139,7 +140,7 @@ const handleEventHubStopPostRequest = (req: express.Request, res: express.Respon
|
|||
};
|
||||
|
||||
const modelRepoUri = '/api/ModelRepo';
|
||||
const handleModelRepoPostRequest = (req: express.Request, res: express.Response) => {
|
||||
export const handleModelRepoPostRequest = (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
if (!req.body) {
|
||||
res.status(BAD_REQUEST).send();
|
||||
|
@ -165,7 +166,7 @@ const handleModelRepoPostRequest = (req: express.Request, res: express.Response)
|
|||
};
|
||||
|
||||
// tslint:disable-next-line:cyclomatic-complexity
|
||||
const addPropertiesToCloudToDeviceMessage = (message: CloudToDeviceMessage, properties: Array<{key: string, value: string, isSystemProperty: boolean}>) => {
|
||||
export const addPropertiesToCloudToDeviceMessage = (message: CloudToDeviceMessage, properties: Array<{key: string, value: string, isSystemProperty: boolean}>) => {
|
||||
if (!properties || properties.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -176,18 +177,16 @@ const addPropertiesToCloudToDeviceMessage = (message: CloudToDeviceMessage, prop
|
|||
message.ack = property.value;
|
||||
break;
|
||||
case 'contentType':
|
||||
// tslint:disable-next-line:no-any
|
||||
message.contentType = property.value as any;
|
||||
message.contentType = property.value as any; // tslint:disable-line:no-any
|
||||
break;
|
||||
case 'correlationId':
|
||||
message.correlationId = property.value;
|
||||
break;
|
||||
case 'contentEncoding':
|
||||
message.correlationId = property.value;
|
||||
message.contentEncoding = property.value as any; // tslint:disable-line:no-any
|
||||
break;
|
||||
case 'expiryTimeUtc':
|
||||
// tslint:disable-next-line:radix
|
||||
message.expiryTimeUtc = parseInt(property.value);
|
||||
message.expiryTimeUtc = parseInt(property.value); // tslint:disable-line:radix
|
||||
break;
|
||||
case 'messageId':
|
||||
message.messageId = property.value;
|
||||
|
@ -207,7 +206,7 @@ const addPropertiesToCloudToDeviceMessage = (message: CloudToDeviceMessage, prop
|
|||
};
|
||||
|
||||
// tslint:disable-next-line:cyclomatic-complexity
|
||||
const eventHubProvider = async (res: any, body: any) => { // tslint:disable-line: no-any
|
||||
export const eventHubProvider = async (res: any, body: any) => { // tslint:disable-line: no-any
|
||||
try {
|
||||
if (!eventHubClientStopping) {
|
||||
if (!client || connectionString !== body.connectionString) {
|
||||
|
@ -228,7 +227,7 @@ const eventHubProvider = async (res: any, body: any) => { // tslint:disable-lin
|
|||
|
||||
return handleMessages(body.deviceId, client, hubInfo, partitionIds, startTime, !!body.fetchSystemProperties, body.consumerGroup);
|
||||
} else {
|
||||
res.status(NOT_FOUND).send('Client currently stopping');
|
||||
res.status(CONFLICT).send('Client currently stopping');
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(SERVER_ERROR).send(error);
|
||||
|
@ -249,7 +248,7 @@ const stopReceivers = async () => {
|
|||
);
|
||||
};
|
||||
|
||||
const stopClient = async () => {
|
||||
export const stopClient = async () => {
|
||||
return stopReceivers().then(() => {
|
||||
return client && client.close().then(() => {
|
||||
client = null;
|
||||
|
|
Загрузка…
Ссылка в новой задаче