Jak programowo zamknąć wystąpienie ExpressJS w celu przetestowania?

106

Próbuję dowiedzieć się, jak wyłączyć wystąpienie Express. Zasadniczo chcę mieć odwrotność .listen(port)połączenia - jak sprawić, aby serwer Express ZATRZYMAŁ nasłuchiwanie, zwolnił port i zamknął czysto?

Wiem, że może to być dziwne zapytanie, więc oto kontekst; może jest inny sposób podejścia do tego i myślę o tym w niewłaściwy sposób. Próbuję skonfigurować środowisko testowe dla mojej aplikacji socket.io/nodejs. Jest to aplikacja jednostronicowa, więc w moich skryptach testowych (używam Mocha, ale to nie ma znaczenia) Chcę móc uruchomić serwer, przeprowadzić testy, a następnie wyłączyć serwer. Mogę obejść ten problem, zakładając, że albo serwer jest włączony przed rozpoczęciem testu, albo przez jeden z testów uruchamiający serwer i każdy kolejny test zakłada, że ​​jest włączony, ale to naprawdę bałagan. Zdecydowanie wolałbym, aby każdy plik testowy uruchamiał instancję serwera z odpowiednimi ustawieniami, a następnie zamykał ją po zakończeniu testów. Oznacza to, że nie ma żadnych dziwnych zależności od uruchomienia testu i wszystko jest czyste. Oznacza to również, że mogę przeprowadzić testy uruchamiania / zamykania.

Masz jakąś radę, jak to zrobić? Myślałem o ręcznym uruchamianiu wyjątków, aby go wyłączyć, ale wydaje się to kłopotliwe. Przeszukałem dokumenty i źródła Express, ale nie mogę znaleźć żadnej metody, która wyłączyłaby serwer. Może być coś do tego w socket.io, ale ponieważ serwer gniazd jest właśnie podłączony do serwera Express, myślę, że musi to się wydarzyć w warstwie ekspresowej.

drewww
źródło

Odpowiedzi:

156

Sytuacja się zmieniła, ponieważ serwer ekspresowy nie dziedziczy już po serwerze HTTP węzła. Na szczęście app.listen zwraca instancję serwera.

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};
Rich Apodaca
źródło
23
W przypadku testów Mocha, które wymagają ('app'), rozszerzam na obiekt aplikacji: app.server = app.listen (3000); więc później mogę powiedzieć: var app = require ('./ app'); app.server.close ();
Jack Chi,
2
podczas testowania serwera odwiedź github.com/visionmedia/supertest , pozwoli ci to przetestować bez uruchamiania rzeczywistego serwera
Lukas Liesis
Sugerowałbym również przekazanie gotowego wywołania zwrotnego do, server.close()jeśli dzwonisz z poziomu hooka.
Ullauri
Uwaga: istnieje duża różnica między „app”, która jest instancją Express Application, a wartością zwracaną przez „app.listen”, który jest podstawową natywną instancją serwera HTTP, która ma metodę „close”. @JackChi wspomniał o tym powyżej.
ajxs
Czy to nie powoduje problemów z otwartymi gniazdami klienta, które są pozostawione otwarte?
Cameron Tacklind
18

Użyj app.close(). Pełny przykład:

var app = require('express').createServer();
app.get('/', function(req, res){
  res.send('hello world');
});
app.get('/quit', function(req,res) {
  res.send('closing..');
  app.close();
});
app.listen(3000);

Wywołaj app.close()wewnątrz wywołania zwrotnego po zakończeniu testów. Pamiętaj jednak, że proces nadal działa (chociaż już nie nasłuchuje).

Jeśli po tym musisz zakończyć proces, zadzwoń process.exit(0).

Spinki do mankietów:

app.close: http://nodejs.org/docs/latest/api/http.html#server.close (to samo dotyczy)

process.exit: http://nodejs.org/docs/latest/api/process.html#process.exit

Srijan Choudhary
źródło
1
Idealnie, dokładnie to, czego szukałem. Wydaje mi się, że nie znalazłem tego w Express, ponieważ rozszerzali główny serwer http węzła, czego nie do końca rozumiałem. Dzięki!
drewww
Dzięki, Srijan, to też mi pomogło
Adam Hopkinson
Czy to nadal prawda? express.createServer jest oznaczony jako przestarzały i wyświetla błąd informujący, że aplikacja nie dziedziczy już z serwera
http.js
4
To nie jest ważne od czasu ekspresowego 3.
gprasant
4
Ujawnienie adresu URL w celu zamknięcia serwera takiego jak ten nie jest dobrym pomysłem IMHO.
shime
2

Wiele razy odpowiadałem na różne warianty „jak zakończyć działanie serwera HTTP” kanały wsparcia. Niestety nie mogłem polecić żadnej z istniejących bibliotek, ponieważ w jakiś sposób im brakuje . Od tego czasu stworzyłem pakiet, który (jak sądzę) obsługuje wszystkie spodziewane przypadki płynnego zakończenia serwera HTTP.

https://github.com/gajus/http-terminator

Główną zaletą terminatora http :

  • nie naprawia małpy API Node.js.
  • natychmiast niszczy wszystkie gniazda bez dołączonego żądania HTTP
  • pozwala na bezpieczne przekroczenie limitu czasu do gniazd z trwającymi żądaniami HTTP
  • prawidłowo obsługuje połączenia HTTPS
  • informuje połączenia za pomocą funkcji keep-alive, że serwer jest zamykany, ustawiając nagłówek connection: close
  • nie kończy procesu Node.js.

Użycie z Express.js:

import express from 'express';
import {
  createHttpTerminator,
} from 'http-terminator';

const app = express();

const server = app.listen();

const httpTerminator = createHttpTerminator({
  server,
});

await httpTerminator.terminate();

Gajus
źródło
0
//... some stuff 

var server = app.listen(3000);
server.close();
аlex dykyі
źródło
-1

Możesz to łatwo zrobić, pisząc skrypt bash, aby uruchomić serwer, uruchomić testy i zatrzymać serwer. Ma to tę zaletę, że pozwala na alias do tego skryptu w celu szybkiego i łatwego uruchamiania wszystkich testów.

Używam takich skryptów do całego procesu ciągłego wdrażania. Aby uzyskać więcej informacji na ten temat, należy zapoznać się z przepływem pracy Jona Rohana Dead Simple Git .

Josh Smith
źródło
2
To zadziała, ale wolałbym rozwiązanie bez bash, jeśli to możliwe. Może to głupia preferencja, ale chciałbym uruchamiać / zatrzymywać serwer z kontekstu testowego, ponieważ ułatwia to pisanie testów specyficznych dla konfiguracji serwera + testów uruchamiania / zamykania. Ponadto nie wprowadza konieczności uruchamiania testów związanych z serwerem za pomocą oddzielnego skryptu.
drewww
Dlaczego piszesz testy specyficzne dla środowiska? Może się mylę, ale wydaje mi się to złą praktyką. Postarałbym się pozostać agnostykiem środowiskowym podczas testowania, ponieważ chciałbyś, aby testy działały w całym zespole, niezależnie od środowiska programistycznego.
Josh Smith
Nie robię tu nic specyficznego dla środowiska, nie sądzę. Będzie kilka różnych opcji uruchamiania serwera (takich jak odczyt opcji konfiguracyjnych z pliku, ładowanie stanu z magazynu danych itp.), Które byłoby fajnie przetestować w tej samej strukturze, w której testuję wszystko inne. Chciałbym również przeprowadzić testy, które na przykład zamkną serwer, przywróć go ponownie i upewnij się, że nie stracił stanu w trakcie. To łatwiejsze, jeśli mogę to zrobić programowo z węzła, niż testowanie kodu również w bashu.
drewww
Nie umieściłbyś kodu testowego w samym bashu. Po prostu uruchomisz serwer i uruchomisz testy ze skryptu, tak jak zrobiłbyś to sam w linii poleceń. Nie ma tam żadnej specjalnej magii.
Josh Smith