2013-07-19 10 views
5

Tutaj jest uproszczoną wersją mojego klastra ekspresowe aplikacji:Jak przetestować klastrowaną aplikację Express z aplikacją Mocha?

/index.js

module.exports = process.env.CODE_COV 
    ? require('./lib-cov/app') 
    : require('./lib/app'); 

/lib/app.js

var cluster = require('cluster'), 
    express = require('express'), 
    app = module.exports = express.createServer(); 

if (cluster.isMaster) { 
    // Considering I have 4 cores. 
    for (var i = 0; i < 4; ++i) { 
     cluster.fork(); 
    } 
} else { 
    // do app configurations, then... 

    // Don't listen to this port if the app is required from a test script. 
    if (!module.parent.parent) { 
     app.listen(8080); 
    } 
} 

/test/test1 .js

var app = require('../'); 

app.listen(7777); 

// send requests to app, then assert the response. 

Pytania:

  1. var app = require('../'); nie będzie działać w tym środowisku klastra. Która z aplikacji dla robotników powinna powrócić? Czy powinien zwrócić obiekt klastra zamiast aplikacji Express?
  2. Teraz oczywiście ustawienie portu w skrypcie testowym nie będzie działać. Jak ustawić port w skrypcie testowym do klastra aplikacji?
  3. Jak wysyłać żądania do tej grupy aplikacji?

Jedyne rozwiązanie, jakie mogę wymyślić, to warunkowo wyłączyć funkcję klastrowania i uruchomić tylko jedną aplikację, jeśli aplikacja jest żądana ze skryptu testowego (if (module.parent.parent) ...).

Każdy inny sposób przetestowania klastrowej aplikacji Express z aplikacją Mocha?

Odpowiedz

8

Minęło sporo czasu, odkąd opublikowałem to pytanie. Ponieważ nikt nie odpowiedział, sam odpowiem na to pytanie.

Ciągle /index.js jak to jest:

module.exports = process.env.CODE_COV 
    ? require('./lib-cov/app') 
    : require('./lib/app'); 

W /lib/app.js który rozpoczyna klaster, Mam następujący kod. Krótko mówiąc, uruchamiam klaster tylko w środowisku innym niż testowe. W środowisku testowym klaster nie jest uruchamiany, ale uruchamia się tylko jedna aplikacja/pracownik zdefiniowany w warunku cluster.isMaster && !module.parent.parent.

var cluster = require('cluster'), 
    express = require('express'), 
    app = module.exports = express.createServer(); 

if (cluster.isMaster && !module.parent.parent) { 
    // Considering I have 4 cores. 
    for (var i = 0; i < 4; ++i) { 
     cluster.fork(); 
    } 
} else { 
    // do app configurations, then... 

    // Don't listen to this port if the app is required from a test script. 
    if (!module.parent.parent) { 
     app.listen(8080); 
    } 
} 

W powyższym przypadku !module.parent.parent zostaną ocenione jako prawdziwej obiektu tylko wtedy, gdy aplikacja nie została uruchomiona przez skrypt testu.

  1. module jest obecny /lib/app.js skrypt.
  2. module.parent jest jego skryptem nadrzędnym /index.js.
  3. module.parent.parent jest undefined, jeśli aplikacja została uruchomiona bezpośrednio przez node index.js.
  4. module.parent.parent to skrypt testowy, jeśli aplikacja została uruchomiona za pośrednictwem jednego ze skryptów.

W ten sposób mogę bezpiecznie uruchomić skrypt, w którym mogę ustawić niestandardowy port.

/test/test1.js

var app = require('../'); 

app.listen(7777); 

// send requests to app, then assert the response. 

Jednocześnie, jeśli trzeba, aby uruchomić aplikację w czasie rzeczywistym, nie znaczy do testowania, a następnie uruchomić node index.js i rozpocznie się klaster Aplikacje.

0

Podobało mi się twoje rozwiązanie z powodu jego prostoty, jednak w środowisku takim, jak szkielet MVC dla węzła, możesz skończyć z łańcuchem modułów.parent do 11 razy (poważnie).

Myślę, że lepszym rozwiązaniem byłoby po prostu sprawdzenie, z którym węzłem skryptu zaczęto przetwarzać. Argumenty wiersza polecenia węzła są dostępne w process.argv. Pierwszą pozycją w tej tablicy będzie "węzeł", plik wykonywalny i drugi argument będą ścieżką do pliku, który uruchamia węzeł. W twoim przypadku byłby to index.js.

Więc zamiast sprawdzania

    module.parent.parent 
          ^ ^  
         (app.js) | 
           (index.js) 

Można zrobić coś takiego

var starter = process.argv[1].split(path.sep).pop(); 

Gdzie starter byłby index lub index.js w zależności od tego, co zaczął z serwera. node index.js vs node index

Czek będzie wtedy wyglądać tak:

if (cluster.isMaster && starter === 'index.js') { 
    cluster.fork(); 
} 

Pracował w moim otoczeniu, mam nadzieję, że to pomoże!

+0

Ten rodzaj założeniu wygląda niebezpieczne, bo don” t wiedzieć, jak zachowa się lista argumentów, jeśli na przykład aplikacja zostanie uruchomiona na zawsze lub PM2 jak demony. – Eye

+0

Wiesz, jak zachowa się lista argumentów. [process.argv] (http://nodejs.org/docs/latest/api/process.html#process_process_argv) zawsze będzie zawierał 0: "węzeł" i 1: skrypt przetwarzany przez węzeł. – jbielick

+0

Myślę, że mylisz wątek procesora z procesem podrzędnym węzła. Jeśli korzystasz z monitora demona , takiego jak na zawsze, na zawsze rozpocznie się odpowiedni proces główny, który następnie przekaże różne widżety do uruchomienia aplikacji. Jeśli w nieodłącznym widelcu uruchamia się twoja aplikacja, to nadal działa pod ręką 'node app.js'. Który uruchomiłby proces węzłowy z 'process.argv' jako ['node', 'path/to/app.js']. Jeśli używasz mokka i napisać jednostki testowej, aby zrobić coś takiego 'exec ('węzeł app.js')' The process.argv będzie nadal być '[ 'node', 'ścieżka/do/app.js' ] '. – jbielick

2

Mam dużo prostszy sposób to zrobić

if (process.env.NODE_ENV !== 'test') { 
    if (cluster.isMaster) { 
     var numCPUs = require('os').cpus().length; 
     console.log('total cpu cores on this host: ', numCPUs); 
     for (var i = 0; i < numCPUs; i++) { 
      console.log('forking worker...'); 
      cluster.fork(); 
     } 

     cluster.on('online', function(worker) { 
      console.log('Worker ' + worker.process.pid + ' is online.'); 
     }); 
     cluster.on('exit', function(worker, code, signal) { 
      console.log('worker ' + worker.process.pid + ' died.'); 
     }); 
    } else { 
     console.log('Im a worker'); 
     // application code 
     setupServer() 
    } 
} else { 
    // when running tests 
    setupServer(); 
    } 

Wystarczy upewnić się, aby ustawić env do test podczas uruchamiania testów Ex: NODE_ENV=test grunt test

Powiązane problemy