0

I have created a simple Node.js Express service that basically uses child_process.exec to run a command (in this case, running the "nightwatch" command in the command prompt to run Nightwatch.js end to end tests), and then once the Nightwatch tests are done running, then reading the report results of the tests from a specific html file that Nightwatch outputs results to. The Express service then returns the html text to the .NET web app who made the request.

I'm running into an error where the Express service returns a 200 response prematurely after 120000 ms everytime the .net c# webapp makes a request to it.

Any idea why the express service returns a 200 response prematurely? I had thought it was a timeout issue, so I set a web request timeout in the .net web app, but still getting the same problem. Is it a problem with maybe having to set a timeout within the Express service itself?

Express service Code:

var exec = require('child_process').exec;
var fs = require('fs');
var Q = require('Q');

exports.runTests = function(req, res){
  var environment = req.param('environment');
  console.log('current environment to run nightwatch tests: ' + environment);

  executeNightwatchCommand(environment)

  return getReportResults(res).then(function(reportHtmlFormatted){
    console.log('About to send back response of report html.');
    res.send(reportHtmlFormatted);
  });
};

var executeNightwatchCommand = function(environment){
  //var nightwatchDirectory = 'C:/Nightwatch/Brightline.AcceptanceTesting';
  var nightwatchDirectory = 'C:/code/project/brightline/tests/Brightline.AcceptanceTesting';

  if(environment.toLowerCase() == 'local'){
    environment = 'develop';
  }

  var cmd = 'cmd /c "cd /d ' + nightwatchDirectory + ' && nightwatch --env ' + environment + '"';

  console.log("About to run Nightwatch tests.");

  exec(cmd, function(error, stdout, stderr) {          
       if(error){
            console.log("error: " + error);
       }
       // if(stdout){
            // console.log("stdout: " + stdout);
       // }       
       if(stderr){
            console.log("stderr: " + stderr);
       }

       console.log("Finished running Nightwatch tests.");
    });
}


var getReportResults = function(res, deferred){
  var deferred = Q.defer();
  //var reportPath = 'C:/Nightwatch/Brightline.AcceptanceTesting/reports_html/report.html';
  var reportPath = 'C:/code/project/brightline/tests/Brightline.AcceptanceTesting/reports_html/report.html';

  console.log('Setting up filesystem watch for report file: ' + reportPath);

  fs.watch(reportPath, function(){
       fs.readFile(reportPath, 'utf8', function (err,data) {
          console.log('currently reading report file.');

          if (err) {
                console.log("error: " + err);
                deferred.reject(new Error(err));
          }

          //remove style from report html so it doesn't override website styles
          var reportHtml = data;
          var reportHtmlFormatted = reportHtml.split('<style type="text/css">')[0] + reportHtml.split('</style>')[1];
          console.log('About to resolve promise for reading report html.')

          deferred.resolve(reportHtmlFormatted);
      });
  });

  return deferred.promise;
}

.NET C# code that makes the request to the Express service:

string environment = null;

        try
        {
            if (IoC.Settings.CurrentEnvironment == EnvironmentType.PRO)
                environment = "production";
            else if (IoC.Settings.CurrentEnvironment == EnvironmentType.UAT)
                environment = "uat";
            else if (IoC.Settings.CurrentEnvironment == EnvironmentType.DEV)
                environment = "develop";
            else
                environment = "local";


            var buildServerIp = ConfigurationManager.AppSettings["buildServerIp"];
            var nightwatchServicePort = ConfigurationManager.AppSettings["nightwatchServicePort"];
            //var requestUrl = string.Format("http://{0}:{1}/nightwatchTests?environment={2}", buildServerIp, nightwatchServicePort, environment);
            var requestUrl = string.Format("http://{0}:{1}/nightwatchTests?environment={2}", "localhost", nightwatchServicePort, environment);

            var request = WebRequest.Create(requestUrl);

            request.Method = "GET";
            request.Timeout = 1000000000;

            string text;
            var response = (HttpWebResponse)request.GetResponse();

            using (var sr = new StreamReader(response.GetResponseStream()))
            {
                text = sr.ReadToEnd();
            }


            var vm = new NightwatchTestsViewModel();
            vm.html = text;

            return JObject.FromObject(vm);   
        }
        catch (Exception ex)
        {
            IoC.Log.Error("Could not retrieve Nightwatch test results.", ex);
            FlashMessageExtensions.Debug(ex);
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError) { ReasonPhrase = "Error processing request." });
        }
jre247
  • 1,787
  • 5
  • 21
  • 28
  • Is the promise actually resolving? Could it be a different code path returning the 200 response? What kind of results are being returned? Blank? – Chris Anderson Oct 01 '15 at 00:30
  • The promise never gets to resolve, since after about 120 seconds every time the node server responds 200 with a blank response. – jre247 Oct 01 '15 at 15:10
  • update: i created another node service with only code being setTimeout for 121 seconds and then return a response. As expected, the node service returned empty response after 120 seconds. Any idea? – jre247 Oct 01 '15 at 15:37
  • Looks like this SO post addresses your question. http://stackoverflow.com/questions/23925284/how-to-modify-the-nodejs-request-default-timeout-time – Chris Anderson Oct 01 '15 at 16:34
  • it worked!!! I had tried other ways to set the timeout in my node app, but the link you just gave me gave the solution! If you want, you can reply below and I'll mark your answer as accepted. Thanks! – jre247 Oct 01 '15 at 17:38

1 Answers1

1

From this post:

If you're using express, you can use the server.timeout functionality.

var server = app.listen(app.get('port'), function() {
  debug('Express server listening on port ' + server.address().port);
});
server.timeout = 1000; //Timeout requests after 1 second

You should also consider not doing the long request and instead do a start/status pattern. This is much less likely to fail due to network issues.

Chris Anderson
  • 8,305
  • 2
  • 29
  • 37
  • can you link me to an article talking about the start/status pattern? Thanks! – jre247 Oct 01 '15 at 21:06
  • It's better known as building asynchronous APIs. For the life of me, I can't find a blog about it regarding Node. If you're just building this for an internal app, maybe you don't care enough to bother. Essentially, you just call the /start api and it would kick off the Nightwatch Command. The /status api would return the current state of the promise (not finished / finished + results). Your C# code then polls again on a recurring basis. – Chris Anderson Oct 01 '15 at 22:37