<commit_before>/*!
 * Copyright (c) 2015-2017 Cisco Systems, Inc. See LICENSE file.
 */

import {set} from 'lodash';
import {assert} from '@ciscospark/test-helper-chai';
import sinon from '@ciscospark/test-helper-sinon';
import MockSpark from '@ciscospark/test-helper-mock-spark';
import {Credentials, Token, grantErrors} from '@ciscospark/spark-core';
import {inBrowser} from '@ciscospark/common';
import lolex from 'lolex';

/* eslint camelcase: [0] */

// eslint-disable-next-line no-empty-function
function noop() {}

function promiseTick(count) {
  let promise = Promise.resolve();
  while (count > 1) {
    promise = promise.then(() => promiseTick(1));
    count -= 1;
  }
  return promise;
}

const AUTHORIZATION_STRING = 'https://api.ciscospark.com/v1/authorize?client_id=MOCK_CLIENT_ID&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8000&scope=spark%3Arooms_read%20spark%3Ateams_read&state=set_state_here';

describe('spark-core', () => {
  describe('Credentials', () => {
    let clock;

    beforeEach(() => {
      clock = lolex.install({now: Date.now()});
    });

    afterEach(() => {
      clock.uninstall();
    });

    function makeToken(spark, options) {
      return new Token(options, {parent: spark});
    }

    describe('#calcRefreshTimeout', () => {
      it('generates a number between 60-90% of expiration', () => {
        const expiration = 1000;
        const spark = new MockSpark();
        const credentials = new Credentials(undefined, {parent: spark});
        const result = credentials.calcRefreshTimeout(expiration);
        assert.isTrue(result >= expiration * 0.6);
        assert.isTrue(result <= expiration * 0.9);
      });
    });

    describe('#canAuthorize', () => {
      it('indicates if the current state has enough information to populate an auth header, even if a token refresh or token downscope is required', () => {
        const spark = new MockSpark();
        spark.config.credentials.refreshCallback = inBrowser && noop;
        let credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.isFalse(credentials.canAuthorize);

        credentials.supertoken = makeToken(spark, {
          access_token: 'AT'
        });
        assert.isTrue(credentials.canAuthorize);

        credentials.supertoken.unset('access_token');
        assert.isFalse(credentials.canAuthorize);

        credentials.supertoken = makeToken(spark, {
          access_token: 'AT'
        });
        assert.isTrue(credentials.canAuthorize);

        credentials.supertoken = makeToken(spark, {
          access_token: 'AT',
          expires: Date.now() - 10000
        });
        assert.isFalse(credentials.supertoken.canAuthorize);
        assert.isFalse(credentials.canRefresh);
        assert.isFalse(credentials.canAuthorize);

        spark.config.credentials.refreshCallback = inBrowser && noop;
        credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.isFalse(credentials.canAuthorize);
        credentials.supertoken = makeToken(spark, {
          access_token: 'AT',
          refresh_token: 'RT'
        });
        credentials.supertoken.unset('access_token');
        assert.isTrue(credentials.canAuthorize);
      });
    });

    describe('#canRefresh', () => {
      it('indicates if there is presently enough information to refresh', () => {
        const spark = new MockSpark();
        let credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.isFalse(credentials.canRefresh);
        credentials.supertoken = makeToken(spark, {
          access_token: 'AT'
        }, {parent: true});
        assert.isFalse(credentials.canRefresh);

        spark.config.credentials.refreshCallback = inBrowser && noop;
        credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.isFalse(credentials.canRefresh);
        credentials.supertoken = makeToken(spark, {
          access_token: 'AT',
          refresh_token: 'RT'
        });
        assert.isTrue(credentials.supertoken.canRefresh);
        assert.isTrue(credentials.canRefresh);
      });
    });

    describe('#buildLoginUrl()', () => {
      it('requires `state` to be an object', () => {
        const spark = new MockSpark({
          children: {
            credentials: Credentials
          }
        });
        spark.trigger('change:config)');
        assert.doesNotThrow(() => {
          spark.credentials.buildLoginUrl();
        }, /if specified, `options.state` must be an object/);

        assert.doesNotThrow(() => {
          spark.credentials.buildLoginUrl({});
        }, /if specified, `options.state` must be an object/);

        assert.throws(() => {
          spark.credentials.buildLoginUrl({state: 'state'});
        }, /if specified, `options.state` must be an object/);

        assert.doesNotThrow(() => {
          spark.credentials.buildLoginUrl({state: {}});
        }, /if specified, `options.state` must be an object/);
      });

      it('prefers the hydra auth url, but falls back to idbroker', () => {
        const spark = new MockSpark();
        let credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');

        assert.match(credentials.buildLoginUrl({state: {}}), /idbroker/);
        spark.config.credentials = {
          authorizationString: AUTHORIZATION_STRING
        };
        credentials = new Credentials({}, {parent: spark});
        spark.trigger('change:config');
        assert.match(credentials.buildLoginUrl({state: {}}), /api.ciscospark.com/);
      });

      it('generates the login url', () => {
        const spark = new MockSpark();
        const credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');

        assert.equal(credentials.buildLoginUrl({state: {page: 'front'}}), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/authorize?state=eyJwYWdlIjoiZnJvbnQifQ&client_id=fake&redirect_uri=http%3A%2F%2Fexample.com&scope=scope%3Aone&response_type=code`);
      });

      it('generates the login url with empty state param', () => {
        const spark = new MockSpark();
        const credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');

        assert.equal(credentials.buildLoginUrl({state: {}}), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/authorize?client_id=fake&redirect_uri=http%3A%2F%2Fexample.com&scope=scope%3Aone&response_type=code`);
      });
    });

    describe('#buildLogoutUrl()', () => {
      it('generates the logout url', () => {
        const spark = new MockSpark();
        spark.config.credentials.redirect_uri = 'ru';
        const credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.equal(credentials.buildLogoutUrl(), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/logout?cisService=spark&goto=ru`);
      });

      it('includes a token param if passed', () => {
        const spark = new MockSpark();
        spark.config.credentials.redirect_uri = 'ru';
        const credentials = new Credentials(undefined, {parent: spark});<commit_msg>test(spark-core): skip BTS browser tests<commit_after>/*!
 * Copyright (c) 2015-2017 Cisco Systems, Inc. See LICENSE file.
 */

import {set} from 'lodash';
import {assert} from '@ciscospark/test-helper-chai';
import sinon from '@ciscospark/test-helper-sinon';
import MockSpark from '@ciscospark/test-helper-mock-spark';
import {Credentials, Token, grantErrors} from '@ciscospark/spark-core';
import {inBrowser} from '@ciscospark/common';
import lolex from 'lolex';
import {skipInBrowser} from '@ciscospark/test-helper-mocha';

/* eslint camelcase: [0] */

// eslint-disable-next-line no-empty-function
function noop() {}

function promiseTick(count) {
  let promise = Promise.resolve();
  while (count > 1) {
    promise = promise.then(() => promiseTick(1));
    count -= 1;
  }
  return promise;
}

const AUTHORIZATION_STRING = 'https://api.ciscospark.com/v1/authorize?client_id=MOCK_CLIENT_ID&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8000&scope=spark%3Arooms_read%20spark%3Ateams_read&state=set_state_here';

describe('spark-core', () => {
  describe('Credentials', () => {
    let clock;

    beforeEach(() => {
      clock = lolex.install({now: Date.now()});
    });

    afterEach(() => {
      clock.uninstall();
    });

    function makeToken(spark, options) {
      return new Token(options, {parent: spark});
    }

    describe('#calcRefreshTimeout', () => {
      it('generates a number between 60-90% of expiration', () => {
        const expiration = 1000;
        const spark = new MockSpark();
        const credentials = new Credentials(undefined, {parent: spark});
        const result = credentials.calcRefreshTimeout(expiration);
        assert.isTrue(result >= expiration * 0.6);
        assert.isTrue(result <= expiration * 0.9);
      });
    });

    describe('#canAuthorize', () => {
      it('indicates if the current state has enough information to populate an auth header, even if a token refresh or token downscope is required', () => {
        const spark = new MockSpark();
        spark.config.credentials.refreshCallback = inBrowser && noop;
        let credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.isFalse(credentials.canAuthorize);

        credentials.supertoken = makeToken(spark, {
          access_token: 'AT'
        });
        assert.isTrue(credentials.canAuthorize);

        credentials.supertoken.unset('access_token');
        assert.isFalse(credentials.canAuthorize);

        credentials.supertoken = makeToken(spark, {
          access_token: 'AT'
        });
        assert.isTrue(credentials.canAuthorize);

        credentials.supertoken = makeToken(spark, {
          access_token: 'AT',
          expires: Date.now() - 10000
        });
        assert.isFalse(credentials.supertoken.canAuthorize);
        assert.isFalse(credentials.canRefresh);
        assert.isFalse(credentials.canAuthorize);

        spark.config.credentials.refreshCallback = inBrowser && noop;
        credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.isFalse(credentials.canAuthorize);
        credentials.supertoken = makeToken(spark, {
          access_token: 'AT',
          refresh_token: 'RT'
        });
        credentials.supertoken.unset('access_token');
        assert.isTrue(credentials.canAuthorize);
      });
    });

    describe('#canRefresh', () => {
      it('indicates if there is presently enough information to refresh', () => {
        const spark = new MockSpark();
        let credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.isFalse(credentials.canRefresh);
        credentials.supertoken = makeToken(spark, {
          access_token: 'AT'
        }, {parent: true});
        assert.isFalse(credentials.canRefresh);

        spark.config.credentials.refreshCallback = inBrowser && noop;
        credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.isFalse(credentials.canRefresh);
        credentials.supertoken = makeToken(spark, {
          access_token: 'AT',
          refresh_token: 'RT'
        });
        assert.isTrue(credentials.supertoken.canRefresh);
        assert.isTrue(credentials.canRefresh);
      });
    });

    describe('#buildLoginUrl()', () => {
      it('requires `state` to be an object', () => {
        const spark = new MockSpark({
          children: {
            credentials: Credentials
          }
        });
        spark.trigger('change:config)');
        assert.doesNotThrow(() => {
          spark.credentials.buildLoginUrl();
        }, /if specified, `options.state` must be an object/);

        assert.doesNotThrow(() => {
          spark.credentials.buildLoginUrl({});
        }, /if specified, `options.state` must be an object/);

        assert.throws(() => {
          spark.credentials.buildLoginUrl({state: 'state'});
        }, /if specified, `options.state` must be an object/);

        assert.doesNotThrow(() => {
          spark.credentials.buildLoginUrl({state: {}});
        }, /if specified, `options.state` must be an object/);
      });

      it('prefers the hydra auth url, but falls back to idbroker', () => {
        const spark = new MockSpark();
        let credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');

        assert.match(credentials.buildLoginUrl({state: {}}), /idbroker/);
        spark.config.credentials = {
          authorizationString: AUTHORIZATION_STRING
        };
        credentials = new Credentials({}, {parent: spark});
        spark.trigger('change:config');
        assert.match(credentials.buildLoginUrl({state: {}}), /api.ciscospark.com/);
      });

      skipInBrowser(it)('generates the login url', () => {
        const spark = new MockSpark();
        const credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');

        assert.equal(credentials.buildLoginUrl({state: {page: 'front'}}), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/authorize?state=eyJwYWdlIjoiZnJvbnQifQ&client_id=fake&redirect_uri=http%3A%2F%2Fexample.com&scope=scope%3Aone&response_type=code`);
      });

      skipInBrowser(it)('generates the login url with empty state param', () => {
        const spark = new MockSpark();
        const credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');

        assert.equal(credentials.buildLoginUrl({state: {}}), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/authorize?client_id=fake&redirect_uri=http%3A%2F%2Fexample.com&scope=scope%3Aone&response_type=code`);
      });
    });


    describe('#buildLogoutUrl()', () => {
      skipInBrowser(it)('generates the logout url', () => {
        const spark = new MockSpark();
        spark.config.credentials.redirect_uri = 'ru';
        const credentials = new Credentials(undefined, {parent: spark});
        spark.trigger('change:config');
        assert.equal(credentials.buildLogoutUrl(), `${process.env.IDBROKER_BASE_URL || 'https://idbroker.webex.com'}/idb/oauth2/v1/logout?cisService=spark&goto=ru`);
      });

      skipInBrowser(it)('includes a token param if passed', () => {
        const spark = new MockSpark();
        spark.config.credentials.redirect_uri = 'ru';
        const credentials = new Credentials(undefined, {parent: spark});
{'fraction_non_alphanumeric': 0.14595462758482233, 'fraction_numerical': 0.00749514822994044, 'mean_word_length': 3.078602620087336, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 53, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, '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': '380506', 'n_tokens_mistral': 4523, 'n_tokens_neox': 4377, 'n_words': 819}