@contract-case/case-core
Version:
Core functionality for the ContractCase contract testing suite
124 lines • 6.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReadingCaseContract = void 0;
const async_mutex_1 = require("async-mutex");
const case_plugin_base_1 = require("@contract-case/case-plugin-base");
const BaseCaseContract_1 = require("./BaseCaseContract");
const executeExample_1 = require("./executeExample");
const entities_1 = require("../entities");
class ReadingCaseContract extends BaseCaseContract_1.BaseCaseContract {
mutex;
makeBrokerService;
links;
status;
contractClosed = false;
/**
* Constructs a ReadingCaseContract
*
* @param contractFile - The DownloadedContract to verify
* @param readerDependencies - The dependencies for a contract reader (injected)
* @param config - the CaseConfig for this run
* @param parentVersions - the array of versions of all the ContractCase packages before this one
*/
constructor(contractFile, { resultFormatter: resultPrinter, makeLogger, defaultConfig, makeBrokerService, }, config, parentVersions) {
super(contractFile.description, { throwOnFail: false, testRunId: 'VERIFIER', ...config }, defaultConfig, resultPrinter, makeLogger, parentVersions);
this.currentContract = contractFile;
this.makeBrokerService = makeBrokerService;
this.links = contractFile;
this.status = 'UNKNOWN';
this.mutex = new async_mutex_1.Mutex();
}
callExecuteExample(index, invoker, completionCallback = () => { }) {
if (this.contractClosed) {
throw new case_plugin_base_1.CaseConfigurationError('Unable to write more interactions to the contract after endRecord() has been called', this.initialContext, 'UNDOCUMENTED');
}
return this.mutex.runExclusive(() => Promise.resolve()
.then(() => {
const example = this.currentContract.examples[index];
if (example == null) {
this.initialContext.logger.error(`Somehow the example at index ${index} was undefined. This shouldn't happen, as calls to this function are meant to be based off the indexes. Examples follow:`, this.currentContract.examples);
throw new case_plugin_base_1.CaseCoreError(`Somehow the example at index ${index} was undefined. This is a bug, please see the log for details.`);
}
if (example.result !== 'VERIFIED') {
throw new case_plugin_base_1.CaseCoreError(`Attempting to verify an interaction which didn't pass the consumer test ('${example.result}'). This should never happen in normal operation, and might be the result of a corrupted ContractCase file, a file that was not written by ContractCase, or a bug.`);
}
const names = (0, entities_1.exampleToNames)(example, `${index}`);
// Set running context instead of inlining this, so that
// stripMatchers etc have access to the context
this.runningContext = (0, case_plugin_base_1.applyNodeToContext)(example.mock, this.initialContext, {
'_case:currentRun:context:testName': `${index}`,
'_case:currentRun:context:contractMode': 'read',
'_case:currentRun:context:location': [
'verification',
`interaction[${index}]`,
],
});
this.initialContext.logger.maintainerDebug(`Run test callback for ${names.mockName}`);
return (0, executeExample_1.executeExample)({ ...example, result: 'PENDING' }, {
...invoker,
names,
}, this, this.runningContext);
})
.finally(() => {
try {
completionCallback();
}
catch (e) {
this.runningContext.logger.error(`BUG: Error in completion callback: ${e.message}`, e);
}
}));
}
/**
* Gets the tests that can be used later to verify the contract
*
* @param invoker - The invoker for this test
* @returns a list of {@link ContractVerificationTest}s that can be run later
* with the `runTest` callback on the ContractVerificationTest
*/
getTests(invoker) {
this.initialContext.logger.maintainerDebug(`Generating tests for contract: '${this.currentContract.description.consumerName}' -> '${this.currentContract.description.providerName}'`);
this.initialContext.logger.maintainerDebug(`This contract has ${this.currentContract.examples.length} interactions`);
return this.currentContract.examples.map((example, index) => {
const names = (0, entities_1.exampleToNames)(example, `${index}`);
this.initialContext.logger.maintainerDebug(`Preparing test framework's callback for: ${names.mockName} `);
let isPending = true;
return {
index,
testName: names.mockName,
isPending: () => isPending,
runTest: () => this.callExecuteExample(index, invoker, () => {
isPending = false;
}),
};
});
}
recordExample(example, currentContext) {
currentContext.logger.deepMaintainerDebug(`recordExample called with`, example);
if (example.result === 'FAILED') {
currentContext.logger.maintainerDebug(`Interaction was a failure, marking verification failed (was '${this.status}')`);
this.status = 'FAILED';
}
else {
currentContext.logger.maintainerDebug(`Interaction was a success, no change to current status of '${this.status}'`);
}
return example;
}
async endRecord() {
this.contractClosed = true;
const publishingContext = (0, case_plugin_base_1.addLocation)('PublishingResults', this.initialContext);
if (this.status === 'UNKNOWN') {
this.status = 'SUCCESS';
}
if (this.status === 'FAILED') {
// TODO: Print all failures
this.initialContext.logger.maintainerDebug('Verification failed');
}
else {
this.initialContext.logger.maintainerDebug('Verification successful');
}
this.initialContext.logger.maintainerDebug('Calling publishVerificationResults');
await this.makeBrokerService(publishingContext).publishVerificationResults(this.links, this.status === 'SUCCESS', (0, case_plugin_base_1.addLocation)(`PublishingVerification(${this.currentContract.description.consumerName} -> ${this.currentContract.description.providerName})`, this.initialContext));
}
}
exports.ReadingCaseContract = ReadingCaseContract;
//# sourceMappingURL=ReadingCaseContract.js.map