Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proxy doesn't know if karma webserver runs on different port than originally configured #1476

Closed
metamatt opened this issue Jun 29, 2015 · 7 comments · May be fixed by Omrisnyk/npm-lockfiles#122 or Omrisnyk/npm-lockfiles#132

Comments

@metamatt
Copy link

I'm using karma to test a project loaded by systemjs. For lack of a better way, my karma config depends heavily on use of proxies to rewrite paths (but I'm proxying back to karma's internal webserver, not a different webserver).

I'm also running these tests via a parallel test runner that runs several copies of karma. The first karma starts up on the port configured in karma.conf.js (9050 for me). The second one gets EADDRINUSE, logs "port 9050 in use", and happily rolls onto port 9051.

The problem is that karma configures the proxy with the port specified via config (thanks to #1007) falling back to default 443/80 if the config doesn't specify. And karma configures the proxy library before it calls listen on its internal webserver, that is, before it discovers the port conflict and starts the webserver on a different port. And when it does discover the port conflict, it never tells the proxy library.

The result in my parallel test runner scenario is this: I start N copies of karma, they start their internal webservers on N different ports starting at 9050, but they've all configured their proxy to proxy to 9050. So all the proxied requests go to the webserver for the first karma instance to start. This actually works out better than you might expect, since they're all serving the same code... until the first karma test passes and exits (the batch tests run in single-run mode), and the rest of the tests keep trying to talk to the webserver that just exited.

This is easy to repro without the parallel scenario; any port conflict will do:

  • take any karma test that has a config which proxies requests back to the internal webserver
  • netcat -lp [the port the karma config uses]
  • run the karma test

You'll see karma itself log "port in use" and increment until it finds an open port, but continue throwing proxied requests at the originally configured port.

A brute force fix for this is to defer evaluation of the proxyConfig port until it's actually needed, by which time karma's listening on the right port. A cleaner fix that doesn't rely on getters would probably have the outer glue code that starts everything wait till the internal webserver owns a port and then tell the proxy code explicitly to use that port. The initialization order and data flow is not very explicit thanks to DI so it's not immediately obvious to me how to accomplish that.

diff --git a/node_modules/karma/lib/middleware/proxy.js b/node_modules/karma/lib/middleware/proxy.js
index e439c52..9485965 100644
--- a/node_modules/karma/lib/middleware/proxy.js
+++ b/node_modules/karma/lib/middleware/proxy.js
@@ -45,7 +45,12 @@ var parseProxyConfig = function(proxies, config) {
     if (!proxyConfig[proxyPath].port) {
       if (!proxyConfig[proxyPath].host) {
         proxyConfig[proxyPath].host = config.hostname;
-        proxyConfig[proxyPath].port = config.port;
+        Object.defineProperty(proxyConfig[proxyPath], 'port', {
+          get: function() {
+            return config.port;
+         },
+        });
       } else {
         proxyConfig[proxyPath].port = proxyConfig[proxyPath].https ? '443' : '80';
       }
@dignifiedquire
Copy link
Member

I would suggest adding an event here https://github.com/karma-runner/karma/blob/canary/lib/server.js#L131 like this:

webServer.on('listening', function () {
  self.emit('webserver_ready')
})

and then use this event on the emitter, to only start the proxy when it's emitted.

@leoselig
Copy link

leoselig commented Apr 7, 2016

Also experienced this just now, took some time to figure out what went wrong, hence my follow-up question: is it possible to tell karma to fail if the port is in use?

@Aaronius
Copy link

@metamatt I know it's been a while, but did you end up using a workaround of some sort for this? Every time I get a failure it takes me a while to remember that it's due to the proxy failing due to the different port. It's a bugger.

@spongyT
Copy link

spongyT commented Feb 27, 2017

Go the same problem and it´s very annoying especially if you run tests with async(), which will fail, when proxied request are denied.
Actually I found a workaround for my problem by injecting some class which don´t rely on proxied request, but a general fix is welcome.

@evanmarshall
Copy link

If you're using gulp (or another task runner) to run karma, you can workaround this by manually finding an open port and then specifying that in the config. What I'm doing

var karmaServer = require('karma').Server;
var portfinder = require('portfinder');
portfinder.basePort = 9876;

portfinder.getPort(function (err, port) {
    console.log('Running karma tests on port: ' + port);
    karmaServer.start({
        /* Other config stuff */
        port: port
    });
});
            

@arunagiritm
Copy link

Check this link to avoid 404 errors on karma using different port

@raspo
Copy link

raspo commented Jan 30, 2018

I encountered this bug when running tests concurrently (using different instances of Karma).

An easy way to reproduce it is to launch your instance of karma (one that uses proxies).
In a different terminal window launch another identical instance.
The second instance will notice that [karma]: Port 9876 in use and use the next available port.
So far so good.
Now kill the first instance. This will interrupt the proxy on port 9876. The second one will start throwing 404 errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants