Add tests for error reporting

This commit is contained in:
Taras
2021-02-15 21:52:54 -05:00
parent ef5a18a9f9
commit 4d483cbc10
3 changed files with 141 additions and 76 deletions
@@ -14,6 +14,10 @@
* limitations under the License.
*/
import fs from 'fs';
import type {
BlobUploadCommonResponse,
ContainerGetPropertiesResponse,
} from '@azure/storage-blob';
export class BlockBlobClient {
private readonly blobName;
@@ -22,23 +26,29 @@ export class BlockBlobClient {
this.blobName = blobName;
}
uploadFile(source: string) {
return new Promise((resolve, reject) => {
if (!fs.existsSync(source)) {
reject('');
} else {
resolve('');
}
uploadFile(source: string): Promise<BlobUploadCommonResponse> {
return Promise.resolve({
_response: {
request: {} as any,
status: 200,
headers: {} as any,
},
});
}
exists() {
return new Promise((resolve, reject) => {
if (fs.existsSync(this.blobName)) {
resolve(true);
} else {
reject({ message: 'The object doest not exist !' });
}
return Promise.resolve(fs.existsSync(this.blobName));
}
}
class BlockBlobClientFailUpload extends BlockBlobClient {
uploadFile(source: string): Promise<BlobUploadCommonResponse> {
return Promise.resolve({
_response: {
request: {} as any,
status: 500,
headers: {} as any,
},
});
}
}
@@ -50,9 +60,14 @@ export class ContainerClient {
this.containerName = containerName;
}
getProperties() {
return new Promise(resolve => {
resolve('');
getProperties(): Promise<ContainerGetPropertiesResponse> {
return Promise.resolve({
_response: {
request: {} as any,
status: 200,
headers: {} as any,
parsedHeaders: {},
},
});
}
@@ -61,6 +76,25 @@ export class ContainerClient {
}
}
class ContainerClientFailGetProperties extends ContainerClient {
getProperties(): Promise<ContainerGetPropertiesResponse> {
return Promise.resolve({
_response: {
request: {} as any,
status: 404,
headers: {} as any,
parsedHeaders: {},
},
});
}
}
class ContainerClientFailUpload extends ContainerClient {
getBlockBlobClient(blobName: string) {
return new BlockBlobClientFailUpload(blobName);
}
}
export class BlobServiceClient {
private readonly url;
private readonly credential;
@@ -71,6 +105,12 @@ export class BlobServiceClient {
}
getContainerClient(containerName: string) {
if (containerName === 'bad_container') {
return new ContainerClientFailGetProperties(containerName);
}
if (this.credential.accountName === 'failupload') {
return new ContainerClientFailUpload(containerName);
}
return new ContainerClient(containerName);
}
}
@@ -154,51 +154,71 @@ describe('publishing with valid credentials', () => {
});
});
describe('attempting to publish with invalid credentials', () => {
let logger: Logger;
describe('accountKey is not specified', () => {
beforeEach(async () => {
const mockConfig = new ConfigReader({
techdocs: {
requestUrl: 'http://localhost:7000',
publisher: {
type: 'azureBlobStorage',
azureBlobStorage: {
credentials: {
accountName: 'accountName',
},
containerName: 'containerName',
describe('error reporting', () => {
it('reports an error when unable to read container properties', async () => {
const mockConfig = new ConfigReader({
techdocs: {
requestUrl: 'http://localhost:7000',
publisher: {
type: 'azureBlobStorage',
azureBlobStorage: {
credentials: {
accountName: 'accountName',
},
containerName: 'bad_container',
},
},
});
logger = createLogger();
publisher = await AzureBlobStoragePublish.fromConfig(mockConfig, logger);
},
});
describe('without Azure environment variables', () => {
it('should log an error', async () => {
const entity = createMockEntity();
const entityRootDir = getEntityRootDir(entity);
const logger = createLogger();
mockFs({
[entityRootDir]: {
'index.html': '',
publisher = await AzureBlobStoragePublish.fromConfig(mockConfig, logger);
expect(logger.error).toHaveBeenCalledWith(
`Could not read Azure Blob Storage container properties`,
);
});
it('reports an error when bad account credentials', async () => {
const mockConfig = new ConfigReader({
techdocs: {
requestUrl: 'http://localhost:7000',
publisher: {
type: 'azureBlobStorage',
azureBlobStorage: {
credentials: {
accountName: 'failupload',
accountKey: 'accountKey',
},
containerName: 'containerName',
},
});
await publisher.publish({
entity,
directory: entityRootDir,
});
expect(logger.error).toHaveBeenCalled();
mockFs.restore();
});
},
},
});
const logger = createLogger();
publisher = await AzureBlobStoragePublish.fromConfig(mockConfig, logger);
const entity = createMockEntity();
const entityRootDir = getEntityRootDir(entity);
mockFs({
[entityRootDir]: {
'index.html': '',
},
});
await publisher.publish({
entity,
directory: entityRootDir,
});
expect(logger.error).toHaveBeenCalledWith(
`Unable to upload 1 file(s) to Azure Blob Storage.`,
);
mockFs.restore();
});
});
@@ -82,10 +82,16 @@ export class AzureBlobStoragePublish implements PublisherBase {
await storageClient
.getContainerClient(containerName)
.getProperties()
.then(() => {
logger.info(
`Successfully connected to the Azure Blob Storage container ${containerName}.`,
);
.then(result => {
if (result?._response?.status >= 400) {
logger.error(
'Could not read Azure Blob Storage container properties',
);
} else {
logger.info(
`Successfully connected to the Azure Blob Storage container ${containerName}.`,
);
}
})
.catch(reason => {
logger.error(
@@ -145,16 +151,23 @@ export class AzureBlobStoragePublish implements PublisherBase {
});
});
await Promise.all(promises).then(() => {
let responses: BlobUploadCommonResponse[] = [];
responses = await Promise.all(promises);
const failed = responses.filter(r => r?._response?.status >= 400);
if (failed.length === 0) {
this.logger.info(
`Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${allFilesToUpload.length}`,
);
});
return;
} else {
const errorMessage = `Unable to upload ${failed.length} file(s) to Azure Blob Storage.`;
this.logger.error(errorMessage);
}
} catch (e) {
const errorMessage = `Unable to upload file(s) to Azure Blob Storage. Error ${e.message}`;
this.logger.error(errorMessage);
throw new Error(errorMessage);
return;
}
}
@@ -237,19 +250,11 @@ export class AzureBlobStoragePublish implements PublisherBase {
* A helper function which checks if index.html of an Entity's docs site is available. This
* can be used to verify if there are any pre-generated docs available to serve.
*/
async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {
return new Promise(resolve => {
const entityRootDir = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;
this.storageClient
.getContainerClient(this.containerName)
.getBlockBlobClient(`${entityRootDir}/index.html`)
.exists()
.then((response: boolean) => {
resolve(response);
})
.catch(() => {
resolve(false);
});
});
hasDocsBeenGenerated(entity: Entity): Promise<boolean> {
const entityRootDir = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;
return this.storageClient
.getContainerClient(this.containerName)
.getBlockBlobClient(`${entityRootDir}/index.html`)
.exists();
}
}