diff --git a/plugins/techdocs-node/__mocks__/aws-sdk.ts b/plugins/techdocs-node/__mocks__/aws-sdk.ts deleted file mode 100644 index ebb3c6840b..0000000000 --- a/plugins/techdocs-node/__mocks__/aws-sdk.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { EventEmitter } from 'events'; -import { ReadStream } from 'fs'; -import { IStorageFilesMock } from '../src/testUtils/types'; - -export { Credentials } from 'aws-sdk'; - -const storage = global.storageFilesMock as IStorageFilesMock; - -export class S3 { - constructor() { - storage.emptyFiles(); - } - - headObject({ Key }: { Key: string }) { - return { - promise: async () => { - if (!storage.fileExists(Key)) { - throw new Error('File does not exist'); - } - }, - }; - } - - getObject({ Key }: { Key: string }) { - return { - promise: async () => storage.fileExists(Key), - createReadStream: () => { - const emitter = new EventEmitter(); - process.nextTick(() => { - if (storage.fileExists(Key)) { - emitter.emit('data', Buffer.from(storage.readFile(Key))); - emitter.emit('end'); - } else { - emitter.emit('error', new Error(`The file ${Key} does not exist!`)); - } - }); - return emitter; - }, - }; - } - - headBucket({ Bucket }) { - return { - promise: async () => { - if (Bucket === 'errorBucket') { - throw new Error('Bucket does not exist'); - } - return {}; - }, - }; - } - - upload({ Key, Body }: { Key: string; Body: ReadStream }) { - return { - promise: () => - new Promise(async resolve => { - const chunks = []; - Body.on('data', chunk => { - chunks.push(chunk); - }); - Body.once('end', () => { - storage.writeFile(Key, Buffer.concat(chunks)); - resolve(null); - }); - }), - }; - } - - listObjectsV2({ Bucket }) { - return { - promise: () => { - if ( - Bucket === 'delete_stale_files_success' || - Bucket === 'delete_stale_files_error' - ) { - return Promise.resolve({ - Contents: [{ Key: 'stale_file.png' }], - }); - } - return Promise.resolve({}); - }, - }; - } - - deleteObject({ Bucket }) { - return { - promise: () => { - if (Bucket === 'delete_stale_files_error') { - throw new Error('Message'); - } - return Promise.resolve(); - }, - }; - } -} - -export default { - S3, -}; diff --git a/plugins/techdocs-node/src/stages/publish/awsS3.test.ts b/plugins/techdocs-node/src/stages/publish/awsS3.test.ts index 537fc52b27..6372093c4b 100644 --- a/plugins/techdocs-node/src/stages/publish/awsS3.test.ts +++ b/plugins/techdocs-node/src/stages/publish/awsS3.test.ts @@ -21,12 +21,112 @@ import express from 'express'; import request from 'supertest'; import mockFs from 'mock-fs'; import path from 'path'; -import fs from 'fs-extra'; +import fs, { ReadStream } from 'fs-extra'; +import { EventEmitter } from 'events'; import { AwsS3Publish } from './awsS3'; +import { storageRootDir } from '../../testUtils/StorageFilesMock'; -// NOTE: /plugins/techdocs-node/__mocks__ is being used to mock aws-sdk client library +jest.mock('aws-sdk', () => { + const { StorageFilesMock } = require('../../testUtils/StorageFilesMock'); + const storage = new StorageFilesMock(); -const rootDir = (global as any).rootDir; // Set by setupTests.ts + return { + __esModule: true, + Credentials: jest.requireActual('aws-sdk').Credentials, + default: { + S3: class { + constructor() { + storage.emptyFiles(); + } + + headObject({ Key }: { Key: string }) { + return { + promise: async () => { + if (!storage.fileExists(Key)) { + throw new Error('File does not exist'); + } + }, + }; + } + + getObject({ Key }: { Key: string }) { + return { + promise: async () => storage.fileExists(Key), + createReadStream: () => { + const emitter = new EventEmitter(); + process.nextTick(() => { + if (storage.fileExists(Key)) { + emitter.emit('data', Buffer.from(storage.readFile(Key))); + emitter.emit('end'); + } else { + emitter.emit( + 'error', + new Error(`The file ${Key} does not exist!`), + ); + } + }); + return emitter; + }, + }; + } + + headBucket({ Bucket }: { Bucket: string }) { + return { + promise: async () => { + if (Bucket === 'errorBucket') { + throw new Error('Bucket does not exist'); + } + return {}; + }, + }; + } + + upload({ Key, Body }: { Key: string; Body: ReadStream }) { + return { + promise: () => + new Promise(async resolve => { + const chunks = new Array(); + Body.on('data', chunk => { + chunks.push(chunk as Buffer); + }); + Body.once('end', () => { + storage.writeFile(Key, Buffer.concat(chunks)); + resolve(null); + }); + }), + }; + } + + listObjectsV2({ Bucket }: { Bucket: string }) { + return { + promise: () => { + if ( + Bucket === 'delete_stale_files_success' || + Bucket === 'delete_stale_files_error' + ) { + return Promise.resolve({ + Contents: [{ Key: 'stale_file.png' }], + }); + } + return Promise.resolve({}); + }, + }; + } + + deleteObject({ Bucket }: { Bucket: string }) { + return { + promise: () => { + if (Bucket === 'delete_stale_files_error') { + throw new Error('Message'); + } + return Promise.resolve(); + }, + }; + } + }, + }, + }; +}); const getEntityRootDir = (entity: Entity) => { const { @@ -34,7 +134,7 @@ const getEntityRootDir = (entity: Entity) => { metadata: { namespace, name }, } = entity; - return path.join(rootDir, namespace || DEFAULT_NAMESPACE, kind, name); + return path.join(storageRootDir, namespace || DEFAULT_NAMESPACE, kind, name); }; const logger = getVoidLogger(); @@ -213,7 +313,7 @@ describe('AwsS3Publish', () => { it('should fail to publish a directory', async () => { const wrongPathToGeneratedDirectory = path.join( - rootDir, + storageRootDir, 'wrong', 'path', 'to', diff --git a/plugins/techdocs-node/src/testUtils/StorageFilesMock.ts b/plugins/techdocs-node/src/testUtils/StorageFilesMock.ts index 4a0e183bdb..dd28110d00 100644 --- a/plugins/techdocs-node/src/testUtils/StorageFilesMock.ts +++ b/plugins/techdocs-node/src/testUtils/StorageFilesMock.ts @@ -19,12 +19,13 @@ import path from 'path'; import fs from 'fs-extra'; import { IStorageFilesMock } from './types'; -const rootDir: string = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir'; +export const storageRootDir: string = + os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir'; const encoding = 'utf8'; export class StorageFilesMock implements IStorageFilesMock { - static rootDir = rootDir; + static rootDir = storageRootDir; private files: Record; @@ -37,20 +38,20 @@ export class StorageFilesMock implements IStorageFilesMock { } public fileExists(targetPath: string): boolean { - const filePath = path.join(rootDir, targetPath); + const filePath = path.join(storageRootDir, targetPath); const posixPath = filePath.split(path.posix.sep).join(path.sep); return this.files[posixPath] !== undefined; } public readFile(targetPath: string): Buffer { - const filePath = path.join(rootDir, targetPath); + const filePath = path.join(storageRootDir, targetPath); return Buffer.from(this.files[filePath] ?? '', encoding); } public writeFile(targetPath: string, sourcePath: string): void; public writeFile(targetPath: string, sourceBuffer: Buffer): void; public writeFile(targetPath: string, source: string | Buffer): void { - const filePath = path.join(rootDir, targetPath); + const filePath = path.join(storageRootDir, targetPath); if (typeof source === 'string') { this.files[filePath] = fs.readFileSync(source).toString(encoding); } else {