Browse Source

Fix tests beforeEach. Added WebSocket server test

rigwild 1 year ago
parent
commit
372e1889b3

+ 4 - 0
server/database/controllers/Data.js

@@ -5,6 +5,10 @@ import { dbLogger, TEST_MODE } from '../../../config'
 import { formatLog } from '../../functions'
 
 export default class Data {
+  static get Model() {
+    return DataModel
+  }
+
   static log(data) {
     if (!TEST_MODE) dbLogger.info(formatLog(data))
   }

+ 3 - 2
server/webSocket/index.js

@@ -16,8 +16,9 @@ import messageHandler from './messageHandler'
  * @returns {ErrorLogger} the actual error logger
  */
 export const errorHandler = ws => err => {
-  ws.send(err.message)
-  if (!TEST_MODE) wsLogger.error(formatError(err))
+  const errStr = formatError(err)
+  ws.send(errStr)
+  if (!TEST_MODE) wsLogger.error(errStr)
 }
 
 /**

+ 21 - 25
test/api/_test_functions.js

@@ -16,11 +16,6 @@ export const testDir = path.resolve(__dirname, '..')
 // Pretty-print a JSON object
 export const json = obj => 'JSON DATA : ' + (JSON.stringify(obj, null, 2) || obj)
 
-/**
- * @typedef PluginConfig
- * @property {boolean} [webSocket=false] should the server start with a WebSocket server
- * @property {boolean} [database=false] should the server start with a WebSocket server
- */
 /**
  * Open an Express server not listening to any port.
  * The server serves images in `test/images`, all api routes and
@@ -28,14 +23,11 @@ export const json = obj => 'JSON DATA : ' + (JSON.stringify(obj, null, 2) || obj
  *
  * Using `request` (supertest) on this object will start the server
  * on an ephemeral port.
+ *
  * @param {PluginConfig} plugins plugins that should be loaded with the server
  * @returns {object} an Express server
  */
-const serve = async (plugins = { webSocket: false, database: false }) => {
-  // Connect to db
-  if (plugins && plugins.database) await connectDb()
-
-  // Open a HTTP server
+export const getHttpServer = () => {
   const app = express()
   app.use(imageServedUrl, serveStatic(imagesPath))
   app.use(apiPrefix, routes)
@@ -45,22 +37,26 @@ const serve = async (plugins = { webSocket: false, database: false }) => {
       data: err.data || undefined
     })
   })
-
-  // Open a WebSocket server
-  if (plugins && plugins.webSocket) {
-    const wss = new WebSocket.Server({ server: app })
-    wss.on('error', err => {
-      throw err
-    })
-    wss.on('connection', ws => {
-      ws.on('message', data => wsMessageHandler(ws)(data).catch(wsErrorHandler(ws)))
-      ws.on('error', wsErrorHandler(ws))
-    })
-  }
-
   return app
 }
 
-// Pass a server to test context
-export const getTestServer = async (t, plugins) => (t.context.server = await serve(plugins))
+/**
+ * Open a WebSocket server on top of a HTTP server
+ *
+ * @param {object} httpServer a HTTP server instance (ie. Express server object)
+ * @returns {object} a WebSocket server instance
+ */
+export const getWebSocketServer = httpServer => {
+  const wss = new WebSocket.Server({ server: httpServer })
+  wss.on('error', err => {
+    throw err
+  })
+  wss.on('connection', ws => {
+    ws.on('message', data => wsMessageHandler(ws)(data).catch(wsErrorHandler(ws)))
+    ws.on('error', wsErrorHandler(ws))
+  })
+  return wss
+}
 
+/** Connect to the database */
+export { connectDb }

+ 85 - 9
test/api/databaseWebSocket.js

@@ -2,29 +2,105 @@
 
 import test from 'ava'
 import WebSocket from 'ws'
-import request from 'supertest'
-import { json, getTestServer } from './_test_functions'
+import { json, getHttpServer, getWebSocketServer, connectDb } from './_test_functions'
 import DataController from '../../server/database/controllers/Data'
 
-// Database testing
+// Database and WebSocket testing
 
 // Before all tests, connect to the database
-test.beforeEach(t => getTestServer(t, { database: true, webSocket: true }))
+test.beforeEach(async t => (t.context.server = await getHttpServer()))
 
 test('Check database is working', async t => {
-  await request(t.context.server)
+  // Connect to database
+  await connectDb()
 
-  const testData = { test_database: 'add', test_database_obj: { msg: 'Hello world' } }
+  // Add the document
+  const testData = { AUTOMATED_TEST_DB: true, TEST_DATABASE_OBJ: { msg: 'add' } }
   const doc = await DataController.add(testData)
   t.deepEqual(doc.data, testData, json(doc))
 
+  // Find the document
   const findDoc = await DataController.find(doc.id)
   t.deepEqual(findDoc.data, testData, json(findDoc))
 
-  testData.test_database = 'updated'
-  const updateTo = { newObject: 'test', newProperties: { test: true } }
+  // Update the document
+  testData.TEST_DATABASE_OBJ.msg = 'updated'
+  const updateTo = { AUTOMATED_TEST_DB: true, newObject: 'test', newProperties: { test: true } }
   const docUpdated = await DataController.update(doc.id, updateTo)
   t.deepEqual(docUpdated.data, updateTo, json(docUpdated))
 
-  t.notThrowsAsync(await DataController.del(doc.id))
+  // Delete the added document
+  await t.notThrowsAsync(DataController.del(doc.id))
+})
+
+test('Check WebSocket server is working', async t => {
+  // Connect to database
+  await connectDb()
+
+  // Start the server and get its ephemeral port
+  const server = t.context.server.listen(0)
+  const { port } = server.address()
+
+  // Start the WebSocket server
+  getWebSocketServer(server)
+
+  t.timeout(15000)
+  t.plan(11)
+
+  // Start the WebSocket client
+  const ws = new WebSocket(`ws://localhost:${port}`)
+  await new Promise((resolve, reject) => {
+    let sent = 0
+    let received = 0
+    ws.on('open', async () => {
+      // Send data on connect
+      ws.send(JSON.stringify({ AUTOMATED_TEST_WS: true, TEST_OBJECT: { msg: 'open' } }))
+      t.pass()
+      sent++
+    })
+    ws.on('message', async receivedData => {
+      received++
+      if (sent === 1) {
+        // Send data on receive
+        t.is('ok', receivedData, json(receivedData))
+        ws.send(JSON.stringify({ AUTOMATED_TEST_WS: true, TEST_OBJECT: { msg: 'message' } }))
+        t.pass()
+        sent++
+      }
+      else if (sent === 2) {
+        // Send invalid JSON data
+        t.is('ok', receivedData, json(receivedData))
+        ws.send('Not a valid JSON string')
+        t.pass()
+        sent++
+      }
+      else if (sent === 3) {
+        // Received error from server, check it is valid JSON
+        let obj = null
+        t.notThrows(() => {
+          try {
+            obj = JSON.parse(receivedData)
+          }
+          catch (err) {
+            throw new Error('Not valid JSON')
+          }
+        })
+        t.truthy(obj, json(receivedData))
+        t.is(obj.log.error, 'Invalid JSON data.', json(obj))
+        t.truthy(obj.log.stack, json(obj))
+        t.is(sent, received)
+        resolve()
+      }
+    })
+    ws.on('error', async err => {
+      // Unknown WebSocket error
+      t.fail(json(err.message))
+      reject(err)
+    })
+  })
+
+  // Delete every collected data during test
+  const db = DataController.Model
+  const found = await db.remove({ 'data.AUTOMATED_TEST_WS': true })
+  t.true(found.deletedCount >= 2)
 })

+ 2 - 2
test/api/getImage.js

@@ -3,12 +3,12 @@
 import test from 'ava'
 import request from 'supertest'
 import { apiPrefix, imageServedUrl } from '../../config'
-import { json, getTestServer } from './_test_functions'
+import { json, getHttpServer } from './_test_functions'
 
 // ROUTE /getImage
 
 // Before each tests, start a server
-test.beforeEach(getTestServer)
+test.beforeEach(async t => (t.context.server = await getHttpServer()))
 
 test('GET /getImage', async t => {
   const res = await request(t.context.server)

+ 2 - 2
test/api/getImageExtracts.js

@@ -6,12 +6,12 @@ import sharp from 'sharp'
 import fs from 'fs-extra'
 import path from 'path'
 import { apiPrefix, imageServedUrl, imagesPath } from '../../config'
-import { json, getTestServer } from './_test_functions'
+import { json, getHttpServer } from './_test_functions'
 
 // ROUTE /getImageExtracts
 
 // Before each tests, start a server
-test.beforeEach(getTestServer)
+test.beforeEach(async t => (t.context.server = await getHttpServer()))
 
 test('GET /getImageExtracts', async t => {
   const res = await request(t.context.server)

+ 2 - 2
test/api/listScenes.js

@@ -3,12 +3,12 @@
 import test from 'ava'
 import request from 'supertest'
 import { apiPrefix } from '../../config'
-import { json, getTestServer } from './_test_functions'
+import { json, getHttpServer } from './_test_functions'
 
 // ROUTE /listScenes
 
 // Before each tests, start a server
-test.beforeEach(getTestServer)
+test.beforeEach(async t => (t.context.server = await getHttpServer()))
 
 test('GET /listScenes', async t => {
   const res = await request(t.context.server)

+ 2 - 2
test/api/listScenesQualities.js

@@ -3,12 +3,12 @@
 import test from 'ava'
 import request from 'supertest'
 import { apiPrefix } from '../../config'
-import { json, getTestServer } from './_test_functions'
+import { json, getHttpServer } from './_test_functions'
 
 // ROUTE /listSceneQualities
 
 // Before each tests, start a server
-test.beforeEach(getTestServer)
+test.beforeEach(async t => (t.context.server = await getHttpServer()))
 
 test('GET /listSceneQualities', async t => {
   const res = await request(t.context.server)