Skip to content

Commit

Permalink
Check if preview can be generated for mime type
Browse files Browse the repository at this point in the history
  • Loading branch information
bischofmax committed Nov 13, 2023
1 parent 8925810 commit b51dc03
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DeepMocked, createMock } from '@golevelup/ts-jest';
import { Test, TestingModule } from '@nestjs/testing';
import { GetFile, S3ClientAdapter } from '@infra/s3-client';
import { UnprocessableEntityException } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { Logger } from '@src/core/logger';
import { Readable } from 'node:stream';
import { PreviewGeneratorService } from './preview-generator.service';
Expand All @@ -16,13 +17,13 @@ jest.mock('gm', () => {
};
});

const createFile = (contentRange?: string): GetFile => {
const createFile = (contentRange?: string, contentType?: string): GetFile => {
const text = 'testText';
const readable = Readable.from(text);

const fileResponse = {
data: readable,
contentType: 'image/jpeg',
contentType,
contentLength: text.length,
contentRange,
etag: 'testTag',
Expand Down Expand Up @@ -68,76 +69,136 @@ describe('PreviewGeneratorService', () => {
});

describe('generatePreview', () => {
const setup = (width = 500) => {
const params = {
originFilePath: 'file/test.jpeg',
previewFilePath: 'preview/text.webp',
previewOptions: {
format: 'webp',
width,
},
};
const originFile = createFile();
s3ClientAdapter.get.mockResolvedValueOnce(originFile);
describe('WHEN download of original and preview file is successful', () => {
describe('WHEN preview is possible', () => {
const setup = (width = 500) => {
const params = {
originFilePath: 'file/test.jpeg',
previewFilePath: 'preview/text.webp',
previewOptions: {
format: 'webp',
width,
},
};
const originFile = createFile(undefined, 'image/jpeg');
s3ClientAdapter.get.mockResolvedValueOnce(originFile);

const data = Readable.from('text');
streamMock.mockReturnValueOnce(data);
const data = Readable.from('text');
streamMock.mockReturnValueOnce(data);

const expectedFileData = {
data,
mimeType: params.previewOptions.format,
};
const expectedFileData = {
data,
mimeType: params.previewOptions.format,
};

return { params, originFile, expectedFileData };
};
return { params, originFile, expectedFileData };
};

describe('WHEN download of original and preview file is successful', () => {
it('should call storageClient get method with originFilePath', async () => {
const { params } = setup();
it('should call storageClient get method with originFilePath', async () => {
const { params } = setup();

await service.generatePreview(params);
await service.generatePreview(params);

expect(s3ClientAdapter.get).toBeCalledWith(params.originFilePath);
});
expect(s3ClientAdapter.get).toBeCalledWith(params.originFilePath);
});

it('should call imagemagicks resize method', async () => {
const { params } = setup();
it('should call imagemagicks resize method', async () => {
const { params } = setup();

await service.generatePreview(params);
await service.generatePreview(params);

expect(resizeMock).toHaveBeenCalledWith(params.previewOptions.width, undefined, '>');
expect(resizeMock).toHaveBeenCalledTimes(1);
});
expect(resizeMock).toHaveBeenCalledWith(params.previewOptions.width, undefined, '>');
expect(resizeMock).toHaveBeenCalledTimes(1);
});

it('should call imagemagicks stream method', async () => {
const { params } = setup();
it('should call imagemagicks stream method', async () => {
const { params } = setup();

await service.generatePreview(params);
await service.generatePreview(params);

expect(streamMock).toHaveBeenCalledWith(params.previewOptions.format);
expect(streamMock).toHaveBeenCalledTimes(1);
});
expect(streamMock).toHaveBeenCalledWith(params.previewOptions.format);
expect(streamMock).toHaveBeenCalledTimes(1);
});

it('should call S3ClientAdapters create method', async () => {
const { params, expectedFileData } = setup();
it('should call S3ClientAdapters create method', async () => {
const { params, expectedFileData } = setup();

await service.generatePreview(params);
await service.generatePreview(params);

expect(s3ClientAdapter.create).toHaveBeenCalledWith(params.previewFilePath, expectedFileData);
expect(s3ClientAdapter.create).toHaveBeenCalledTimes(1);
});
expect(s3ClientAdapter.create).toHaveBeenCalledWith(params.previewFilePath, expectedFileData);
expect(s3ClientAdapter.create).toHaveBeenCalledTimes(1);
});

it('should should return values', async () => {
const { params } = setup();
const expectedValue = { previewFilePath: params.previewFilePath, status: true };
it('should should return values', async () => {
const { params } = setup();
const expectedValue = { previewFilePath: params.previewFilePath, status: true };

const result = await service.generatePreview(params);
const result = await service.generatePreview(params);

expect(result).toEqual(expectedValue);
expect(result).toEqual(expectedValue);
});
});

describe('WHEN preview is not possible', () => {
const setup = (mimeType?: string, width = 500) => {
const params = {
originFilePath: 'file/test.jpeg',
previewFilePath: 'preview/text.webp',
previewOptions: {
format: 'webp',
width,
},
};
const originFile = createFile(undefined, mimeType);
s3ClientAdapter.get.mockResolvedValueOnce(originFile);

return { params, originFile };
};

describe('WHEN mimeType is undefined', () => {
it('should throw UnprocessableEntityException', async () => {
const { params } = setup();

const error = new UnprocessableEntityException();
await expect(service.generatePreview(params)).rejects.toThrowError(error);
});
});

describe('WHEN mimeType is text/plain ', () => {
it('should throw UnprocessableEntityException', async () => {
const { params } = setup('text/plain');

const error = new UnprocessableEntityException();
await expect(service.generatePreview(params)).rejects.toThrowError(error);
});
});
});
});

describe('WHEN previewParams.width not set', () => {
const setup = (width = 500) => {
const params = {
originFilePath: 'file/test.jpeg',
previewFilePath: 'preview/text.webp',
previewOptions: {
format: 'webp',
width,
},
};
const originFile = createFile(undefined, 'image/jpeg');
s3ClientAdapter.get.mockResolvedValueOnce(originFile);

const data = Readable.from('text');
streamMock.mockReturnValueOnce(data);

const expectedFileData = {
data,
mimeType: params.previewOptions.format,
};

return { params, originFile, expectedFileData };
};

it('should not call imagemagicks resize method', async () => {
const { params } = setup(0);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GetFile, S3ClientAdapter } from '@infra/s3-client';
import { Injectable } from '@nestjs/common';
import { Injectable, UnprocessableEntityException } from '@nestjs/common';
import { Logger } from '@src/core/logger';
import { subClass } from 'gm';
import { PassThrough } from 'stream';
Expand All @@ -20,6 +20,9 @@ export class PreviewGeneratorService {
const { originFilePath, previewFilePath, previewOptions } = params;

const original = await this.downloadOriginFile(originFilePath);

this.checkIfPreviewPossible(original, params);

const preview = this.resizeAndConvert(original, previewOptions);

const file = PreviewGeneratorBuilder.buildFile(preview, params.previewOptions);
Expand All @@ -34,6 +37,16 @@ export class PreviewGeneratorService {
};
}

private checkIfPreviewPossible(original: GetFile, params: PreviewFileOptions): void | UnprocessableEntityException {
const isPreviewPossible =
original.contentType && Object.values<string>(PreviewInputMimeTypes).includes(original.contentType);

if (!isPreviewPossible) {
this.logger.warning(new PreviewActionsLoggable('PreviewGeneratorService.previewNotPossible', params));
throw new UnprocessableEntityException();
}
}

private async downloadOriginFile(pathToFile: string): Promise<GetFile> {
const file = await this.storageClient.get(pathToFile);

Expand Down

0 comments on commit b51dc03

Please sign in to comment.