Merge pull request #4567 from viavarejo/techdocs-azure-tests
This commit is contained in:
@@ -17,11 +17,13 @@ import type {
|
||||
BlobUploadCommonResponse,
|
||||
ContainerGetPropertiesResponse,
|
||||
} from '@azure/storage-blob';
|
||||
import { EventEmitter } from 'events';
|
||||
import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
const rootDir = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir';
|
||||
|
||||
/**
|
||||
* @param sourceFile Relative path to entity root dir. Contains either / or \ as file separator
|
||||
* depending upon the OS.
|
||||
@@ -48,6 +50,9 @@ export class BlockBlobClient {
|
||||
}
|
||||
|
||||
uploadFile(source: string): Promise<BlobUploadCommonResponse> {
|
||||
if (!fs.existsSync(source)) {
|
||||
return Promise.reject(new Error(`The file ${source} does not exist`));
|
||||
}
|
||||
return Promise.resolve({
|
||||
_response: {
|
||||
request: {
|
||||
@@ -62,6 +67,25 @@ export class BlockBlobClient {
|
||||
exists() {
|
||||
return checkFileExists(this.blobName);
|
||||
}
|
||||
|
||||
download() {
|
||||
const filePath = path.join(rootDir, this.blobName);
|
||||
const emitter = new EventEmitter();
|
||||
process.nextTick(() => {
|
||||
if (fs.existsSync(filePath)) {
|
||||
emitter.emit('data', Buffer.from(fs.readFileSync(filePath)));
|
||||
emitter.emit('end');
|
||||
} else {
|
||||
emitter.emit(
|
||||
'error',
|
||||
new Error(`The file ${filePath} does not exist !`),
|
||||
);
|
||||
}
|
||||
});
|
||||
return Promise.resolve({
|
||||
readableStreamBody: emitter,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class BlockBlobClientFailUpload extends BlockBlobClient {
|
||||
|
||||
@@ -14,13 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';
|
||||
import {
|
||||
Entity,
|
||||
EntityName,
|
||||
ENTITY_DEFAULT_NAMESPACE,
|
||||
} from '@backstage/catalog-model';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import mockFs from 'mock-fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { AzureBlobStoragePublish } from './azureBlobStorage';
|
||||
import { PublisherBase } from './types';
|
||||
import { PublisherBase, TechDocsMetadata } from './types';
|
||||
|
||||
// NOTE: /packages/techdocs-common/__mocks__ is being used to mock Azure client library
|
||||
|
||||
@@ -38,7 +42,14 @@ const createMockEntity = (annotations = {}) => {
|
||||
};
|
||||
};
|
||||
|
||||
const createMockEntityName = (): EntityName => ({
|
||||
kind: 'TestKind',
|
||||
name: 'test-component-name',
|
||||
namespace: 'test-namespace',
|
||||
});
|
||||
|
||||
const rootDir = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir';
|
||||
|
||||
const getEntityRootDir = (entity: Entity) => {
|
||||
const {
|
||||
kind,
|
||||
@@ -163,6 +174,72 @@ describe('publishing with valid credentials', () => {
|
||||
expect(await publisher.hasDocsBeenGenerated(entity)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchTechDocsMetadata', () => {
|
||||
it('should return tech docs metadata', async () => {
|
||||
const entityNameMock = createMockEntityName();
|
||||
const entity = createMockEntity();
|
||||
const entityRootDir = getEntityRootDir(entity);
|
||||
|
||||
mockFs({
|
||||
[entityRootDir]: {
|
||||
'techdocs_metadata.json':
|
||||
'{"site_name": "backstage", "site_description": "site_content"}',
|
||||
},
|
||||
});
|
||||
const expectedMetadata: TechDocsMetadata = {
|
||||
site_name: 'backstage',
|
||||
site_description: 'site_content',
|
||||
};
|
||||
expect(
|
||||
await publisher.fetchTechDocsMetadata(entityNameMock),
|
||||
).toStrictEqual(expectedMetadata);
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it('should return tech docs metadata when json encoded with single quotes', async () => {
|
||||
const entityNameMock = createMockEntityName();
|
||||
const entity = createMockEntity();
|
||||
const entityRootDir = getEntityRootDir(entity);
|
||||
|
||||
mockFs({
|
||||
[entityRootDir]: {
|
||||
'techdocs_metadata.json': `{'site_name': 'backstage', 'site_description': 'site_content'}`,
|
||||
},
|
||||
});
|
||||
|
||||
const expectedMetadata: TechDocsMetadata = {
|
||||
site_name: 'backstage',
|
||||
site_description: 'site_content',
|
||||
};
|
||||
expect(
|
||||
await publisher.fetchTechDocsMetadata(entityNameMock),
|
||||
).toStrictEqual(expectedMetadata);
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it('should return an error if the techdocs_metadata.json file is not present', async () => {
|
||||
const entityNameMock = createMockEntityName();
|
||||
const entity = createMockEntity();
|
||||
const entityRootDir = getEntityRootDir(entity);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await publisher.fetchTechDocsMetadata(entityNameMock);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
expect(error).toEqual(
|
||||
new Error(
|
||||
`TechDocs metadata fetch failed, The file ${path.join(
|
||||
entityRootDir,
|
||||
'techdocs_metadata.json',
|
||||
)} does not exist !`,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('error reporting', () => {
|
||||
@@ -255,4 +332,63 @@ describe('error reporting', () => {
|
||||
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
describe('fetchTechDocsMetadata', () => {
|
||||
it('should return tech docs metadata', async () => {
|
||||
const entityNameMock = createMockEntityName();
|
||||
const entity = createMockEntity();
|
||||
const entityRootDir = getEntityRootDir(entity);
|
||||
|
||||
mockFs({
|
||||
[entityRootDir]: {
|
||||
'techdocs_metadata.json':
|
||||
'{"site_name": "backstage", "site_description": "site_content"}',
|
||||
},
|
||||
});
|
||||
const expectedMetadata: TechDocsMetadata = {
|
||||
site_name: 'backstage',
|
||||
site_description: 'site_content',
|
||||
};
|
||||
expect(
|
||||
await publisher.fetchTechDocsMetadata(entityNameMock),
|
||||
).toStrictEqual(expectedMetadata);
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it('should return tech docs metadata when json encoded with single quotes', async () => {
|
||||
const entityNameMock = createMockEntityName();
|
||||
const entity = createMockEntity();
|
||||
const entityRootDir = getEntityRootDir(entity);
|
||||
|
||||
mockFs({
|
||||
[entityRootDir]: {
|
||||
'techdocs_metadata.json': `{'site_name': 'backstage', 'site_description': 'site_content'}`,
|
||||
},
|
||||
});
|
||||
|
||||
const expectedMetadata: TechDocsMetadata = {
|
||||
site_name: 'backstage',
|
||||
site_description: 'site_content',
|
||||
};
|
||||
expect(
|
||||
await publisher.fetchTechDocsMetadata(entityNameMock),
|
||||
).toStrictEqual(expectedMetadata);
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it('should return an error if the techdocs_metadata.json file is not present', async () => {
|
||||
const entityNameMock = createMockEntityName();
|
||||
|
||||
let error;
|
||||
try {
|
||||
await publisher.fetchTechDocsMetadata(entityNameMock);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
expect(error.message).toEqual(
|
||||
expect.stringContaining('TechDocs metadata fetch'),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -201,10 +201,7 @@ export class AzureBlobStoragePublish implements PublisherBase {
|
||||
return;
|
||||
}
|
||||
body
|
||||
.on('error', e => {
|
||||
this.logger.error(e.message);
|
||||
reject(e.message);
|
||||
})
|
||||
.on('error', reject)
|
||||
.on('data', chunk => {
|
||||
fileStreamChunks.push(chunk);
|
||||
})
|
||||
@@ -220,16 +217,21 @@ export class AzureBlobStoragePublish implements PublisherBase {
|
||||
): Promise<TechDocsMetadata> {
|
||||
const entityRootDir = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;
|
||||
try {
|
||||
return await new Promise<TechDocsMetadata>(resolve => {
|
||||
const download = this.download(
|
||||
this.containerName,
|
||||
`${entityRootDir}/techdocs_metadata.json`,
|
||||
const techdocsMetadataJson = await this.download(
|
||||
this.containerName,
|
||||
`${entityRootDir}/techdocs_metadata.json`,
|
||||
);
|
||||
if (!techdocsMetadataJson) {
|
||||
throw new Error(
|
||||
`Unable to parse the techdocs metadata file ${entityRootDir}/techdocs_metadata.json.`,
|
||||
);
|
||||
resolve(JSON5.parse(download.toString()));
|
||||
});
|
||||
}
|
||||
const techdocsMetadata = JSON5.parse(
|
||||
techdocsMetadataJson.toString('utf-8'),
|
||||
);
|
||||
return techdocsMetadata;
|
||||
} catch (e) {
|
||||
this.logger.error(e.message);
|
||||
throw e;
|
||||
throw new Error(`TechDocs metadata fetch failed, ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user