<commit_before>/**
 * Copyright 2014 Skytap Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var path             = require('path'),
    fs               = require('fs'),
    cluster          = require('cluster'),
    child_process    = require('child_process'),
    EventEmitter     = require('events').EventEmitter,
    Promise          = require('bluebird'),
    _                = require('underscore'),
    portfinder       = require('portfinder'),
    glob             = require('glob'),
    extend           = require('extend'),
    CucumberReporter = require('./reporters/cucumber_reporter'),
    MochaReporter    = require('./reporters/mocha_reporter'),
    ServerInstance   = require('./server_instance');

module.exports = Functional = {

  MAX_SERVERS         : 2,

  TEST_DIRECTORY      : 'test/functional/',

  TYPE_CUCUMBER       : 'cucumber',

  TYPE_MOCHA          : 'mocha',

  servers             : [],

  serversDone         : 0,

  eventMediator       : null,

  tests               : [],

  testsCount          : 0,

  finishedSuitesCount : 0,

  finishedSuites      : [],

  hasFailingTest      : false,

  ////////////////////////////////////////////////////////////////////////////
  // Public methods /////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////

  /**
   * Functional.start(options) -> Promise
   * - options (Object)
   **/
  start : function (options) {
    var self = this;

    if (options == null) {
      options = {};
    }

    this.options = extend({
      requestedPorts : 0,
      type           : this.TYPE_MOCHA
    }, options);

    this.eventMediator = new EventEmitter();

    this.eventMediator.on('bail', this._bail.bind(this));

    switch (this.options.type) {
      case this.TYPE_CUCUMBER:
        this.reporter = new CucumberReporter(this.eventMediator);
        break;
      case this.TYPE_MOCHA:
      default:
        this.reporter = new MochaReporter(this.eventMediator);
    }

    this._setColors();

    this._handleSignals();

    cluster.setupMaster({
      exec   : path.join(__dirname, 'fork_worker.js'),
      silent : false
    });

    this._loadTestSuites()
      .then(function (tests) {
        return self._processTests(tests);
      })
      .then(function(){
        self.eventMediator.emit('start');
        return self._getOpenPorts(self.options.requestedPorts);
      })
      .then(function (ports) {
        for (var i=0; i<self._getMaxServers(); i++) {
          var portBlockSize  = self.options.requestedPorts + 1,
              portBlockStart = i * portBlockSize,
              port           = ports[portBlockStart],
              requestedPorts = ports.slice(portBlockStart+1, portBlockStart+portBlockSize);

          self._createServerWorker(port, requestedPorts);
        }
      })
      .done();
  },

  ////////////////////////////////////////////////////////////////////////////
  // Psuedo-private methods /////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////

  /**
   * Functional._bail()
   *
   * Bail out of running any more tests when we encounter a failure.
   **/
  _bail : function () {
    this.hasFailingTest = true;
    this.tests          = [];
  },

  /**
   * Functional._checkMissingSuites()
   *
   * See if we failed to run any test suites.
   **/
  _checkMissingSuites : function () {
    var missedSuites = _.difference(this.originalTests, this.finishedSuites);

    if (missedSuites.length > 0 && !this.hasFailingTest) {
      console.log("\nError! Expected to run " + this.originalTests.length +<commit_msg>feature: Add ability to accept batch parameters for tests<commit_after>/**
 * Copyright 2014 Skytap Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var path             = require('path'),
    fs               = require('fs'),
    cluster          = require('cluster'),
    child_process    = require('child_process'),
    EventEmitter     = require('events').EventEmitter,
    Promise          = require('bluebird'),
    _                = require('underscore'),
    portfinder       = require('portfinder'),
    glob             = require('glob'),
    extend           = require('extend'),
    CucumberReporter = require('./reporters/cucumber_reporter'),
    MochaReporter    = require('./reporters/mocha_reporter'),
    ServerInstance   = require('./server_instance');

module.exports = Functional = {

  MAX_SERVERS         : 2,

  TEST_DIRECTORY      : 'test/functional/',

  TYPE_CUCUMBER       : 'cucumber',

  TYPE_MOCHA          : 'mocha',

  servers             : [],

  serversDone         : 0,

  eventMediator       : null,

  tests               : [],

  testsCount          : 0,

  finishedSuitesCount : 0,

  finishedSuites      : [],

  hasFailingTest      : false,

  ////////////////////////////////////////////////////////////////////////////
  // Public methods /////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////

  /**
   * Functional.start(options) -> Promise
   * - options (Object)
   **/
  start : function (options) {
    var self = this;

    if (options == null) {
      options = {};
    }

    this.options = extend({
      requestedPorts : 0,
      type           : this.TYPE_MOCHA
    }, options);

    this.eventMediator = new EventEmitter();

    this.eventMediator.on('bail', this._bail.bind(this));

    switch (this.options.type) {
      case this.TYPE_CUCUMBER:
        this.reporter = new CucumberReporter(this.eventMediator);
        break;
      case this.TYPE_MOCHA:
      default:
        this.reporter = new MochaReporter(this.eventMediator);
    }

    this._setColors();

    this._handleSignals();

    cluster.setupMaster({
      exec   : path.join(__dirname, 'fork_worker.js'),
      silent : false
    });

    this._loadTestSuites()
      .then(function (tests) {
        return self._processTests(self._batchTests(tests));
      })
      .then(function(){
        self.eventMediator.emit('start');
        return self._getOpenPorts(self.options.requestedPorts);
      })
      .then(function (ports) {
        for (var i=0; i<self._getMaxServers(); i++) {
          var portBlockSize  = self.options.requestedPorts + 1,
              portBlockStart = i * portBlockSize,
              port           = ports[portBlockStart],
              requestedPorts = ports.slice(portBlockStart+1, portBlockStart+portBlockSize);

          self._createServerWorker(port, requestedPorts);
        }
      })
      .done();
  },

  ////////////////////////////////////////////////////////////////////////////
  // Psuedo-private methods /////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////

  /**
   * Functional._batchTests(testPaths)
   * - testPaths (Array)
   *
   * Return sub array of testPaths.
   **/
  _batchTests : function (testPaths) {
    var batchCount = this.options.batchCount
    var currentBatch = this.options.currentBatch
    if (!batchCount && !currentBatch) {
      return testPaths
    }
    var batchSize = Math.floor(testPaths.length / batchCount)
    var end = (batchSize * currentBatch)
    var start = (end - batchSize)
    if (batchCount === currentBatch) {
      end = undefined
    }
    return testPaths.slice(start, end)
  },

  /**
   * Functional._bail()
   *
   * Bail out of running any more tests when we encounter a failure.
   **/
  _bail : function () {
    this.hasFailingTest = true;
    this.tests          = [];
  },

  /**
   * Functional._checkMissingSuites()
   *
   * See if we failed to run any test suites.
   **/
  _checkMissingSuites : function () {
    var missedSuites = _.difference(this.originalTests, this.finishedSuites);

    if (missedSuites.length > 0 && !this.hasFailingTest) {
      console.log("\nError! Expected to run " + this.originalTests.length +
{'fraction_non_alphanumeric': 0.1960588951621831, 'fraction_numerical': 0.0037639765304992804, 'mean_word_length': 1.7350893127459885, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, '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': '7345349', 'n_tokens_mistral': 2494, 'n_tokens_neox': 2393, 'n_words': 566}