Home Reference Source Test

__tests__/functions/transfer/transfer/destination.test.js

/* eslint-disable import/no-unresolved */

import Destination from '@functions/transfer/transfer/destination';
import Attribute from '@functions/transfer/transfer/attribute';
import File from '@functions/transfer/transfer/artifact/file';

import faker from 'faker';
import Path from 'path';
import { Credentials, STS } from 'aws-sdk';
import AWS from 'aws-sdk-mock';

describe('Destination', () => {
  const roleArn = faker.random.uuid();

  const bucket = faker.random.word();

  const artifact = {
    ready: async () => true,
    match: async () => {
      const path = Path.join('/', faker.random.uuid());
      const filename = faker.system.fileName();
      const data = Buffer.from(JSON.stringify({ [faker.random.uuid()]: faker.random.uuid() }));
      return [new File(path, filename, data)];
    },
  };

  const artifactName = faker.random.word();

  const artifacts = { [artifactName]: artifact };

  const sources = [`${artifactName}::**/*`];

  const prefix = Path.join('/', faker.random.uuid());

  const cwd = faker.random.uuid();

  const properties = { roleArn, bucket, src: sources, prefix, cwd };

  describe('#new', () => {
    it('instantiates correctly', () => {
      const destination = new Destination(properties, artifacts);
      expect(destination.artifacts).toEqual(artifacts);
      expect(destination.roleArn).toEqual(expect.any(Attribute));
      expect(destination.bucket).toEqual(expect.any(Attribute));
      expect(destination.sources).toEqual(sources);
      expect(destination.prefix).toEqual(prefix);
      expect(destination.cwd).toEqual(cwd);
      expect(destination.sts).toEqual(expect.any(STS));
    });

    describe('.roleArn resolution', () => {
      it('resolves to the correct value', () => {
        const destination = new Destination(properties, artifacts);
        expect(destination.roleArn.value()).resolves.toEqual(roleArn);
      });
    });

    describe('.bucket resolution', () => {
      it('resolves to the correct value', () => {
        const destination = new Destination(properties, artifacts);
        expect(destination.bucket.value()).resolves.toEqual(bucket);
      });
    });
  });

  describe('#credentials', () => {
    describe('when the request is successful', () => {
      const accessKeyId = faker.random.uuid();

      const secretAccessKey = faker.random.uuid();

      const sessionToken = faker.random.uuid();

      const credentials = {
        AccessKeyId: accessKeyId,
        SecretAccessKey: secretAccessKey,
        SessionToken: sessionToken,
      };

      beforeEach(() => {
        AWS.mock('STS', 'assumeRole', (params, cb) => {
          expect(params).toEqual(
            expect.objectContaining({
              RoleSessionName: process.env.AWS_LAMBDA_FUNCTION_NAME,
              ExternalId: process.env.AWS_LAMBDA_FUNCTION_NAME,
              RoleArn: roleArn,
            })
          );
          cb(null, { Credentials: credentials });
        });
      });

      afterEach(() => {
        AWS.restore('STS', 'assumeRole');
      });

      it('returns a correctly instantiated AWS Credentials object', async () => {
        const destination = new Destination(properties, artifacts);
        const assumed = await destination.credentials();
        expect(assumed).toEqual(expect.any(Credentials));
        expect(assumed.accessKeyId).toEqual(accessKeyId);
        expect(assumed.secretAccessKey).toEqual(secretAccessKey);
        expect(assumed.sessionToken).toEqual(sessionToken);
      });
    });

    describe('when the request is invalid', () => {
      beforeEach(() => {
        AWS.mock('STS', 'assumeRole', (params, cb) => {
          cb(new Error('TEST'), {});
        });
      });

      afterEach(() => {
        AWS.restore('STS', 'assumeRole');
      });

      it('returns a correctly instantiated AWS Credentials object', () => {
        const destination = new Destination(properties, artifacts);
        return expect(destination.credentials()).rejects.toEqual(expect.any(Error));
      });
    });
  });

  describe('#files', () => {
    describe('when the artifact exists', () => {
      it('resolves with an array of instantiated files', () => {
        const destination = new Destination(properties, artifacts);
        return expect(destination.files()).resolves.toEqual(
          expect.arrayContaining([expect.any(File)])
        );
      });
    });

    describe('when there are no files', () => {
      const noFileProperties = { roleArn, bucket, src: [], prefix };

      it('resolves with an empty array', () => {
        const destination = new Destination(noFileProperties, artifacts);
        return expect(destination.files()).resolves.toEqual([]);
      });
    });

    describe('when the artifact does not exist', () => {
      const invalidFileProperties = {
        roleArn,
        bucket,
        src: [`${faker.random.uuid()}::${faker.system.fileName()}`],
        prefix,
      };

      it('resolves with an empty array', () => {
        const destination = new Destination(invalidFileProperties, artifacts);
        return expect(destination.files()).rejects.toEqual(expect.any(Error));
      });
    });
  });

  describe('#upload', () => {
    describe('when all files can be uploaded successfully', () => {
      const destination = new Destination(properties, artifacts);

      const uploadLocation = `s3://${faker.random.uuid()}/${faker.system.fileName()}`;

      const upload = jest.fn().mockImplementation(async () => uploadLocation);

      const credentials = new Credentials(
        faker.random.uuid(),
        faker.random.uuid(),
        faker.random.uuid()
      );

      jest.spyOn(destination, 'files').mockImplementation(async () => [{ upload }]);

      jest.spyOn(destination, 'credentials').mockImplementation(async () => credentials);

      it('resolves with an array of remote locations', async () => {
        const urls = await destination.upload();
        expect(urls).toEqual(expect.arrayContaining([expect.stringMatching(uploadLocation)]));
        expect(destination.files).toHaveBeenCalled();
        expect(destination.credentials).toHaveBeenCalled();
        expect(upload).toHaveBeenCalledWith(
          expect.objectContaining({
            bucket,
            credentials,
            prefix,
          })
        );
      });
    });
  });
});