cloudfoundry-incubator/stratos

View on GitHub
src/test-e2e/helpers/request-helpers.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import { browser, promise } from 'protractor';
import request from 'request-promise-native';

import { E2E, e2e } from '../e2e';
import { ConsoleUserType } from './e2e-helpers';

// This helper is used internally - tests should not need to use this class

export interface RequestDefaults {
  headers: {
    'Content-Type'?: string,
    Accept?: string,
    [key: string]: string
  };
  resolveWithFullResponse: boolean;
  jar: any;
  agentOptions: object;
  timeout: number;
}

export class RequestHelpers {


  constructor() { }

  getHost(): string {
    return browser.baseUrl;
  }

  /**
   * @newRequest
   * @description Create a new request
   */
  newRequest(defaults: Partial<RequestDefaults> = {
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json'
    },
    resolveWithFullResponse: true,
    jar: request.jar(),
    timeout: 30000
  }) {
    const skipSSLValidation = browser.params.skipSSLValidation;
    if (skipSSLValidation) {
      process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
    } else if (browser.params.caCert) {
      let caCertFile = join(__dirname, '..', 'dev-ssl');
      caCertFile = join(caCertFile, browser.params.caCert);
      if (existsSync(caCertFile)) {
        const ca = readFileSync(caCertFile);
        defaults.agentOptions = {
          ca
        };
      }
    }

    return request.defaults(defaults);
  }

  /**
   * @sendRequest
   * @description Send request
   * @param {object} req - the request
   * @param {object} options -
   * @param {object?} body - the request body
   * @param {object?} formData - the form data
   */
  sendRequest(req, options, body?: any, formData?): promise.Promise<any> {
    const reqObj = req || this.newRequest();

    options.url = this.getHost() + '/' + options.url;
    if (body) {
      options.body = typeof body !== 'string' ? JSON.stringify(body) : body;
    } else if (formData) {
      options.formData = formData;
    }

    if (reqObj._xsrfToken) {
      options.headers = options.headers || {};
      options.headers['x-xsrf-token'] = reqObj._xsrfToken;
    }

    E2E.debugLog('REQ: ' + options.method + ' ' + options.url);
    this.showOptions(options);
    return this.retryRequest(reqObj, options, body, formData);
  }

  retryRequest(reqObj, options, body?: any, formData?, promize = null, retry = 0): promise.Promise<any> {
    const _that = this;
    const p = promize || promise.defer<any>();

    reqObj(options).then((response) => {
      E2E.debugLog('   + OK : ' + response.statusCode);
      // Get XSRF Token
      if (response.headers && response.headers['x-xsrf-token']) {
        reqObj._xsrfToken = response.headers['x-xsrf-token'];
      }
      p.fulfill(response.body);
    }).catch((e) => {
      E2E.debugLog('   - ERR: ' + e.statusCode + ' : ' + e.message);
      if (e.statusCode !== 401 && retry < 2) {
        retry++;
        E2E.debugLog('   - Retrying ' + options.method + ' ' + options.url + ' [' + retry + ']');
        _that.retryRequest(reqObj, options, body, formData, p, retry);
      } else {
        p.reject(e);
      }
    });

    return p.promise;
  }

  showOptions(options: any) {
    if (!options) {
      return;
    }
    const cpy = JSON.parse(JSON.stringify(options));
    this.sanitizeOption(cpy);
    E2E.debugLog('   > ' + JSON.stringify(cpy));
  }

  sanitizeOption(options) {
    Object.keys(options).forEach(key => {
      const v = options[key];
      if (typeof v === 'string' && key === 'password') {
        options[key] = '******';
      } else if (typeof v === 'object') {
        this.sanitizeOption(options[key]);
      }
    });
  }

  /**
   * @createSession
   * @description Create a session
   * @param {object} req - the request
   */
  createSession(req, userType: ConsoleUserType): promise.Promise<any> {
    const creds = e2e.secrets.getConsoleCredentials(userType);
    const formData = {
      username: creds.username || 'dev',
      password: creds.password || 'dev'
    };

    return this.sendRequest(req, { method: 'POST', url: 'pp/v1/auth/login/uaa' }, null, formData);
  }

  // /**
  //  * @isSetupMode
  //  * @description Check if console is in setup mode
  //  */
  // isSetupMode(): Promise<any> {
  //   const req = this.newRequest();
  //   return new Promise((resolve, reject) => {
  //     return req.post(this.getHost() + '/pp/v1/auth/login/uaa', {})
  //       .on('error', reject)
  //       .on('response', (response) => {
  //         if (response.statusCode === 503) {
  //           resolve();
  //         } else {
  //           reject();
  //         }
  //       });
  //   });
  // }

  chain<T>(
    currentValue: T,
    nextChainFc: () => promise.Promise<T>,
    maxChain: number,
    abortChainFc: (val: T) => boolean,
    count = 0): promise.Promise<T> {
    if (count >= maxChain || abortChainFc(currentValue)) {
      return promise.fullyResolved(currentValue);
    }
    e2e.debugLog('Chaining requests. Count: ' + count);

    return nextChainFc().then(res => {
      if (abortChainFc(res)) {
        return promise.fullyResolved<T>(res);
      }
      browser.sleep(500);
      return this.chain<T>(res, nextChainFc, maxChain, abortChainFc, ++count);
    });
  }
}