text: /**
   * Copyright (c) 2016 - 2018 Sqreen. All Rights Reserved.
   * Please refer to our terms for more information: https://www.sqreen.io/terms.html
   */
  'use strict';
  
  // needs to run first.
  
  const Code = require('code');
  const Lab = require('lab');
  const lab = exports.lab = Lab.script();
  
  const describe = lab.describe;
  const it = lab.it;
  const expect = Code.expect;
  
  const SDK = require('../../lib/sdk');
  const Director = require('../../lib/instrumentation/sqreenDirector');
  const Record = require('../../lib/instrumentation/record');
  let NS = require('../../lib/instrumentation/hooks/util').getNS();
  
  const Express = require('express');
  const Request = require('supertest');
  
  describe('SDK', () => {
  
      describe('auth', () => {
  
          describe('_getPatchedMethod', () => {
  
              it('should return a patchedMethod', { plan: 2 },  (done) => {
  
                  const method = SDK._getPatchedMethod('aaa', 'bbb');
  
                  expect(method).to.be.a.function();
                  expect(Director._getInstrumented()['sqreen-sdk']['']['']['bbb:aaa']).to.be.an.array();
                  done();
              });
          });
  
          describe('auth_track', () => {
  
              it('should update the user in the RR yes', { plan: 1 }, (done) => {
  
                  const req = { aaa: 'aaa' };
                  const record = Record.lazyGet(req);
  
                  SDK.auth_track(req, true, { username: 'hello' });
  
                  expect(record.user).to.equal({ username: 'hello' });
                  done();
              });
  
              it('should update the user in the RR yes', { plan: 0 }, (done) => {
  
                  SDK.auth_track(null, true, { username: 'hello' });
                  SDK.auth_track(undefined, true, { username: 'hello' });
  
                  done();
              });
  
              it('should trigger the callback on the auth sdk', { plan: 2 }, (done) => {
  
                  Director._getInstrumented()['sqreen-sdk']['']['']['auth:auth_track'][0]({
                      preCbs: [
                          {
                              method: function (args) {
  
                                  expect(args[0]).to.be.true();
                                  expect(args[1]).to.equal({ a: 1 });
                                  done();
                              }
                          }
                      ]
                  });
  
                  SDK.auth_track(true, { a: 1 });
              });
  
              it('should trigger the callback on the auth sdk', { plan: 2 }, (done) => {
  
                  Director._getInstrumented()['sqreen-sdk']['']['']['auth:auth_track'][0]({
                      preCbs: [
                          {
                              method: function (args) {
  
                                  expect(args[0]).to.be.false();
                                  expect(args[1]).to.not.exist();
                                  done();
                              }
                          }
                      ]
                  });
  
                  SDK.auth_track('');
              });
          });
  
          describe('signup_track', () => {
  
              it('should trigger the callback on the auth sdk', { plan: 1 }, (done) => {
  
                  Director._getInstrumented()['sqreen-sdk']['']['']['signup:signup_track'][0]({
                      preCbs: [
                          {
                              method: function (args) {
  
                                  expect(args[0]).to.equal({ a: 1 });
                                  done();
                              }
                          }
                      ]
                  });
  
                  SDK.signup_track({ a: 1 });
              });
          });
  
          describe('identify', () => {
  
              it('should refuse a to operate if there is no proper reques', { plan: 2 }, (done) => {
  
                  expect(SDK.identify(null)).to.be.false();
                  expect(SDK.identify('')).to.be.false();
                  done();
              });
  
              it('should create a new record and add auth session', { plan: 10 }, (done) => {
  
                  const req = { __sqreen_uuid: 10 };
                  const res = SDK.identify(req, { hello: 'world' }, 'b');
                  expect(res).to.be.true();
  
                  expect(Record.lazyGet()).to.not.exist();
                  expect(Record.lazyGet(null)).to.not.exist();
                  const record = Record.STORE.get(req);
                  expect(record).to.exist();
                  expect(record.observed.sdk).to.have.length(1);
                  expect(record.observed.sdk[0].args).to.equal([{ hello: 'world' }, 'b']);
                  expect(record.observed.sdk[0].time).to.exist();
                  expect(record.observed.sdk[0].name).to.equal('identify');
  
                  SDK.identify(req, 'a', 'b', 'c', 'd', 'e');
                  expect(record.observed.sdk).to.have.length(2);
                  expect(record.observed.sdk[1].args).to.equal(['a', 'b']);
                  done();
  
              });
          });
      });
  
      describe('events', () => {
  
          describe('track', () => {
  
              it('should track a custom event and provide a stacktrace', { plan: 3 }, (done) => {
  
                  const Command = require('../../lib/command/index');
  
                  Command.execute({
                      name: 'record_stacktrace',
                      params: ['hello'],
                      uuid: '1'
                  });
  
                  const date = new Date();
                  const req = { __sqreen_uuid: 1 };
                  SDK.track('hello', {
                      request: req,
                      timestamp: date,
                      extra_field: 'we will we will warn you'
                  });
  
                  SDK.track('hello2', {
                      request: req,
                      timestamp: date
                  });
  
  
                  const record = Record.lazyGet(req);
  
                  expect(record.observed.sdk).to.have.length(2);
                  expect(record.observed.sdk[0].args[1].stacktrace).to.exist();
                  expect(record.observed.sdk[1].args[1].stacktrace).to.not.exist();
                  done();
              });
  
              it('should track a custom event and find req in CLS', { plan: 2 }, (done) => {
  
                  delete process.namespaces.sqreen_session;
                  NS = require('../../lib/instrumentation/hooks/util').getNS();
                  NS.run(() => {
  
                      const req = { __sqreen_uuid: 1 };
                      NS.set('req', req);
                      SDK.track('hello');
  
                      const record = Record.lazyGet(req);
  
                      expect(record.observed.sdk).to.have.length(1);
                      expect(record.observed.sdk[0].args[0]).to.equal('hello');
  
                      done();
                  });
              });
  
              it('should track a custom event and find req in CLS and remove properties', { plan: 9 }, (done) => {
  
                  delete process.namespaces.sqreen_session;
                  NS = require('../../lib/instrumentation/hooks/util').getNS();
                  NS.run(() => {
  
                      const req = { __sqreen_uuid: 1 };
                      NS.set('req', req);
  
                      const prop = {};
                      for (let i = 0; i < 16; ++i) {
                          prop[String.fromCharCode(65 + i)] = String.fromCharCode(65 + i);
                      }
  
                      SDK.track('hello1', {});
                      SDK.track('hello2', { properties: {} });
                      SDK.track('hello3', { properties: prop });
  
                      expect(prop[String.fromCharCode(65 + 15)]).to.exist();
  
                      prop.Z = 'Z';
  
                      SDK.track('hello4', { properties: prop });
                      SDK.track('hello5');
  
                      expect(prop.Z).to.equal('Z');
  
  
                      const record = Record.lazyGet(req);
  
                      expect(record.observed.sdk).to.have.length(5);
                      expect(record.observed.sdk[0].args[0]).to.equal('hello1');
                      expect(record.observed.sdk[1].args[0]).to.equal('hello2');
                      expect(record.observed.sdk[2].args[0]).to.equal('hello3');
                      expect(record.observed.sdk[2].args[1].properties).to.have.length(16);
                      expect(record.observed.sdk[3].args[0]).to.equal('hello4');
                      expect(record.observed.sdk[3].args[1].properties.Z).to.not.exist();
  
                      done();
                  });
              });
  
              it('should track a custom event but update its name', { plan: 2 }, (done) => {
  
                  const req = { __sqreen_uuid: 1 };
                  const res = SDK.track('sq.hello', {
                      request: req
                  });
  
                  expect(res).to.be.false();
  
                  const record = Record.lazyGet(req);
  
                  expect(record.observed.sdk).to.have.length(0);
                  done();
              });
  
              it('should not track a custom event but update its name', { plan: 1 }, (done) => {
  
                  const res = SDK.track('hello', {
                      request: undefined
                  });
  
                  expect(res).to.be.false();
  
                  done();
              });
  
              it('should fail to track a custom event because request is wrong', { plan: 2 }, (done) => {
  
                  const req = null;
                  const res = SDK.track('sq.hello', {
                      request: req
                  });
  
                  const record = Record.lazyGet(req);
  
                  expect(res).to.be.false();
                  expect(record).to.not.exist();
  
                  done();
              });
  
              it('should throw if used with bad arguments', { plan: 2 }, (done) => {
  
                  try {
                      SDK.track({});
                  }
                  catch (e) {
                      expect(e instanceof TypeError).to.be.true();
                  }
  
                  try {
                      SDK.track('', { timestamp: '' });
                  }
                  catch (e) {
                      expect(e instanceof TypeError).to.be.true();
                  }
                  done();
              });
  
          });
  
          describe('express integration', () => {
  
              it('should expose the sdk in req', { plan: 19 }, (done) => {
  
                  process.env.SQREEN_TOKEN = 'a';
                  const app = Express();
  
                  let request;
  
                  app.use(SDK.middleware);
                  app.get('/', (req, res) => {
  
                      expect(req.sqreen).to.exist();
                      expect(req.sqreen.identify).to.exist();
                      expect(req.sqreen.signup_track).to.be.a.function();
                      expect(req.sqreen.auth_track).to.be.a.function();
                      expect(req.sqreen.track).to.exist();
  
                      req.sqreen.identify({ username: 'admin' });
                      req.sqreen.track('login');
                      req.sqreen.track('login-admin', { user_identifiers: { username: 'vlad' } });
                      req.sqreen.track('login-admin', { user_identifiers: { username: 'admin' } });
  
                      request = req;
  
                      res.end('ok');
                  });
  
                  Request(app)
                      .get('/')
                      .expect(200)
                      .end((err, res) => {
  
                          expect(err).to.not.exist();
                          expect(res.text).to.equal('ok');
  
                          const record = Record.lazyGet(request);
  
                          record.observed.sdk.push({ name: 'track', args: ['hello'] });
  
                          expect(record).to.exist();
                          record.close(request);
  
                          expect(record.observed.sdk).to.have.length(5);
                          expect(record.observed.sdk[0].name).to.equal('identify');
                          expect(record.observed.sdk[1].name).to.equal('track');
                          expect(record.observed.sdk[1].args[0]).to.equal('login');
                          expect(record.observed.sdk[1].args[1].user_identifiers).to.equal({ username: 'admin' });
                          expect(record.observed.sdk[2].args[0]).to.equal('login-admin');
                          expect(record.observed.sdk[2].args[1].user_identifiers).to.equal({ username: 'vlad' });
                          expect(record.observed.sdk[3].args[0]).to.equal('login-admin');
                          expect(record.observed.sdk[3].args[1].user_identifiers).to.equal({ username: 'admin' });
                          expect(record.observed.sdk[4].args[0]).to.equal('hello');
                          expect(record.observed.sdk[4].args[1].user_identifiers).to.equal({ username: 'admin' });
  
                          process.env.SQREEN_TOKEN = undefined;
                          done();
                      });
  
  
              });
  
          });
  
      });
  });
  