text: 'use strict';
  
  const chai = require('chai');
  
  const expect = chai.expect;
  const sinon = require('sinon');
  const BbPromise = require('bluebird');
  const _ = require('lodash');
  const childProcess = BbPromise.promisifyAll(require('child_process'));
  const AwsCompileWebsocketsEvents = require('../index');
  const Serverless = require('../../../../../../../Serverless');
  const AwsProvider = require('../../../../../provider/awsProvider');
  const generateCustomResourceZip = require('../../../../../customResources/generateZip');
  
  chai.use(require('chai-as-promised'));
  
  describe('#compileStage()', () => {
    let awsCompileWebsocketsEvents;
    let stageLogicalId;
    let logGroupLogicalId;
  
    // Ensure to clear stored custom resource zip path
    // As if it was created with previous test file run, it'll be not existent
    // due to temporary home directory being removed in a meantime
    before(() => generateCustomResourceZip.cache.clear());
  
    beforeEach(() => {
      const options = {
        stage: 'dev',
        region: 'us-east-1',
      };
      const serverless = new Serverless();
      serverless.setProvider('aws', new AwsProvider(serverless));
      serverless.service.service = 'my-service';
      serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} };
      serverless.config.servicePath = 'my-service';
      serverless.cli = { log: () => {} };
  
      awsCompileWebsocketsEvents = new AwsCompileWebsocketsEvents(serverless, options);
      stageLogicalId = awsCompileWebsocketsEvents.provider.naming.getWebsocketsStageLogicalId();
      logGroupLogicalId = awsCompileWebsocketsEvents.provider.naming.getWebsocketsLogGroupLogicalId();
      awsCompileWebsocketsEvents.websocketsApiLogicalId = awsCompileWebsocketsEvents.provider.naming.getWebsocketsApiLogicalId();
      awsCompileWebsocketsEvents.websocketsDeploymentLogicalId = awsCompileWebsocketsEvents.provider.naming.getWebsocketsDeploymentLogicalId(
        1234
      );
    });
  
    it('should create a stage resource if no websocketApiId specified', () =>
      awsCompileWebsocketsEvents.compileStage().then(() => {
        const resources =
          awsCompileWebsocketsEvents.serverless.service.provider.compiledCloudFormationTemplate
            .Resources;
        const resourceKeys = Object.keys(resources);
  
        expect(resourceKeys[0]).to.equal(stageLogicalId);
        expect(resources.WebsocketsDeploymentStage.Type).to.equal('AWS::ApiGatewayV2::Stage');
        expect(resources.WebsocketsDeploymentStage.Properties.ApiId).to.deep.equal({
          Ref: awsCompileWebsocketsEvents.websocketsApiLogicalId,
        });
        expect(resources.WebsocketsDeploymentStage.Properties.DeploymentId).to.deep.equal({
          Ref: awsCompileWebsocketsEvents.websocketsDeploymentLogicalId,
        });
        expect(resources.WebsocketsDeploymentStage.Properties.StageName).to.equal('dev');
        expect(resources.WebsocketsDeploymentStage.Properties.Description).to.equal(
          'Serverless Websockets'
        );
      }));
  
    it('should not create a stage resource if a websocketApiId is specified', () => {
      awsCompileWebsocketsEvents.serverless.service.provider.apiGateway = {
        websocketApiId: 'xyz123abc',
      };
      return awsCompileWebsocketsEvents.compileStage().then(() => {
        const resources =
          awsCompileWebsocketsEvents.serverless.service.provider.compiledCloudFormationTemplate
            .Resources;
        const resourceKeys = Object.keys(resources);
  
        expect(resourceKeys.length).to.equal(0);
      });
    });
  
    describe('logs', () => {
      before(() => sinon.stub(childProcess, 'execAsync'));
      after(() => childProcess.execAsync.restore());
      beforeEach(() => {
        // setting up Websocket logs
        awsCompileWebsocketsEvents.serverless.service.provider.logs = {
          websocket: true,
        };
      });
  
      it('should create a dedicated stage resource if logs are configured', () =>
        awsCompileWebsocketsEvents.compileStage().then(() => {
          const resources =
            awsCompileWebsocketsEvents.serverless.service.provider.compiledCloudFormationTemplate
              .Resources;
  
          expect(resources[stageLogicalId]).to.deep.equal({
            Type: 'AWS::ApiGatewayV2::Stage',
            Properties: {
              ApiId: {
                Ref: awsCompileWebsocketsEvents.websocketsApiLogicalId,
              },
              DeploymentId: {
                Ref: awsCompileWebsocketsEvents.websocketsDeploymentLogicalId,
              },
              StageName: 'dev',
              Description: 'Serverless Websockets',
              AccessLogSettings: {
                DestinationArn: {
                  'Fn::Sub':
                    'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${WebsocketsLogGroup}',
                },
                Format: [
                  '$context.identity.sourceIp',
                  '$context.identity.caller',
                  '$context.identity.user',
                  '[$context.requestTime]',
                  '"$context.eventType $context.routeKey $context.connectionId"',
                  '$context.requestId',
                ].join(' '),
              },
              DefaultRouteSettings: {
                DataTraceEnabled: true,
                LoggingLevel: 'INFO',
              },
            },
          });
        }));
  
      it('should create a Log Group resource', () =>
        awsCompileWebsocketsEvents.compileStage().then(() => {
          const resources =
            awsCompileWebsocketsEvents.serverless.service.provider.compiledCloudFormationTemplate
              .Resources;
  
          expect(resources[logGroupLogicalId]).to.deep.equal({
            Type: 'AWS::Logs::LogGroup',
            Properties: {
              LogGroupName: '/aws/websocket/my-service-dev',
            },
          });
        }));
  
      it('should set a RetentionInDays in a Log Group if provider has logRetentionInDays', () => {
        awsCompileWebsocketsEvents.serverless.service.provider.logRetentionInDays = 42;
  
        return awsCompileWebsocketsEvents.compileStage().then(() => {
          const resources =
            awsCompileWebsocketsEvents.serverless.service.provider.compiledCloudFormationTemplate
              .Resources;
  
          expect(resources[logGroupLogicalId]).to.deep.equal({
            Type: 'AWS::Logs::LogGroup',
            Properties: {
              LogGroupName: '/aws/websocket/my-service-dev',
              RetentionInDays: 42,
            },
          });
        });
      });
  
      it('should use valid logging level', () => {
        awsCompileWebsocketsEvents.serverless.service.provider.logs = {
          websocket: {
            level: 'ERROR',
          },
        };
  
        return awsCompileWebsocketsEvents.compileStage().then(() => {
          const resources =
            awsCompileWebsocketsEvents.serverless.service.provider.compiledCloudFormationTemplate
              .Resources;
  
          expect(resources[stageLogicalId].Properties.DefaultRouteSettings.LoggingLevel).equal(
            'ERROR'
          );
        });
      });
  
      it('should reject invalid logging level', () => {
        awsCompileWebsocketsEvents.serverless.service.provider.logs = {
          websocket: {
            level: 'FOOBAR',
          },
        };
  
        expect(awsCompileWebsocketsEvents.compileStage()).to.be.rejectedWith('invalid value');
      });
  
      it('should ensure ClousWatch role custom resource', () => {
        return awsCompileWebsocketsEvents.compileStage().then(() => {
          const resources =
            awsCompileWebsocketsEvents.serverless.service.provider.compiledCloudFormationTemplate
              .Resources;
  
          expect(
            _.isObject(
              resources[
                awsCompileWebsocketsEvents.provider.naming.getCustomResourceApiGatewayAccountCloudWatchRoleResourceLogicalId()
              ]
            )
          ).to.equal(true);
        });
      });
    });
  });
  