<commit_before>var Cimpler      = require('../lib/cimpler'),
    fs           = require('fs'),
    path         = require('path'),
    assert       = require('assert'),
    _            = require('underscore'),
    expect       = require("./expect"),
    childProcess = require('child_process'),
    testConfig   = require('./test-config.js'),
    testRepoDir  = testConfig.testRepoDir,
    httpPort     = testConfig.httpPort;

describe("CLI build command", function() {
   var exec = execInDir(testRepoDir);

   it("should add builds based on CWD or commandline params", function(done) {
      var cimpler = new Cimpler({
         plugins: {
            cli: {
            }
         },
         httpPort: httpPort,
         testMode: true  // Don't console.log() anything
      }),
      bin = "../../bin/cimpler -h 127.0.0.1 -p " + httpPort,
      builtBranches  = [],
      expectedBuilds = 2,
      cimplerCalls   = 0,
      consumedBuild  = false,
      expectedBuild = {
         repo:   'http://example.com/repo.git',
         branch: 'master',
         status: 'pending',
         _control: {}
      };

      var check = expect(4, function() {
         cimpler.shutdown();
         assert.deepEqual(builtBranches, ['master', 'test-branch']);
         done();
      });

      cimpler.consumeBuild(function(inBuild, started, finished) {
         started();

         builtBranches.push(inBuild.branch);
         assert.deepEqual(inBuild, expectedBuild);
         // So the next assertion will succeed
         expectedBuild.branch = 'test-branch';
         expectedBuild.buildCommand = 'blah';

         finished();
         check();
      });

      exec(bin, function(stdout) { }, /* expect failure = */ true);

      exec(bin + " build", function(stdout) {
         check();
         exec(bin + " build --branch=test-branch --command='blah'", function(stdout) {
            check();
         });
      });

   });

   /**
    * Because Git doesn't allow adding any files or dirs named .git
    * we can't add the test repo's .git dir directly to the main repo.
    * We must resort to dynamically creating and destroying a
    * "symlink-like" file that points git to a different folder for
    * the actual repo dir.
    *
    * Actual repo dir:        fixtures/repo/git
    * "symlink" to repo dir:  fixtures/repo/.git
    */
   before(function() {
      try {
         fs.writeFileSync(testRepoDir + '.git', "gitdir: ./git");
      } catch (err) {}
   });

   after(function() {
      // Dont' do this, because Travis seems to execute its builds in paralell
      // on the same dir tree. So if one test finishes during a parallel
      // execution of the same test, the parallel test could fail.
      // fs.unlink(testRepoDir + '.git');
   });
});

describe("CLI server command", function() {
   var exec = execInDir(testRepoDir);

   it("takes in the config option", function(done) {
      var configPath = testConfigFile(httpPort);
      var proc = exec("../../bin/cimpler server --config=" + configPath, function(output) {
         var pattern = "Listening on port: " + httpPort;
         assert(output.match(new RegExp(pattern)))
         done();
         clearInterval(killerInterval);
      }, true);
      var killerInterval = setInterval(function() {
         proc.kill();
      }, 1000);
   });
});

describe("CLI status command", function() {
   var exec = execInDir("./");

   it("should print a pretty list of builds", function(done) {
      var cimpler = new Cimpler({
         plugins: {
            'build-status': true
         },
         httpPort: httpPort,
         testMode: true  // Don't console.log() anything
      }),
      bin = __dirname + "/../bin/cimpler -h 127.0.0.1 -p " + httpPort;

      cimpler.addBuild({
         repo:   'http://',
         branch: 'master'
      });
      cimpler.addBuild({
         repo:   'http://',
         branch: 'test-branch'
      });

      var expectedOutputs = [
         "* master\n" +
         "  test-branch\n",

         "* test-branch\n",

         "(no builds in queue)\n"
      ];

      cimpler.consumeBuild(function(inBuild, started, finished) {
         started();
         testNextCommand(finished);
      });

      function testNextCommand(callback) {
         testCommand(bin + " status", expectedOutputs.shift(), function(){
            callback();
            if (expectedOutputs.length == 1) {
               testNextCommand(function() {
                  cimpler.shutdown();
                  done();
               });
            }
         });
      }

      function testCommand(command, expectedOutput, callback) {
         exec(command, function(stdout) {
            assert.equal(stdout, expectedOutput);
            callback();
         });
      }
   });
});

function execInDir(dir) {
   return function exec(cmd, callback, expectFailure) {
      var execOptions = {
         cwd: dir
      };
      return childProcess.exec(cmd, execOptions, function(err, stdout, stderr) {
         if (!expectFailure && err) {
            console.error("Command failed: " + cmd);
            console.log(stdout.toString());
            console.log(stderr.toString());
            process.exit(1);
         } else if (expectFailure && !err) {
            console.error("Command was supposed to fail (but didn't): " + cmd);
            console.log(stdout.toString());
            console.log(stderr.toString());
            process.exit(1);
         }
         callback && callback(stdout.toString() + stderr.toString());
      });
   };
}

function testConfigFile(port) {
   var configPath = path.join(testRepoDir, "./config.temp.js");
   fs.writeFileSync(configPath,
   "module.exports = " + JSON.stringify({
      httpHost: 'localhost',
      httpPort: httpPort,
      plugins: {cli: true}
   }));
   return configPath;
}<commit_msg>Tests: use spawn() in cli test<commit_after>var Cimpler      = require('../lib/cimpler'),
    fs           = require('fs'),
    path         = require('path'),
    assert       = require('assert'),
    _            = require('underscore'),
    expect       = require("./expect"),
    childProcess = require('child_process'),
    testConfig   = require('./test-config.js'),
    testRepoDir  = testConfig.testRepoDir,
    httpPort     = testConfig.httpPort;

describe("CLI build command", function() {
   var exec = execInDir(testRepoDir);

   it("should add builds based on CWD or commandline params", function(done) {
      var cimpler = new Cimpler({
         plugins: {
            cli: {
            }
         },
         httpPort: httpPort,
         testMode: true  // Don't console.log() anything
      }),
      builtBranches  = [],
      expectedBuilds = 2,
      cimplerCalls   = 0,
      consumedBuild  = false,
      expectedBuild = {
         repo:   'http://example.com/repo.git',
         branch: 'master',
         status: 'pending',
         _control: {}
      };

      var bin = "../../bin/cimpler"
      var args = ["-h", "127.0.0.1", "-p", httpPort];

      var check = expect(4, function() {
         cimpler.shutdown();
         assert.deepEqual(builtBranches, ['master', 'test-branch']);
         done();
      });

      cimpler.consumeBuild(function(inBuild, started, finished) {
         started();

         builtBranches.push(inBuild.branch);
         assert.deepEqual(inBuild, expectedBuild);
         // So the next assertion will succeed
         expectedBuild.branch = 'test-branch';
         expectedBuild.buildCommand = 'blah';

         finished();
         check();
      });

      exec(bin, args, function(stdout) { }, /* expect failure = */ true);

      exec(bin, args.concat(["build"]), function(stdout) {
         check();
         exec(bin, args.concat(["build", "--branch=test-branch", "--command=blah"]),
         function(stdout) {
            check();
         });
      });

   });

   /**
    * Because Git doesn't allow adding any files or dirs named .git
    * we can't add the test repo's .git dir directly to the main repo.
    * We must resort to dynamically creating and destroying a
    * "symlink-like" file that points git to a different folder for
    * the actual repo dir.
    *
    * Actual repo dir:        fixtures/repo/git
    * "symlink" to repo dir:  fixtures/repo/.git
    */
   before(function() {
      try {
         fs.writeFileSync(testRepoDir + '.git', "gitdir: ./git");
      } catch (err) {}
   });

   after(function() {
      // Dont' do this, because Travis seems to execute its builds in paralell
      // on the same dir tree. So if one test finishes during a parallel
      // execution of the same test, the parallel test could fail.
      // fs.unlink(testRepoDir + '.git');
   });
});

describe("CLI server command", function() {
   var exec = execInDir(testRepoDir);

   it("takes in the config option", function(done) {
      var configPath = testConfigFile(httpPort);
      var proc = exec(__dirname + "/../bin/cimpler", ["server", "--config=" + configPath],
      function(output) {
         var pattern = "Listening on port: " + httpPort;
         assert(output.match(new RegExp(pattern)));
         done();
         clearInterval(killerInterval);
      }, true);
      var killerInterval = setInterval(function() {
         proc.kill();
      }, 1000);
   });
});

describe("CLI status command", function() {
   var exec = execInDir("./");

   it("should print a pretty list of builds", function(done) {
      var cimpler = new Cimpler({
         plugins: {
            'build-status': true
         },
         httpPort: httpPort,
         testMode: true  // Don't console.log() anything
      });

      var bin = __dirname + "/../bin/cimpler";
      var args = ["-h", "127.0.0.1", "-p", httpPort];

      cimpler.addBuild({
         repo:   'http://',
         branch: 'master'
      });
      cimpler.addBuild({
         repo:   'http://',
         branch: 'test-branch'
      });

      var expectedOutputs = [
         "* master\n" +
         "  test-branch\n",

         "* test-branch\n",

         "(no builds in queue)\n"
      ];

      cimpler.consumeBuild(function(inBuild, started, finished) {
         started();
         testNextCommand(finished);
      });

      function testNextCommand(callback) {
         testCommand(bin, args.concat(["status"]), expectedOutputs.shift(), function(){
            callback();
            if (expectedOutputs.length == 1) {
               testNextCommand(function() {
                  cimpler.shutdown();
                  done();
               });
            }
         });
      }

      function testCommand(command, args, expectedOutput, callback) {
         exec(command, args, function(stdout) {
            assert.equal(stdout, expectedOutput);
            callback();
         });
      }
   });
});

function execInDir(dir) {
   return function exec(cmd, args, callback, expectFailure) {
      var execOptions = {
         cwd: dir
      };
      var output = [];
      var proc = childProcess.spawn(cmd, args, execOptions);

      var collect = function(out) {
         output.push(out);
      };

      proc.stdout.on('data', collect);
      proc.stderr.on('data', collect);
      proc.on('close', function(code, signal) {
         var outputStr = output.join('');
         if (!expectFailure && code != 0) {
            console.error("Command failed: " + cmd);
            console.log(outputStr);
            process.exit(1);
         } else if (expectFailure && code == 0) {
            console.error("Command was supposed to fail (but didn't): " + cmd);
            console.log(outputStr);
            process.exit(1);
         }
         callback && callback(outputStr);
      });
      return proc;
   };
}

function testConfigFile(port) {
   var configPath = path.join(testRepoDir, "./config.temp.js");
   fs.writeFileSync(configPath,
   "module.exports = " + JSON.stringify({
      httpHost: 'localhost',
      httpPort: httpPort,
      plugins: {cli: true}
   }));
   return configPath;
}
{'fraction_non_alphanumeric': 0.1423327215084265, 'fraction_numerical': 0.0038378107792424497, 'mean_word_length': 1.976657561460144, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '183246', 'n_tokens_mistral': 3472, 'n_tokens_neox': 3391, 'n_words': 830}