UNPKG

@contract-case/case-core

Version:

Core functionality for the ContractCase contract testing suite

124 lines 6.71 kB
"use strict"; 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