text: /*
   * Copyright 2016 e-UCM (http://www.e-ucm.es/)
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * This project has received funding from the European Union’s Horizon
   * 2020 research and innovation programme under grant agreement No 644187.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0 (link is external)
   *
   * 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.
   */
  
  'use strict';
  
  var should = require('should'),
      ObjectID = require('mongodb').ObjectId,
      Q = require('q'),
      sessions = require('../../lib/activities');
  
  var idGame = new ObjectID('dummyGameId0'),
      idVersion = new ObjectID('dummyVersId0'),
      idClass = new ObjectID('dummyClasId0'),
      idActivity = new ObjectID('dummyActsId0'),
      idActivity2 = new ObjectID('dummyActsId2'),
      trackingCode = '123',
      trackingCode2 = '456';
  
  module.exports = function (request, db, config) {
  
      /**-------------------------------------------------------------**/
      /**-------------------------------------------------------------**/
      /**                   Test Tracker                              **/
      /**-------------------------------------------------------------**/
      /**-------------------------------------------------------------**/
      describe('Collector tests', function () {
  
          before(function (done) {
              db.collection('games').insert(
                  {
                      _id: idGame,
                      title: 'Dummy',
                      public: true
                  }, db.collection('versions').insert(
                      {
                          _id: idVersion,
                          gameId: idGame
                      }, db.collection('classes').insert(
                          {
                              _id: idClass,
                              name: 'Class',
                              groups: [],
                              groupings: [],
                              participants: {
                                  teachers: ['Teacher1'],
                                  assistants: [],
                                  students: []
                              }
                          }, db.collection('activities').insert(
                              {
                                  _id: idActivity,
                                  trackingCode: trackingCode,
                                  classId: idClass,
                                  gameId: idGame,
                                  versionId: idVersion,
                                  name: 'name',
                                  allowAnonymous: true,
                                  groups: [],
                                  groupings: [],
                                  open: true
                              }, db.collection('activities').insert(
                                  {
                                      _id: idActivity2,
                                      trackingCode: trackingCode2,
                                      classId: idClass,
                                      gameId: idGame,
                                      versionId: idVersion,
                                      name: 'name',
                                      allowAnonymous: false,
                                      groups: [],
                                      groupings: [],
                                      open: true
                                  }, done)
                          )
                      )
                  )
              );
          });
  
          after(function (done) {
              db.collection('games').drop(function () {
                  db.collection('versions').drop(function () {
                      db.collection('sessions').drop(function () {
                          db.db.dropDatabase(done);
                      });
                  });
              });
          });
  
          var starts = 0;
          var ends = 0;
  
  
          it('Testing activity start', function (done) {
              sessions.startTasks = [];
              sessions.endTasks = [];
              sessions.startTasks.push(function () {
                  starts++;
                  return Q.fcall(function () {
                      return true;
                  });
              });
  
              sessions.endTasks.push(function () {
                  ends = 2;
                  return Q.fcall(function () {
                      return true;
                  });
              });
              request.post('/api/activities/' + idActivity + '/event/start')
                  .expect(200)
                  .expect('Content-Type', /json/)
                  .set('X-Gleaner-User', 'Teacher1')
                  .end(function (err, res) {
                      should.not.exist(err);
                      should(res.body).be.Object();
                      should.equal(res.body.gameId, idGame);
                      should.equal(res.body.versionId, idVersion);
                      should(res.body.start).be.String();
                      should.equal(res.body.end, null);
                      done();
                  });
          });
  
          var authToken;
          var playerId;
          var animalName;
          var name = '57345599db69cf4200fa41d971088';
          var event = 'initialized';
          var target = 'testName';
          var timestamp = '2016-05-16T11:48:25Z';
          var type = 'type';
          var statement = {
              id: '19de3bf2-6b7f-4399-a71b-da5f3674c8f8',
              actor: {
                  name: name,
                  account: {
                      homePage: 'http://a2:3000/',
                      name: 'Anonymous'
                  }
              },
              verb: {
                  id: 'http://id.tincanapi.com/verb/' + event
              },
              object: {
                  id: 'http://example.com/games/SuperMarioBros/Screens/' + target,
                  definition: {
                      extensions: {
                          type: 'defType',
                          extensions: {
                              versionId: 'testVersionId',
                              gameplayId: 'testGameplayId'
                          }
                      },
                      type: 'https://rage.e-ucm.es/xapi/seriousgames/activities/' + type
                  }
              },
              result: {
                  extensions: {
                      ext1: '123',
                      '/ext2': '456',
                      'asdasd/asdasd3': 0,
                      '23.423.4756/ext3': '411'
                  }
              },
              timestamp: timestamp
          };
  
          it('Testing the start collector with errored JWT', function (done) {
              request.post('/api/collector/start/' + trackingCode)
                  .expect(400)
                  .expect('Content-Type', /json/)
                  .set('Authorization', 'Non JWT Compliant Format')
                  .end(function (err, res) {
                      should.deepEqual(res.body, {
                          message: 'Authorization header found but the expected format ' +
                          'is \'Bearer JSON Web Token\' obtained by logging in to A2'
                      });
                      done();
                  });
          });
  
          it('Testing the start collector', function (done) {
              request.post('/api/collector/start/' + trackingCode)
                  .expect(200)
                  .expect('Content-Type', /json/)
                  .end(function (err, res) {
                      should(res.body).be.Object();
                      should(res.body.authToken).be.String();
                      should(res.body.objectId).be.String();
                      should(res.body.playerAnimalName).be.String();
                      should.equal(res.body.playerAnimalName, res.body.actor.name);
                      should.equal(res.body.objectId.indexOf('http'), 0);
                      should(res.body.actor).be.Object();
                      should(res.body.actor.name).be.String();
                      should(res.body.actor.account).be.Object();
                      should.equal(res.body.actor.account.name, 'Anonymous');
                      var expectedSession = 1;
                      should.equal(res.body.session, expectedSession);
                      should.equal(res.body.actor.account.homePage, config.a2.a2HomePage);
                      should(res.body.firstSessionStarted).be.a.String();
                      should(res.body.currentSessionStarted).be.a.String();
                      if (expectedSession === 1) {
                          should(res.body.firstSessionStarted).eql(res.body.currentSessionStarted);
                      }
                      authToken = res.body.authToken;
                      playerId = res.body.playerId;
                      animalName = res.body.actor.name;
                      statement.actor = res.body.actor;
                      done();
                  });
          });
  
          var checkConsumerData = function(playerId, versionId, gameplayId, activity, data, convertedTraces) {
              for (var i = 0; i < data.length; ++i) {
                  var extensions = data[i].object.definition.extensions;
                  should(data[i].actor.name).not.eql(playerId);
                  should(data[i].actor.account.name).not.eql(playerId);
                  should.equal(extensions.gameplayId, gameplayId);
                  should.equal(extensions.versionId, versionId);
                  should(extensions.firstSessionStarted).be.a.Date();
                  should(extensions.currentSessionStarted).be.a.Date();
                  should(extensions.session).be.a.Number();
                  if (extensions.session === 1) {
                      should(extensions.firstSessionStarted).eql(extensions.currentSessionStarted);
                  }
  
                  if (activity) {
                      var activityId = activity._id.toString();
                      should.equal(extensions.activityId, activityId);
                      should.equal(convertedTraces[i].activityId, activityId);
                  }
  
                  should.equal(convertedTraces[i].gameplayId, gameplayId);
                  should.equal(convertedTraces[i].versionId, versionId);
                  should(convertedTraces[i].firstSessionStarted).be.a.Date();
                  should(convertedTraces[i].currentSessionStarted).be.a.Date();
                  should(convertedTraces[i].session).be.a.Number();
                  if (convertedTraces[i].session === 1) {
                      should(convertedTraces[i].firstSessionStarted).eql(convertedTraces[i].currentSessionStarted);
                  }
              }
          };
  
          it('Testing collector track', function (done) {
              var dataSource = require('../../lib/traces');
  
              dataSource.clearConsumers();
              dataSource.addConsumer({
                  addTraces: function (playerId, versionId, gameplayId, activity, data, convertedTraces) {
                      checkConsumerData(playerId, versionId, gameplayId, activity, data, convertedTraces);
                  }
              });
              request.post('/api/collector/track')
                  .expect(200)
                  .expect('Content-Type', /json/)
                  .set('Authorization', authToken)
                  .send([statement])
                  .end(function (err, res) {
                      should(res.body).eql({message: 'Success.'});
                      done();
                  });
          });
  
          it('Testing collector track fails ith the same status and message as the consumer', function (done) {
              var dataSource = require('../../lib/traces');
  
              var status = 700;
              var message = 'Provoked error!';
  
              dataSource.clearConsumers();
              dataSource.addConsumer({
                  addTraces: function (playerId, versionId, gameplayId, activity, data, convertedTraces) {
                      checkConsumerData(playerId, versionId, gameplayId, activity, data, convertedTraces);
                      var deferred = Q.defer();
                      setTimeout(function () {
                          var err = new Error(message);
                          err.status = status;
                          deferred.reject(err);
                      }, 50);
                      return deferred.promise;
                  }
              });
              request.post('/api/collector/track')
                  .expect(status)
                  .expect('Content-Type', /json/)
                  .set('Authorization', authToken)
                  .send([statement])
                  .end(function (err, res) {
                      should(res.body).eql({message: message});
                      done();
                  });
          });
  
  
          it('Testing collector track fails status 400 if consumer throws a non status error', function (done) {
              var dataSource = require('../../lib/traces');
              var message = 'Provoked error!';
              dataSource.clearConsumers();
              dataSource.addConsumer({
                  addTraces: function (playerId, versionId, gameplayId, activity, data, convertedTraces) {
                      checkConsumerData(playerId, versionId, gameplayId, activity, data, convertedTraces);
                      var deferred = Q.defer();
                      setTimeout(function () {
                          var err = new Error(message);
                          deferred.reject(err);
                      }, 50);
                      return deferred.promise;
                  }
              });
              request.post('/api/collector/track')
                  .expect(400)
                  .expect('Content-Type', /json/)
                  .set('Authorization', authToken)
                  .send([statement])
                  .end(function (err, res) {
                      should(res.body).eql({message: message});
                      done();
                  });
          });
  
          it('Testing collector track fails for a non array object ', function (done) {
              var dataSource = require('../../lib/traces');
              dataSource.clearConsumers();
  
              request.post('/api/collector/track')
                  .expect(400)
                  .expect('Content-Type', /json/)
                  .set('Authorization', authToken)
                  .send({})
                  .end(function (err, res) {
                      should(res.body).eql({message: 'Statements must be an array!'});
                      request.post('/api/collector/track')
                          .expect(400)
                          .expect('Content-Type', /json/)
                          .set('Authorization', authToken)
                          .send(null)
                          .end(function (err, res) {
                              should(res.body).eql({message: 'Statements must be an array!'});
                              request.post('/api/collector/track')
                                  .expect(400)
                                  .expect('Content-Type', /json/)
                                  .set('Authorization', authToken)
                                  .send(undefined)
                                  .end(function (err, res) {
                                      should(res.body).eql({message: 'Statements must be an array!'});
                                      request.post('/api/collector/track')
                                          .expect(400)
                                          .expect('Content-Type', /json/)
                                          .set('Authorization', authToken)
                                          .send()
                                          .end(function (err, res) {
                                              should(res.body).eql({message: 'Statements must be an array!'});
                                              done();
                                          });
                                  });
                          });
                  });
          });
  
          it('Testing collector track fails for a wrongly formatter statement (verb error) ', function (done) {
              var dataSource = require('../../lib/traces');
              dataSource.clearConsumers();
  
              var errStatement = {};
              request.post('/api/collector/track')
                  .expect(400)
                  .expect('Content-Type', /json/)
                  .set('Authorization', authToken)
                  .send([errStatement])
                  .end(function (err, res) {
                      should(res.body).eql({
                          message: 'Statement ' + errStatement +
                          ' doesn\'t have a valid format. Error: Actor is missing for statement, ' + errStatement
                      });
  
  
                      var noVerbStatement = {
                          object: {
                              objectType: 'Activity',
                              id: 'http://example.adlnet.gov/xapi/example/simplestatement',
                              definition: {
                                  name: {
                                      'en-US': 'simple statement'
                                  },
                                  description: {
                                      'en-US': 'A simple Experience API statement. Note that the LRS does not need to have any prior ' +
                                      'information about the Actor (learner), the verb, or the Activity/object.'
                                  }
                              }
                          }
                      };
  
                      request.post('/api/collector/track')
                          .expect(400)
                          .expect('Content-Type', /json/)
                          .set('Authorization', authToken)
                          .send([noVerbStatement])
                          .end(function (err, res) {
                              should(res.body).eql({
                                  message: 'Statement ' + noVerbStatement +
                                  ' doesn\'t have a valid format. Error: Actor is missing for statement, ' + noVerbStatement
                              });
  
  
                              var noVerbIdStatement = {
                                  verb: {
                                      display: {
                                          'en-US': 'created'
                                      }
                                  },
                                  object: {
                                      objectType: 'Activity',
                                      id: 'http://example.adlnet.gov/xapi/example/simplestatement',
                                      definition: {
                                          name: {
                                              'en-US': 'simple statement'
                                          },
                                          description: {
                                              'en-US': 'A simple Experience API statement. Note that the LRS does not need to have any prior ' +
                                              'information about the Actor (learner), the verb, or the Activity/object.'
                                          }
                                      }
                                  }
                              };
  
                              request.post('/api/collector/track')
                                  .expect(400)
                                  .expect('Content-Type', /json/)
                                  .set('Authorization', authToken)
                                  .send([noVerbIdStatement])
                                  .end(function (err, res) {
                                      should(res.body).eql({message: 'Statement ' + noVerbIdStatement +
                                          ' doesn\'t have a valid format. Error: Actor is missing for statement, ' + noVerbIdStatement});
  
                                      var noUrlVerbIdStatement = {
                                          verb: {
                                              id: 'nourlId',
                                              display: {
                                                  'en-US': 'created'
                                              }
                                          },
                                          object: {
                                              objectType: 'Activity',
                                              id: 'http://example.adlnet.gov/xapi/example/simplestatement',
                                              definition: {
                                                  name: {
                                                      'en-US': 'simple statement'
                                                  },
                                                  description: {
                                                      'en-US': 'A simple Experience API statement. Note that the LRS does not need to have any prior ' +
                                                      'information about the Actor (learner), the verb, or the Activity/object.'
                                                  }
                                              }
                                          }
                                      };
  
                                      request.post('/api/collector/track')
                                          .expect(400)
                                          .expect('Content-Type', /json/)
                                          .set('Authorization', authToken)
                                          .send([noUrlVerbIdStatement])
                                          .end(function (err, res) {
                                              should(res.body).eql({
                                                  message: 'Statement ' + noUrlVerbIdStatement +
                                                  ' doesn\'t have a valid format. Error: Actor is missing for statement, ' + noUrlVerbIdStatement
                                              });
  
  
                                              done();
                                          });
                                  });
                          });
                  });
          });
  
  
          it('Testing collector track fails for a wrongly formatter statement (object error) ', function (done) {
              var dataSource = require('../../lib/traces');
              dataSource.clearConsumers();
  
              var noObjectErrStatement = {
                  verb: {
                      id: 'http://adlnet.gov/expapi/verbs/created',
                      display: {
                          'en-US': 'created'
                      }
                  }
              };
              request.post('/api/collector/track')
                  .expect(400)
                  .expect('Content-Type', /json/)
                  .set('Authorization', authToken)
                  .send([noObjectErrStatement])
                  .end(function (err, res) {
                      should(res.body).eql({
                          message: 'Statement ' + noObjectErrStatement +
                          ' doesn\'t have a valid format. Error: Actor is missing for statement, ' + noObjectErrStatement
                      });
  
  
                      var noObjectIdStatement = {
                          verb: {
                              id: 'http://adlnet.gov/expapi/verbs/created',
                              display: {
                                  'en-US': 'created'
                              }
                          },
                          object: {
                              objectType: 'Activity',
                              definition: {
                                  name: {
                                      'en-US': 'simple statement'
                                  },
                                  description: {
                                      'en-US': 'A simple Experience API statement. Note that the LRS does not need to have any prior ' +
                                      'information about the Actor (learner), the verb, or the Activity/object.'
                                  }
                              }
                          }
                      };
  
                      request.post('/api/collector/track')
                          .expect(400)
                          .expect('Content-Type', /json/)
                          .set('Authorization', authToken)
                          .send([noObjectIdStatement])
                          .end(function (err, res) {
                              should(res.body).eql({
                                  message: 'Statement ' + noObjectIdStatement +
                                  ' doesn\'t have a valid format. Error: Actor is missing for statement, ' + noObjectIdStatement
                              });
  
  
                              var noUrlOjbectIdStatement = {
                                  verb: {
                                      id: 'http://adlnet.gov/expapi/verbs/created',
                                      display: {
                                          'en-US': 'created'
                                      }
                                  },
                                  object: {
                                      objectType: 'Activity',
                                      id: 'simplestatement',
                                      definition: {
                                          name: {
                                              'en-US': 'simple statement'
                                          },
                                          description: {
                                              'en-US': 'A simple Experience API statement. Note that the LRS does not need to have any prior ' +
                                              'information about the Actor (learner), the verb, or the Activity/object.'
                                          }
                                      }
                                  }
                              };
  
                              request.post('/api/collector/track')
                                  .expect(400)
                                  .expect('Content-Type', /json/)
                                  .set('Authorization', authToken)
                                  .send([noUrlOjbectIdStatement])
                                  .end(function (err, res) {
                                      should(res.body).eql({
                                          message: 'Statement ' + noUrlOjbectIdStatement +
                                          ' doesn\'t have a valid format. Error: Actor is missing for statement, ' + noUrlOjbectIdStatement
                                      });
                                      done();
                                  });
                          });
                  });
          });
  
          it('Testing collector track fails ' +
              'with the same status and message as the consumer that fails first', function (done) {
              var dataSource = require('../../lib/traces');
  
              var status1 = 700;
              var message1 = 'Provoked error 1!';
  
              var status2 = 900;
              var message2 = 'Provoked error 2!';
              var consumer2Called = false;
              var consumer2Failed = false;
  
              var firstConsumer = {
                  addTraces: function (playerId, versionId, gameplayId, activity, data, convertedTraces) {
                      checkConsumerData(playerId, versionId, gameplayId, activity, data, convertedTraces);
                      consumer2Called = true;
                      var deferred = Q.defer();
                      setTimeout(function () {
                          var err = new Error(message1);
                          err.status = status1;
                          consumer2Failed = true;
                          deferred.reject(err);
                      }, 200);
                      return deferred.promise;
                  }
              };
              var secondConsumer = {
                  addTraces: function (playerId, versionId, gameplayId, activity, data, convertedTraces) {
                      checkConsumerData(playerId, versionId, gameplayId, activity, data, convertedTraces);
                      var deferred = Q.defer();
                      setTimeout(function () {
                          var err = new Error(message2);
                          err.status = status2;
                          deferred.reject(err);
                      }, 50);
                      return deferred.promise;
                  }
              };
  
              dataSource.clearConsumers();
              dataSource.addConsumer(firstConsumer);
              dataSource.addConsumer(secondConsumer);
              request.post('/api/collector/track')
                  .expect(status2)
                  .expect('Content-Type', /json/)
                  .set('Authorization', authToken)
                  .send([statement, statement])
                  .end(function (err, res) {
                      should(res.body).eql({message: message2});
                      should(consumer2Called).eql(true);
                      should(consumer2Failed).eql(false);
                      done();
                  });
          });
  
          // Test collector sessions count
  
          var startNewSession = function (expectedSession, playerIdentifier, checkAnimalName, type) {
              request.post('/api/collector/start/' + trackingCode)
                  .expect(200)
                  .expect('Content-Type', /json/)
                  .send({
                      anonymous: playerIdentifier
                  })
                  .end(function (err, res) {
                      should(res.body).be.Object();
                      should(res.body.authToken).be.String();
                      should(res.body.objectId).be.String();
                      should(res.body.playerAnimalName).be.String();
                      should.equal(res.body.playerAnimalName, res.body.actor.name);
                      should.equal(res.body.objectId.indexOf('http'), 0);
                      should(res.body.actor).be.Object();
                      if (checkAnimalName) {
                          should.equal(res.body.actor.name, checkAnimalName);
                      } else {
                          should(res.body.actor.name).be.String();
                      }
                      should(res.body.actor.account).be.Object();
                      if (!type) {
                          type = 'Anonymous';
                      }
                      should.equal(res.body.actor.account.name, type);
                      should.equal(res.body.session, expectedSession);
                      should.equal(res.body.actor.account.homePage, config.a2.a2HomePage);
                      authToken = res.body.authToken;
                      should(res.body.firstSessionStarted).be.a.String();
                      should(res.body.currentSessionStarted).be.a.String();
                      if (expectedSession === 1) {
                          should(res.body.firstSessionStarted).eql(res.body.currentSessionStarted);
                      }
                      statement.actor = res.body.actor;
  
                      var dataSource = require('../../lib/traces');
                      dataSource.clearConsumers();
                      var checkSessionCount = {
                          addTraces: function (playerId, versionId, gameplayId, activity, data, convertedTraces) {
                              checkConsumerData(playerId, versionId, gameplayId, activity, data, convertedTraces);
  
                              should(convertedTraces[0].session).eql(expectedSession);
  
                              var deferred = Q.defer();
                              setTimeout(function () {
                                  deferred.resolve();
                              }, 100);
                              return deferred.promise;
                          }
                      };
                      dataSource.addConsumer(checkSessionCount);
                      var numStatementsSent = 5;
                      var checkSuccess = function (err, res) {
                          should(res.body).eql({
                              message: 'Success.'
                          });
                      };
                      for (var i = 0; i < numStatementsSent; ++i) {
                          request.post('/api/collector/track')
                              .expect(200)
                              .expect('Content-Type', /json/)
                              .set('Authorization', authToken)
                              .send([statement, statement, statement])
                              .end(checkSuccess);
                      }
                  });
          };
  
          it('Testing the start collector with an anonymous user', function (done) {
              startNewSession(2, playerId, animalName);
              setTimeout(function () {
                  startNewSession(3, playerId, animalName);
              }, 300);
              setTimeout(function () {
                  startNewSession(1, '');
              }, 600);
              setTimeout(function () {
                  startNewSession(4, playerId, animalName);
              }, 900);
              setTimeout(function () {
                  startNewSession(1, '');
              }, 1200);
              setTimeout(function () {
                  startNewSession(5, playerId, animalName);
              }, 1500);
              setTimeout(done, 1800);
          });
  
          // Test Non anonymous users login and session count
  
          var startNewIdentifiedSession = function (expectedSession, playerIdentifier) {
              request.post('/api/collector/start/' + trackingCode)
                  .expect(200)
                  .expect('Content-Type', /json/)
                  .set('x-gleaner-user', playerIdentifier)
                  .set('Authorization', 'Bearer 1234')
                  .end(function (err, res) {
                      should.not.exist(err);
                      should(res.body).be.Object();
                      should(res.body.authToken).be.String();
                      should(res.body.objectId).be.String();
                      should.equal(res.body.objectId.indexOf('http'), 0);
                      should(res.body.actor).be.Object();
                      should(res.body.playerAnimalName).be.String();
                      should(res.body.playerAnimalName).not.equal(res.body.actor.account.name);
                      should(res.body.actor.account).be.Object();
                      // Identified actor has actor.account.name === actor.name
                      should.equal(res.body.actor.account.name, res.body.actor.name);
                      should.equal(res.body.actor.account.name, playerIdentifier);
                      should.equal(res.body.session, expectedSession);
                      should.equal(res.body.actor.account.homePage, config.a2.a2HomePage);
                      authToken = res.body.authToken;
                      should(res.body.firstSessionStarted).be.a.String();
                      should(res.body.currentSessionStarted).be.a.String();
                      if (expectedSession === 1) {
                          should(res.body.firstSessionStarted).eql(res.body.currentSessionStarted);
                      }
                      statement.actor = res.body.actor;
  
                      var dataSource = require('../../lib/traces');
                      dataSource.clearConsumers();
                      var checkSessionCount = {
                          addTraces: function (playerId, versionId, gameplayId, activity, data, convertedTraces) {
                              checkConsumerData(playerId, versionId, gameplayId, activity, data, convertedTraces);
  
                              should(convertedTraces[0].session).eql(expectedSession);
                              var deferred = Q.defer();
                              setTimeout(function () {
                                  deferred.resolve();
                              }, 100);
                              return deferred.promise;
                          }
                      };
                      dataSource.addConsumer(checkSessionCount);
                      var numStatementsSent = 5;
                      var checkSuccess = function (err, res) {
                          should(res.body).eql({
                              message: 'Success.'
                          });
                      };
                      for (var i = 0; i < numStatementsSent; ++i) {
                          request.post('/api/collector/track')
                              .expect(200)
                              .expect('Content-Type', /json/)
                              .set('Authorization', authToken)
                              .send([statement])
                              .end(checkSuccess);
                      }
                  });
          };
  
          it('Testing the start collector with an identified user', function (done) {
              startNewIdentifiedSession(1, 'dan');
              setTimeout(function () {
                  startNewIdentifiedSession(2, 'dan');
              }, 300);
              setTimeout(function () {
                  startNewSession(1, '');
              }, 600);
              setTimeout(function () {
                  startNewIdentifiedSession(3, 'dan');
              }, 900);
              setTimeout(function () {
                  startNewSession(6, playerId, animalName);
              }, 1200);
              setTimeout(function () {
                  startNewIdentifiedSession(4, 'dan');
              }, 1500);
              setTimeout(done, 1800);
          });
  
          it('Should fail to start a session with a non participant username', function (done) {
              request.post('/api/collector/start/' + trackingCode2)
                  .expect(401)
                  .expect('Content-Type', /json/)
                  .set('x-gleaner-user', 'AnyUser')
                  .set('Authorization', 'Bearer 1234')
                  .end(function (err, res) {
                      should.not.exist(err);
                      should(res).be.Object();
                      done();
                  });
          });
  
          it('Should fail to start an anonymous session with a non existant "anonymous" playerId', function (done) {
              var nonExistantAnonymousPlayerId = 'nonExistantPlayerId';
              request.post('/api/collector/start/' + trackingCode)
                  .expect(404)
                  .expect('Content-Type', /json/)
                  .send({
                      anonymous: nonExistantAnonymousPlayerId
                  })
                  .end(function (err, res) {
  
                      should.deepEqual(res.body, {
                          message: 'No anonymous player found with id ' + nonExistantAnonymousPlayerId +
                          '. Start a new anonymous session without providing any body in this request.'
                      });
                      done();
                  });
          });
  
          it('Testing the end collector', function (done) {
              request.post('/api/activities/' + idActivity + '/event/end')
                  .expect(200)
                  .set('X-Gleaner-User', 'Teacher1')
                  .end(function (err, res) {
                      should.not.exist(err);
                      should(res).be.Object();
                      done();
                  });
          });
      });
  };
  