text: /* eslint-disable import/no-unresolved */
  
  import Artifact from '@functions/transfer/transfer/artifact';
  
  import S3 from 'aws-sdk/clients/s3';
  import AWS from 'aws-sdk-mock';
  import faker from 'faker';
  import Zip from 'node-zip';
  import fs from 'fs';
  
  describe('Artifact', () => {
    const bucketName = faker.random.uuid();
  
    const objectKey = faker.random.uuid();
  
    const secretAccessKey = faker.random.uuid();
  
    const sessionToken = faker.random.uuid();
  
    const accessKeyId = faker.random.uuid();
  
    const credentials = { secretAccessKey, sessionToken, accessKeyId };
  
    const location = { bucketName, objectKey };
  
    describe('#id', () => {
      it('returns the correct value', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.id).toEqual(expect.stringMatching(/^[-a-zA-Z0-9]+$/));
      });
    });
  
    describe('#filename', () => {
      it('returns the correct value', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.filename).toEqual(`${artifact.id}.zip`);
      });
    });
  
    describe('#filepath', () => {
      it('returns the correct value', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.filepath).toEqual(`/tmp/${artifact.id}.zip`);
      });
    });
  
    describe('#dir', () => {
      it('returns the correct value', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.dir).toEqual(expect.stringMatching(/^\/tmp\/[-a-zA-Z0-9]+$/));
      });
    });
  
    describe('#bucketName', () => {
      it('returns the correct value', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.bucketName).toEqual(bucketName);
      });
    });
  
    describe('#objectKey', () => {
      it('returns the correct value', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.objectKey).toEqual(objectKey);
      });
    });
  
    describe('#secretAccessKey', () => {
      it('returns the correct value', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.secretAccessKey).toEqual(secretAccessKey);
      });
    });
  
    describe('#sessionToken', () => {
      it('returns the correct value', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.sessionToken).toEqual(sessionToken);
      });
    });
  
    describe('#accessKeyId', () => {
      it('returns the correct value', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.accessKeyId).toEqual(accessKeyId);
      });
    });
  
    describe('#ready', () => {
      const artifact = new Artifact(location, credentials);
  
      const { dir, filepath } = artifact;
  
      const key = faker.random.word();
  
      const value = faker.random.number();
  
      const jsonFile = `${faker.random.uuid()}.json`;
  
      const data = JSON.stringify({ [key]: value });
  
      describe('when the artifact readys successfully', () => {
        beforeEach(() => {
          const zipFile = new Zip();
          zipFile.file(jsonFile, data);
          const zipped = zipFile.generate({ base64: false, compression: 'DEFLATE' });
          AWS.mock('S3', 'getObject', (params, cb) => {
            expect(params).toEqual(
              expect.objectContaining({
                Bucket: bucketName,
                Key: objectKey,
              })
            );
            cb(null, { Body: Buffer.from(zipped, 'binary') });
          });
        });
  
        afterEach(() => {
          fs.unlinkSync(filepath);
          fs.unlinkSync(`${dir}/${jsonFile}`);
          fs.rmdirSync(dir);
          AWS.restore('S3', 'getObject');
        });
  
        it('fetches, loads and unzips correctly', () => expect(artifact.ready()).resolves.toBe(true));
      });
  
      describe('when the artifact fails to ready', () => {
        const invalidArtifact = new Artifact({}, credentials);
  
        it('rejects with an error', () =>
          expect(invalidArtifact.ready()).rejects.toEqual(expect.any(Error)));
      });
    });
  
    describe('#match', () => {
      describe('when files are matched', () => {
        const artifact = new Artifact(location, credentials);
  
        const { dir } = artifact;
  
        const relativePath = 'output';
  
        const path = `${dir}/${relativePath}`;
  
        const filename = faker.system.fileName();
  
        const selector = '**/*';
  
        const absolutePath = `${path}/${filename}`;
  
        beforeEach(() => {
          fs.mkdirSync(dir);
          fs.mkdirSync(path);
          fs.writeFileSync(absolutePath, '', { encoding: 'utf8' });
        });
  
        afterEach(() => {
          fs.unlinkSync(absolutePath);
          fs.rmdirSync(path);
          fs.rmdirSync(dir);
        });
  
        it('should return the correct files (without path)', async () => {
          const [file] = await artifact.match(selector);
          expect(file.key).toEqual(`/${relativePath}/${filename}`);
          expect(file.absolutePath).toEqual(absolutePath);
        });
  
        it('should return the correct files (with path)', async () => {
          const [file] = await artifact.match(selector, relativePath);
          expect(file.key).toEqual(`/${filename}`);
          expect(file.absolutePath).toEqual(absolutePath);
        });
      });
    });
  
    describe('#get', () => {
      describe('when the file exists', () => {
        const artifact = new Artifact(location, credentials);
  
        const { dir } = artifact;
  
        const filename = faker.random.uuid();
  
        const data = JSON.stringify({ [faker.random.word()]: faker.random.number() });
  
        beforeEach(() => {
          fs.mkdirSync(dir);
          fs.writeFileSync(`${dir}/${filename}`, data, { encoding: 'utf8' });
        });
  
        afterEach(() => {
          fs.unlinkSync(`${dir}/${filename}`);
          fs.rmdirSync(dir);
        });
  
        it('should return the file', () => {
          expect(artifact.get(filename)).toEqual(data);
        });
      });
  
      describe('when the file does not exist', () => {
        const artifact = new Artifact(location, credentials);
  
        const { dir } = artifact;
  
        const filename = faker.random.uuid();
  
        beforeEach(() => {
          fs.mkdirSync(dir);
        });
  
        afterEach(() => {
          fs.rmdirSync(dir);
        });
  
        it('throws an error', () => {
          expect(() => artifact.get(filename)).toThrow(Error);
        });
      });
    });
  
    describe('#attribute', () => {
      describe('when the file and key exists', () => {
        const artifact = new Artifact(location, credentials);
  
        const { dir } = artifact;
  
        const filename = faker.random.uuid();
  
        const key = faker.random.word();
  
        const value = faker.random.number();
  
        const data = JSON.stringify({ [key]: value });
  
        beforeEach(() => {
          fs.mkdirSync(dir);
          fs.writeFileSync(`${dir}/${filename}`, data, { encoding: 'utf8' });
        });
  
        afterEach(() => {
          fs.unlinkSync(`${dir}/${filename}`);
          fs.rmdirSync(dir);
        });
  
        it('should return the file', () => {
          expect(artifact.attribute(filename, key)).toEqual(value);
        });
      });
  
      describe('when the files does not exist', () => {
        const artifact = new Artifact(location, credentials);
  
        const { dir } = artifact;
  
        const filename = faker.random.uuid();
  
        const key = faker.random.word();
  
        beforeEach(() => {
          fs.mkdirSync(dir);
        });
  
        afterEach(() => {
          fs.rmdirSync(dir);
        });
  
        it('should throw an error', () => {
          expect(() => artifact.attribute(filename, key)).toThrow(Error);
        });
      });
  
      describe('when the key is not present', () => {
        const artifact = new Artifact(location, credentials);
  
        const { dir } = artifact;
  
        const filename = faker.random.uuid();
  
        const key = faker.random.word();
  
        const data = JSON.stringify({});
  
        beforeEach(() => {
          fs.mkdirSync(dir);
          fs.writeFileSync(`${dir}/${filename}`, data, { encoding: 'utf8' });
        });
  
        afterEach(() => {
          fs.unlinkSync(`${dir}/${filename}`);
          fs.rmdirSync(dir);
        });
  
        it('should throw an error', () => {
          expect(() => artifact.attribute(filename, key)).toThrow(Error);
        });
      });
    });
  
    describe('#unzip', () => {
      describe('when the artifact can be unzipped', () => {
        const artifact = new Artifact(location, credentials);
  
        const { filepath } = artifact;
  
        const key = `${faker.random.uuid()}.json`;
  
        const data = JSON.stringify({ [faker.random.word()]: faker.random.number() });
  
        beforeEach(() => {
          const zipFile = new Zip();
          zipFile.file(key, data);
          const zipped = zipFile.generate({ base64: false, compression: 'DEFLATE' });
          fs.writeFileSync(filepath, zipped, 'binary');
        });
  
        afterEach(() => {
          fs.unlinkSync(filepath);
        });
  
        it('should unzip the file', async () => {
          const success = await artifact.unzip();
          expect(success).toBe(true);
          expect(artifact.get(key)).toEqual(data);
        });
      });
  
      describe('when the artifact cannot be unzipped', () => {
        const artifact = new Artifact(location, credentials);
  
        const { filepath } = artifact;
  
        beforeEach(() => {
          fs.writeFileSync(filepath, '', 'utf8');
        });
  
        afterEach(() => {
          fs.unlinkSync(filepath);
        });
  
        it('reject with an error', async () =>
          expect(artifact.unzip()).rejects.toEqual(expect.any(Error)));
      });
    });
  
    describe('#write', () => {
      const artifact = new Artifact(location, credentials);
  
      const data = JSON.stringify({ [faker.random.word()]: faker.random.number() });
  
      it('writes a file to the correct location', () =>
        expect(artifact.write(data)).resolves.toEqual(true));
  
      afterEach(() => {
        fs.unlinkSync(artifact.filepath);
      });
    });
  
    describe('#fetch', () => {
      describe('when the artifact can be retrieved', () => {
        const artifact = new Artifact(location, credentials);
  
        const data = JSON.stringify({ [faker.random.word()]: faker.random.number() });
  
        beforeEach(() => {
          AWS.mock('S3', 'getObject', (params, cb) => {
            expect(params).toEqual(
              expect.objectContaining({
                Bucket: bucketName,
                Key: objectKey,
              })
            );
            cb(null, { Body: Buffer.from(data) });
          });
        });
  
        afterEach(() => {
          AWS.restore('S3', 'getObject');
        });
  
        it('should retrieve the correct data', () =>
          expect(artifact.fetch()).resolves.toEqual(Buffer.from(data)));
      });
  
      describe('when the artifact cannot be retrieved', () => {
        const artifact = new Artifact(location, credentials);
  
        beforeEach(() => {
          AWS.mock('S3', 'getObject', (params, cb) => {
            cb(new Error('TEST'));
          });
        });
  
        afterEach(() => {
          AWS.restore('S3', 'getObject');
        });
  
        it('should reject with an error', () =>
          expect(artifact.fetch()).rejects.toEqual(expect.any(Error)));
      });
    });
  
    describe('#client', () => {
      it('returns an S3 client', () => {
        const artifact = new Artifact(location, credentials);
        expect(artifact.client).toBeInstanceOf(S3);
      });
    });
  });
  
  describe('Artifact#toArtifact', () => {
    const bucketName = faker.random.uuid();
  
    const objectKey = faker.random.uuid();
  
    const secretAccessKey = faker.random.uuid();
  
    const sessionToken = faker.random.uuid();
  
    const accessKeyId = faker.random.uuid();
  
    const credentials = { secretAccessKey, sessionToken, accessKeyId };
  
    const name = faker.random.word();
  
    const artifact = { name, location: { s3Location: { bucketName, objectKey } } };
  
    it('correctly builds an artifact instance', () => {
      const obj = Artifact.toArtifact(artifact, credentials);
      expect(obj).toBeInstanceOf(Artifact);
      expect(obj.bucketName).toEqual(bucketName);
      expect(obj.objectKey).toEqual(objectKey);
      expect(obj.secretAccessKey).toEqual(secretAccessKey);
      expect(obj.sessionToken).toEqual(sessionToken);
      expect(obj.accessKeyId).toEqual(accessKeyId);
    });
  });
  
  describe('Artifact#toArtifactMapEntry', () => {
    const bucketName = faker.random.uuid();
  
    const objectKey = faker.random.uuid();
  
    const secretAccessKey = faker.random.uuid();
  
    const sessionToken = faker.random.uuid();
  
    const accessKeyId = faker.random.uuid();
  
    const credentials = { secretAccessKey, sessionToken, accessKeyId };
  
    const name = faker.random.word();
  
    const artifact = { name, location: { s3Location: { bucketName, objectKey } } };
  
    it('correctly builds an artifact instance', () => {
      const arr = Artifact.toArtifactMapEntry(artifact, credentials);
      expect(arr[0]).toEqual(name);
      expect(arr[1]).toBeInstanceOf(Artifact);
    });
  });
  