Как запустить / закрыть http-сервер как дочерний процесс - PullRequest
0 голосов
/ 17 октября 2019

У нас есть приложение, взаимодействующее с (Node.js) HTTP-сервером. Чтобы проверить вызовы API, мы создали тестовый HTTP-сервер, который отлично работает с приложением. Все вызовы, которые мы выполняем, ожидаются из приложения.

В последнее время мы тратим время, пытаясь автоматизировать тестирование этих вызовов API. Мы разработали одну стратегию:

  1. автоматический запуск тестового HTTP-сервера;
  2. выполнение вызовов на него;
  3. закрытие тестового HTTP-сервера после теста.

Вот как написан наш первый тест:

var serverHandler = require('../../server/serverHandler.js');

describe('Test the test server', function() {
  beforeEach(async () => {
    serverHandler.start(500, 'index.js'); // index.js: the HTTP test server.
                                          // 500: 500 ms of latency to mimic a slow response.

    result = await serverHandler.isRunning();
    expect(result).toEqual(true);
  });

  afterEach(async () => {
    serverHandler.kill();

    result = await serverHandler.isRunning();
    expect(result).toEqual(false);
  });

  test('Server is killed', async () => {
    // We could have more complex test logic here...
    serverHandler.kill();

    try {
      result = await serverHandler.isRunning();
      expect(result).toEqual(false);
    } catch (error) {
      expect(error).toEqual({
        error: 'server is running',
      });
    }
  });
});

Где serverHandler выглядит следующим образом:

const spawn = require('child_process').spawn;
const isReachable = require('is-reachable');

var child = null;

exports.start = (latency, path) => {
  child = spawn('node', [path, latency]);
};

exports.kill = () => {
  child.kill();
};

exports.isRunning = async () => {
  return await isReachable('http://localhost:8080');
};

Как выКак видите, пока мы только пытаемся заставить шаги 1 и 3 работать, прежде чем добавлять тестовую логику. К сожалению, это не так. Когда я запускаю этот тест, я получаю следующий вывод:

  ● Test the test server › Server is killed

    expect(received).toEqual(expected) // deep equality

    Expected: true
    Received: false

      14 | 
      15 |     result = await serverHandler.isRunning();
    > 16 |     expect(result).toEqual(true);
         |                    ^
      17 |   });
      18 | 
      19 |   afterEach(async () => {

      at toEqual (__tests__/integration/serverIntegrationExample.test.js:16:20)
      at tryCatch (node_modules/regenerator-runtime/runtime.js:45:40)
      at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:271:22)
      at Generator.prototype.(anonymous function) [as next] (node_modules/regenerator-runtime/runtime.js:97:21)
      at tryCatch (node_modules/regenerator-runtime/runtime.js:45:40)
      at invoke (node_modules/regenerator-runtime/runtime.js:135:20)
      at node_modules/regenerator-runtime/runtime.js:145:13
      at tryCallOne (node_modules/promise/lib/core.js:37:12)
      at node_modules/promise/lib/core.js:123:15
      at flush (node_modules/asap/raw.js:50:29)

Похоже, сервер фактически никогда не запускается. Я знаю, что тестовый сервер работает хорошо, потому что все вызовы успешно выполняются в приложении. Я обнаружил различные источники, говорящие о похожих проблемах, но большинство из них, похоже, либо тупиковые, либо используют непереносимые функции ОС, что для нас неприемлемо (я получаю этот вывод из Ubuntu).

В чем (с) проблема (ы) в этом коде и как мне этого добиться? Также обратите внимание, что это мой первый проект Node.js, поэтому любые конструктивные советы по коду будут приняты с благодарностью.

EDIT

Вот код для index.js:

const Express = require('express');
const multer = require('multer');
const bodyParser = require('body-parser');
const fs = require('fs');

const labelListMock = require('./mockData');

const uploadDirectory = './images';

const app = Express();
app.use(bodyParser.json());

const Storage = multer.diskStorage({
  destination(req, file, callback) {
    callback(null, uploadDirectory);
  },
  filename(req, file, callback) {
    callback(null, `${file.fieldname}_${Date.now()}_${file.originalname}`);
  },
});

const upload = multer({storage: Storage});

app.get('/', (req, res) => {
  res.status(200).send('You can post to /DispatchData.');
});


var latency = process.argv[2];

if (isNaN(latency)) {
  latency = 0;
}

app.use(function(req, res, next) {
  setTimeout(next, latency);
});


app.get('/RetrieveTypes', (req, res) => {
  res.status(200).json(labelListMock);
});

app.post(
  '/DispatchData',
  checkUploadPath,
  upload.single('photo'),
  (req, res, next) => {
    console.log('file', req.file);
    console.log('body', req.body);

    res.status(200).json({
      message: 'success!',
      fileName: req.file.originalname,
      category: 'buildAILabel',
    });
  },
);

module.exports = app.listen(8080, () => {
  console.log(
    'Mock server running on http://localhost:8080 (or http:://10.0.2.2:8080 if using an emulator.)',
  );
});


function checkUploadPath(req, res, next) {
  fs.exists(uploadDirectory, function(exists) {
    if (exists) {
      next();
    } else {
      fs.mkdir(uploadDirectory, function(err) {
        if (err) {
          console.log('Error in folder creation');
          next();
        }
        next();
      });
    }
  });
}
...