UNPKG

node-nlp

Version:

Library for NLU (Natural Language Understanding) done in Node.js

317 lines (289 loc) 13 kB
const assert = require('assert'); const { ActivityTypes } = require('../'); function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } function createActivities(conversationId, ts, count = 5) { var activities = []; for (let i = 1; i <= count; i++) { activities.push({ type: ActivityTypes.Message, timestamp: ts, id: uuid(), text: i.toString(), channelId: 'test', from: { id: `User${i}` }, conversation: { id: conversationId }, recipient: { id: 'Bot1', name: '2' }, serviceUrl: 'http://foo.com/api/messages' }); ts = new Date(ts.getTime() + 60000); activities.push({ type: ActivityTypes.Message, timestamp: ts, id: uuid(), text: i.toString(), channelId: 'test', from: { id: 'Bot1', name: '2' }, conversation: { id: conversationId }, recipient: { id: `User${i}` }, serviceUrl: 'http://foo.com/api/messages' }); ts = new Date(ts.getTime() + 60000); } return activities; } function group(array, size) { return array.reduce((acc, x, i) => { if (i % size) { acc[acc.length - 1].push(x); } else { acc.push([x]); } return acc; }, []); } function promiseSeq(promiseFuncArray) { return promiseFuncArray.reduce((chain, promiseFunc) => { return chain.then(chainResult => promiseFunc().then(currentResult => [ ...chainResult, currentResult ] ) ); }, Promise.resolve([])); } function promiseParallel(promiseFuncArray) { return Promise.all(promiseFuncArray.map(promiseFunc => promiseFunc())); } function resolvePromises(promiseFuncArray, useParallel = true) { return useParallel ? promiseParallel(promiseFuncArray) : promiseSeq(promiseFuncArray); } function dateSorter(a, b) { return a.timestamp.getTime() - b.timestamp.getTime(); } exports._badArgs = function _badArgs(store) { var assertPromise = (promiseFunc, errMessage) => new Promise((resolve, reject) => { try { promiseFunc().then(() => reject(errMessage)) } catch (error) { resolve('expected error') } }); return Promise.all([ assertPromise( () => store.logActivity(null), 'logActivity should have thrown error about missing activity' ), assertPromise( () => store.getTranscriptActivities(null, null), 'getTranscriptActivities should have thrown error about missing channelId' ), assertPromise( () => store.getTranscriptActivities('foo', null), 'getTranscriptActivities should have thrown error about missing conversationId' ), assertPromise( () => store.listTranscripts(null), 'listTranscripts should have thrown error about missing channelId' ), assertPromise( () => store.deleteTranscript(null, null), 'deleteTranscript should have thrown error about missing channelId' ), assertPromise( () => store.deleteTranscript('foo', null), 'deleteTranscript should have thrown error about missing conversationId' ) ]); } exports._logActivity = function _logActivity(store) { var conversationId = '_logActivity'; var date = new Date(); var activity = createActivities(conversationId, date, 1).pop(); return store.logActivity(activity) .then(() => store.getTranscriptActivities('test', conversationId)) .then((result) => { assert.equal(result.items.length, 1); assert.equal(JSON.stringify(result.items[0]), JSON.stringify(activity)); }); } exports._logMultipleActivities = function _logMultipleActivities(store, useParallel = true) { var conversationId = '_logMultipleActivities'; var start = new Date(); var activities = createActivities(conversationId, start); // log activities var writes = activities.map(a => () => store.logActivity(a)); // wait for all logs return resolvePromises(writes, useParallel).then(() => { // group the different queries into promises return Promise.all([ // make sure other channels and conversations don't return results store.getTranscriptActivities('bogus', conversationId).then(pagedResult => { assert(!pagedResult.continuationToken); assert.equal(pagedResult.items.length, 0); }), // make sure other channels and conversations don't return results store.getTranscriptActivities('test', 'bogus').then(pagedResult => { assert(!pagedResult.continuationToken); assert.equal(pagedResult.items.length, 0); }), // make sure all created activities where persisted store.getTranscriptActivities('test', conversationId).then(pagedResult => { assert(!pagedResult.continuationToken); assert.equal(pagedResult.items.length, activities.length); // assert all are equal assert.equal( JSON.stringify(pagedResult.items.sort(dateSorter)), JSON.stringify(activities) ); }), // assert half page, get activities +5 minutes store.getTranscriptActivities('test', conversationId, null, new Date(start.getTime() + 60000 * 5)).then(pagedResult => { assert.equal(activities.length / 2, pagedResult.items.length); var expected = activities.slice(5); assert.equal( JSON.stringify(pagedResult.items.sort(dateSorter)), JSON.stringify(expected)); }) ]); }); } exports._deleteTranscript = function _deleteTranscript(store, useParallel = true) { var conversationId = '_deleteConversation'; var conversationId2 = '_deleteConversation2'; var start = new Date(); var activities = createActivities(conversationId, start); var activities2 = createActivities(conversationId2, start); // log all activities var writes = activities.concat(activities2) .map(a => () => store.logActivity(a)); // wait for all writes return resolvePromises(writes, useParallel).then(() => { return Promise.all([ // test A store.getTranscriptActivities('test', conversationId).then(pagedResult => { assert.equal(pagedResult.items.length, activities.length); // delete! store.deleteTranscript('test', conversationId).then(() => { return Promise.all([ // check deleted store.getTranscriptActivities('test', conversationId).then(pagedResult => { assert.equal(pagedResult.items.length, 0); }), // check second transcript still exists store.getTranscriptActivities('test', conversationId2).then(pagedResult => { assert.equal(pagedResult.items.length, activities2.length); }) ]) }) }), // test B store.getTranscriptActivities('test', conversationId2).then(pagedResult => { assert.equal(pagedResult.items.length, activities2.length); }) ]); }); } exports._getTranscriptActivities = function _getTranscriptActivities(store, useParallel = true) { return new Promise((resolve, reject) => { var conversationId = '_getTranscriptActivitiesPaging'; var date = new Date(); var activities = createActivities(conversationId, date, 50); // log in parallel batches of 10 var groups = group(activities, 10); return promiseSeq(groups.map(group => () => resolvePromises(group.map(item => () => store.logActivity(item)), useParallel))) .then(async () => { var actualPageSize = 0; var pagedResult = {}; var seen = []; do { pagedResult = await store.getTranscriptActivities('test', conversationId, pagedResult.continuationToken); assert(pagedResult); assert(pagedResult.items); if (!actualPageSize) { actualPageSize = pagedResult.items.length; } else if (actualPageSize === pagedResult.items.length) { assert(pagedResult.continuationToken) } pagedResult.items.forEach(item => { assert(!seen.includes(item.id)); seen.push(item.id); }); } while (pagedResult.continuationToken); assert.equal(seen.length, activities.length); activities.forEach(activity => assert(seen.includes(activity.id))); resolve(); }).catch(error => reject(error)); }); } exports._getTranscriptActivitiesStartDate = function _getTranscriptActivitiesStartDate(store, useParallel = true) { return new Promise((resolve, reject) => { var conversationId = '_getTranscriptActivitiesStartDate'; var date = new Date(); var activities = createActivities(conversationId, date, 50); // log in parallel batches of 10 var groups = group(activities, 10); return promiseSeq(groups.map(group => () => resolvePromises(group.map(item => () => store.logActivity(item)), useParallel))) .then(async () => { var actualPageSize = 0; var pagedResult = {}; var seen = []; var referenceDate = new Date(date.getTime() + (50 * 60 * 1000)); do { pagedResult = await store.getTranscriptActivities('test', conversationId, pagedResult.continuationToken, referenceDate); assert(pagedResult); assert(pagedResult.items); if (!actualPageSize) { actualPageSize = pagedResult.items.length; } else if (actualPageSize === pagedResult.items.length) { assert(pagedResult.continuationToken) } pagedResult.items.forEach(item => { assert(!seen.includes(item.id)); seen.push(item.id); }); } while (pagedResult.continuationToken); assert.equal(seen.length, activities.length / 2); activities.filter(a => a.timestamp.getTime() >= referenceDate.getTime()).forEach(activity => assert(seen.includes(activity.id))); activities.filter(a => a.timestamp.getTime() < referenceDate.getTime()).forEach(activity => assert(!seen.includes(activity.id))); resolve(); }).catch(error => reject(error)); }); } exports._listTranscripts = function _listTranscripts(store, useParallel = true) { return new Promise((resolve, reject) => { var conversationIds = []; var start = new Date(); for (let i = 1; i <= 100; i++) { conversationIds.push(`_ListConversations${i}`) } var activities = [].concat(...conversationIds.map(cId => createActivities(cId, start, 1))); // log in parallel batches of 10 var groups = group(activities, 10); return promiseSeq(groups.map(group => () => resolvePromises(group.map(item => () => store.logActivity(item)), useParallel))) .then(async () => { var actualPageSize = 0; var pagedResult = {}; var seen = []; do { pagedResult = await store.listTranscripts('test', pagedResult.continuationToken); assert(pagedResult); assert(pagedResult.items); if (!actualPageSize) { actualPageSize = pagedResult.items.length; } else if (actualPageSize === pagedResult.items.length) { assert(pagedResult.continuationToken) } pagedResult.items.forEach(item => { assert(!seen.includes(item.id)); if (item.id.startsWith('_ListConversations')) { seen.push(item.id); } }); } while (pagedResult.continuationToken); assert.equal(seen.length, conversationIds.length); conversationIds.forEach(cId => assert(seen.includes(cId))); resolve(); }).catch(error => reject(error)); }); }