Шутка издевается над Google-облаком / хранилище машинописи - PullRequest
0 голосов
/ 15 апреля 2020

Я пытался смоделировать @ google-cloud / storage для моей реализации, чтобы я мог протестировать его, не сталкиваясь с облачным потоком в gcp, и до сих пор все было напрасно, я пытался издеваться над папка области действия node_module с использованием jest do c, и это не сработало. Поэтому я попытался использовать ниже

Это мой класс реализации

import { GcloudAuthenticationInstance } from '../common/services/gcloud.authentication';
import * as fs from 'fs';
import pump from 'pump';
import pino from 'pino';
import * as _ from 'lodash';

import {
    ENV_NAME_DEV,
    GCLOUD_DATABASE_BUCKET_DEV,
    GCLOUD_DATABASE_BUCKET_PROD,
    GCLOUD_ENV_STR_BUCKET_NAME,
    GCLOUD_STORED_FILE_NAME_DEV,
    GCLOUD_STORED_FILE_NAME_PROD,
    GCLOUD_UPLOAD_FILE_DEV_LOCAL_PATH,
    GCLOUD_UPLOAD_FILE_PROD_LOCAL_PATH,
} from '../common/util/app.constants';
import { PinoLoggerServiceInstance } from '../common/services/pino.logger.service';
import { AppUtilServiceInstance } from '../common/services/app.util.service';
export const uploadEnvFiles = async (env_name: string) => {
    const LOGGER: pino.Logger = PinoLoggerServiceInstance.getLogger(__filename);

    return new Promise(async (res, rej) => {
       // This just returns the Storage() instance with keyFileName and projectID
        //of google cloud console being set so authentication takes place
        const str = GcloudAuthenticationInstance.createGcloudAuthenticationBucket();

        const bucketToUpload = GCLOUD_ENV_STR_BUCKET_NAME;
        let uploadLocalFilePath;
        let destinationBucketPath;
        if (!AppUtilServiceInstance.isNullOrUndefined(env_name)) {
            uploadLocalFilePath = ENV_NAME_DEV === env_name ? GCLOUD_UPLOAD_FILE_DEV_LOCAL_PATH : GCLOUD_UPLOAD_FILE_PROD_LOCAL_PATH;
            destinationBucketPath = ENV_NAME_DEV === env_name ? GCLOUD_DATABASE_BUCKET_DEV : GCLOUD_DATABASE_BUCKET_PROD;
        }
        LOGGER.info('after authentication');
        pump(
            fs.createReadStream(uploadLocalFilePath),
            str
                .bucket(bucketToUpload)
                .file(destinationBucketPath)
                .createWriteStream({
                    gzip: true,
                    public: true,
                    resumable: true,
                })
        )
            .on('error', (err) => {
                LOGGER.error('Error occured in uploading:', err);
                rej({ status: 'Error', error: err, code: 500 });
            })
            .on('finish', () => {
                LOGGER.info('Successfully uploaded the file');
                res({ status: 'Success', code: 201, error: null });
            });
    });
};

export const downloadEnvFiles = async (env_name): Promise<any> => {
    const LOGGER: pino.Logger = PinoLoggerServiceInstance.getLogger(__filename);

    return new Promise(async (res, rej) => {
        const str = GcloudAuthenticationInstance.createGcloudAuthenticationBucket();
        try {
            const [files] = await str.bucket(GCLOUD_ENV_STR_BUCKET_NAME).getFiles();

            const filteredFile =
                ENV_NAME_DEV === env_name
                    ? _.find(files, (file) => {
                        c
                            return file.name.includes(GCLOUD_STORED_FILE_NAME_DEV);
                      })
                    : _.find(files, (file) => {

                            return file.name.includes(GCLOUD_STORED_FILE_NAME_PROD);
                      });
            res({
                status: 'Success',
                code: 200,
        error: null,
                stream: str
                    .bucket(GCLOUD_ENV_STR_BUCKET_NAME)
                    .file(filteredFile.name)
                    .createReadStream()
            });
        } catch (err) {
            LOGGER.error('Error in retrieving files from gcloud:'+err);
            rej({ status: 'Error', error: err, code: 500 });
        }
    });
};

Это мой шут ts

bucket.operations.int.spec.ts

Я пытался включить макет inline

 import { GcloudAuthenticationInstance } from '../common/services/gcloud.authentication';
const { Storage } = require('@google-cloud/storage');
const { Bucket } = require('@google-cloud/storage');
import { File } from '@google-cloud/storage';
import { mocked } from 'ts-jest/utils'
const fs = require('fs');
import * as path from 'path';
import pump from 'pump';
import * as BucketOperations from './bucket.operations';
import { GCLOUD_ENV_STR_BUCKET_NAME } from '../common/util/app.constants';
const { PassThrough } = require('stream');
const fsMock = jest.mock('fs');

// Here we are trying to mock pump with a function returned
// since pump () is the actual fucntion, we are mocking the function to return a value
// which is just a value of "on" eventlistener.. so we indicate that this will be substituted
// with another mocked function
jest.genMockFromModule('@google-cloud/storage');
jest.mock('@google-cloud/storage', () => {

  const mockedFile = jest.fn().mockImplementation(() => {
    return {
      File: jest.fn().mockImplementation(() => {
        return {
          name: 'dev.txt',
          createReadStream: jest
            .fn()
            .mockReturnValue(
              fs.createReadStream(
                path.resolve(process.cwd(), './tests/cloud-storage/sample-read.txt')
              )
            ),
          createWriteStream: jest
            .fn()
            .mockReturnValue(
              fs.createWriteStream(
                path.resolve(process.cwd(), './tests/cloud-storage/sample-write.txt')
              )
            )
        };
      })
    };
  });

  const mockedBUcket = jest.fn().mockImplementation(() => {
    return {
      Bucket: jest.fn().mockImplementation(() => {
        return {
          constructor: jest.fn().mockReturnValue('test-bucket'),
          getFiles: jest.fn().mockReturnValue([mockedFile])
        }
      })
    }
  });


  return {
    Storage: jest.fn().mockImplementation(() => {
      return {
        constructor: jest.fn().mockReturnValue('test-storage'),
        bucket: mockedBUcket,
        file: mockedFile,
        createWriteStream: jest.fn().mockImplementation(() =>
          fs.createWriteStream(path.resolve(process.cwd(), './tests/cloud-storage/sample-write.txt')))
      };
    })
  };
});

jest.mock('pump', () => {
  const mPump = { on: jest.fn() };
  return jest.fn(() => mPump);
});

describe('Test suite for testing bucket operations', () => {
  const mockedStorage = mocked(Storage, true);
  const mockeddFile = mocked(File, true);
  const mockeddBucket = mocked(Bucket, true);
  function cancelCloudStorageMock() {
    //mockCloudStorage.unmock('@google-cloud/storage');
    mockedStorage.mockClear();
    mockeddBucket.mockClear();
    mockeddFile.mockClear();
    jest.unmock('@google-cloud/storage');
    jest.requireActual('@google-cloud/storage');
  }

  function cancelFsMock() {
    jest.unmock('fs');
    jest.requireActual('fs');
  }

  afterEach(() => {
    jest.clearAllMocks();
    //jest.restoreAllMocks();
  });
  test('test for uploadfiles - success', async (done) => {
    cancelFsMock();
    pump().on = jest.fn(function(this: any, event, callback) {
      if (event === 'finish') {
        callback();
      }
      return this;
    });
    const actual = await BucketOperations.uploadEnvFiles('dev');

    expect(actual).toEqual(
      expect.objectContaining({
        status: 'Success',
        code: 201,
      })
    );
    done();
  });


  test('test downloadEnvFiles  - success', async (done) => {
    jest.unmock('fs');

    const fMock = (File.prototype.constructor = jest.fn().mockImplementation(() => {
      return {
        storage: new Storage(),
        bucket: 'testBucket',
        acl: 'test-acl',
        name: 'dev.txt',
        parent: 'parent bucket',
      };
    }));

    const bucketGetFilMock = (Bucket.prototype.getFiles = jest.fn().mockImplementation(() => {
      return [fMock];
    }));

    // Get files should be an array of File from google-cloud-storage
    //Bucket.prototype.getFiles = jest.fn().mockReturnValue([mockedFsConstructor]);

    //Storage.prototype.bucket = jest.fn().mockReturnValue(new Storage());

    const mockReadable = new PassThrough();
    const mockWritable = new PassThrough();

    jest.spyOn(fs, 'createReadStream').mockReturnValue(
      fs.createWriteStream(path.resolve(process.cwd(), './tests/cloud-storage/sample-read.txt'))
    );
    await BucketOperations.downloadEnvFiles('dev');

    done();
  });
});

Это исключение, которое я заканчиваю. После отладки я вижу, что проверенные экземпляры пытаются выполнить, но он не выполняет файловый метод в хранилище. Это недоступно в @ google-cloud / storage, но я пытался это сделать. Есть ли способ издеваться только над использованием google-cloud / storage с помощью jest?

РЕДАКТИРОВАТЬ: Вот исключение:

TypeError: str.bucket(...).file is not a function

    at /home/vijaykumar/Documents/Code/Nestjs/cloud-storage-app/src/gcloud/bucket.operations.ts:37:6
    at Generator.next (<anonymous>)
    at /home/vijaykumar/Documents/Code/Nestjs/cloud-storage-app/src/gcloud/bucket.operations.ts:8:71
    at new Promise (<anonymous>)
    at Object.<anonymous>.__awaiter (/home/vijaykumar/Documents/Code/Nestjs/cloud-storage-app/src/gcloud/bucket.operations.ts:4:12)
    at /home/vijaykumar/Documents/Code/Nestjs/cloud-storage-app/src/gcloud/bucket.operations.ts:22:40
    at new Promise (<anonymous>)
    at /home/vijaykumar/Documents/Code/Nestjs/cloud-storage-app/src/gcloud/bucket.operations.ts:22:9

1 Ответ

1 голос
/ 15 апреля 2020

Благодаря @ralemos. Мне удалось найти ответ о том, как я издевался. Вот полная реализация.

Я также добавил еще несколько тестовых историй

Так что jest.mock () esp the @google Модули -cloud / storage, должны быть по-другому смоделированы. Bucket of the Storage содержит все подробности о файлах в gcp-хранилище, поэтому сначала нужно смоделировать, я также высмеивал файл (это тип @ google-cloud / storage). Теперь я добавил mockedFile в mockedBucket и оттуда в mockedStorage. Я также добавил все методы и свойства и реализовал макет для всех из них.

В моем тестовом файле есть использование loda sh node_module, поэтому я также высмеял эту реализацию. Теперь все отлично работает.

import { GcloudAuthenticationInstance } from '../common/services/gcloud.authentication';
const { Storage } = require('@google-cloud/storage');
const fs = require('fs');
import * as path from 'path';
import pump from 'pump';
import * as BucketOperations from './bucket.operations';
const { PassThrough } = require('stream');
const fsMock = jest.mock('fs');

const mockedFile = {
  name: 'dev.txt',
  createWriteStream: jest.fn().mockImplementation(() => {
    return fs.createWriteStream(path.resolve(process.cwd(), './tests/cloud-storage/sample-write.txt'));
  }),
  createReadStream: jest.fn().mockImplementation(() => {
    return fs.createReadStream(path.resolve(process.cwd(), './tests/cloud-storage/sample-read.txt'));
  }),
};
jest.mock('lodash', () => {
  return {
    find: jest.fn().mockImplementation(() => {
      return mockedFile;
    })
  };

});
const mockedBucket = {
  file: jest.fn(() => mockedFile),
  getFiles: jest.fn().mockImplementation(() => {
    const fileArray = new Array();
    fileArray.push(mockedFile);
    return fileArray;
  })
};

const mockedStorage = {
  bucket: jest.fn(() => mockedBucket)
};


jest.mock('@google-cloud/storage', () => {
  return {
    Storage: jest.fn(() => mockedStorage)
  };
});

jest.mock('pump', () => {
  const mPump = { on: jest.fn() };
  return jest.fn(() => mPump);
});

describe('Test suite for testing bucket operations', () => {

  function cancelCloudStorageMock() {
    jest.unmock('@google-cloud/storage');
    jest.requireActual('@google-cloud/storage');
  }

  function cancelFsMock() {
    jest.unmock('fs');
    jest.requireActual('fs');
  }

  afterEach(() => {
    jest.clearAllMocks();
    //jest.restoreAllMocks();
  });
  test('test for uploadfiles - success', async (done) => {

    pump().on = jest.fn(function(this: any, event, callback) {
      if (event === 'finish') {
        callback();
      }
      return this;
    });
    const actual = await BucketOperations.uploadEnvFiles('dev');

    expect(actual).toEqual(
      expect.objectContaining({
        status: 'Success',
        code: 201,
      })
    );
    done();
  });


  test('test downloadEnvFiles  - success', async (done) => {
    jest.unmock('fs');
    const downloadRes =  await BucketOperations.downloadEnvFiles('dev');
    expect(downloadRes).toBeDefined();
    expect(downloadRes).toEqual(expect.objectContaining({code:200, status: 'Success'}));
    done();
  });

  test('test for uploadfiles- failure', async (done) => {
    cancelCloudStorageMock();
    const bucketStorageSpy = jest
      .spyOn(GcloudAuthenticationInstance, 'createGcloudAuthenticationBucket')
      .mockImplementation(() => {
        return new Storage({
          projectId: 'testId',
          keyFilename: path.resolve(process.cwd(), './tests/cloud-storage/sample-read.txt'),
          scopes: ['testScope'],
          autoRetry: false,
        });
      });

    const mockReadable = new PassThrough();
    const mockWritable = new PassThrough();
    fs.createWriteStream = jest.fn().mockReturnValue(mockWritable);
    fs.createReadStream = jest.fn().mockReturnValue(mockReadable);
    pump().on = jest.fn(function(this: any, event, callback) {
      if (event === 'error') {
        callback();
      }
      return this;
    });
    const actual = BucketOperations.uploadEnvFiles('prod');
    expect(actual).rejects.toEqual(
      expect.objectContaining({
        status: 'Error',
        code: 500,
      })
    );
    expect(bucketStorageSpy).toHaveBeenCalledTimes(1);
    done();
  });

  test('test download - make the actual call - rej with auth error', async (done) => {
    cancelCloudStorageMock();
    console.dir(Storage);
    const mockReadable = new PassThrough();
    const mockWritable = new PassThrough();
    fs.createWriteStream = jest.fn().mockReturnValue(mockWritable);
    fs.createReadStream = jest.fn().mockReturnValue(mockReadable);
    const createGcloudAuthenticationBucketSpy = jest
      .spyOn(GcloudAuthenticationInstance, 'createGcloudAuthenticationBucket')
      .mockImplementation(() => {
        return new Storage();
      });
    try {
      await BucketOperations.downloadEnvFiles('dev');
    } catch (err) {
      expect(err.code).toBe(500);
      expect(err.status).toBe('Error');
    }

    expect(createGcloudAuthenticationBucketSpy).toHaveBeenCalledTimes(1);
    createGcloudAuthenticationBucketSpy.mockReset();
    done();
  });
});
...