Skip to content

Commit

Permalink
Merge branch 'master' into coverage/opportunity-outside-range-c1-c2
Browse files Browse the repository at this point in the history
  • Loading branch information
nickevansuk committed Oct 16, 2020
2 parents cfb11bc + 52cb2d8 commit 57b9e23
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 5 deletions.
16 changes: 13 additions & 3 deletions packages/openactive-broker-microservice/app.js
Expand Up @@ -28,6 +28,13 @@ const DISABLE_BROKER_TIMEOUT = config.has('disableBrokerMicroserviceTimeout') ?

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

class FatalError extends Error {
constructor(message) {
super(message);
this.name = 'FatalError';
}
}

const app = express();

// eslint-disable-next-line no-console
Expand Down Expand Up @@ -156,7 +163,10 @@ async function harvestRPDE(baseUrl, feedIdentifier, headers, processPage) {
url = json.next;
}
} catch (error) {
if (!error.response) {
if (error instanceof FatalError) {
// If a fatal error, just rethrow
throw error;
} else if (!error.response) {
log(`Error for RPDE feed "${url}": ${error.message}.\n${error.stack}`);
// Force retry, after a delay
await sleep(5000);
Expand Down Expand Up @@ -262,11 +272,11 @@ function setFeedIsUpToDate(feedIdentifier) {
if (totalChildren === 0) {
logError('\nFATAL ERROR: Zero opportunities could be harvested from the opportunities feeds.');
logError('Please ensure that the opportunities feeds conforms to RPDE using https://validator.openactive.io/rpde.\n');
throw new Error('Zero opportunities could be harvested from the opportunities feeds');
throw new FatalError('Zero opportunities could be harvested from the opportunities feeds');
} else if (childOrphans === totalChildren) {
logError(`\nFATAL ERROR: 100% of the ${totalChildren} harvested opportunities do not have a matching parent item from the parent feed, so all integration tests will fail.`);
logError('Please ensure that the value of the `subEvent` or `facilityUse` property in each opportunity exactly matches an `@id` from the parent feed.\n');
throw new Error('100% of the harvested opportunities do not have a matching parent item from the parent feed');
throw new FatalError('100% of the harvested opportunities do not have a matching parent item from the parent feed');
} else if (childOrphans > 0) {
logError(`\nWARNING: ${childOrphans} of ${totalChildren} opportunities (${percentageChildOrphans}%) do not have a matching parent item from the parent feed.`);
logError('Please ensure that the value of the `subEvent` or `facilityUse` property in each opportunity exactly matches an `@id` from the parent feed.\n');
Expand Down
2 changes: 1 addition & 1 deletion packages/openactive-integration-tests/config/default.json
Expand Up @@ -23,7 +23,7 @@
"amending-order-quote": true,
"simple-book-free-opportunities": true,
"order-deletion": null,
"agent-broker": null,
"agent-broker": true,
"simple-book-with-payment": true,
"multiple-sellers": true,
"payment-reconciliation-detail-validation": null,
Expand Down
Expand Up @@ -12,7 +12,7 @@ See also: [.NET Tutorial](https://tutorials.openactive.io/open-booking-sdk/quick
### Test prerequisites
Opportunities that match the following criteria must exist in the booking system (for each configured `bookableOpportunityTypesInScope`) for the configured primary Seller in order to use `useRandomOpportunities: true`. Alternatively the following `testOpportunityCriteria` values must be supported by the [test interface](https://openactive.io/test-interface/) of the booking system for `useRandomOpportunities: false`.

[TestOpportunityBookableCancellable](https://openactive.io/test-interface#TestOpportunityBookableCancellable) x1
[TestOpportunityBookableCancellable](https://openactive.io/test-interface#TestOpportunityBookableCancellable) x3


### Running tests for only this feature
Expand All @@ -38,6 +38,8 @@ Update `default.json` within `packages/openactive-integration-tests/config/` as
| Identifier | Name | Description | Prerequisites per Opportunity Type |
|------------|------|-------------|---------------|
| [book-and-cancel](./implemented/book-and-cancel-test.js) | Successful booking and cancellation. | A successful end to end booking including cancellation, including checking the Orders Feed. | [TestOpportunityBookableCancellable](https://openactive.io/test-interface#TestOpportunityBookableCancellable) x1 |
| [cancellation-not-permitted-error](./implemented/cancellation-not-permitted-error-test.js) | Successful booking and cancellation. | A successful end to end booking including cancellation, including checking the Orders Feed. | [TestOpportunityBookableCancellable](https://openactive.io/test-interface#TestOpportunityBookableCancellable) x1 |
| [patch-contains-excessive-properties-error](./implemented/patch-contains-excessive-properties-error-test.js) | Successful booking and unsuccessful cancellation due to PatchContainsExcessiveProperties error | PatchContainsExcessivePropertiesError returned because patch request includes other properties than @type, @context, orderProposalStatus and orderCustomerNote | [TestOpportunityBookableCancellable](https://openactive.io/test-interface#TestOpportunityBookableCancellable) x1 |
| [unknown-order](./implemented/unknown-order-test.js) | Expect a UnknownOrderError for an Order that does not exist | Runs Order Cancellation for a non-existent Order (with a fictional UUID), expecting an UnknownOrderError error to be returned | |


@@ -0,0 +1,84 @@
/* eslint-disable no-unused-vars */
const chakram = require('chakram');
const { RequestState } = require('../../../../helpers/request-state');
const { FlowHelper } = require('../../../../helpers/flow-helper');
const { FeatureHelper } = require('../../../../helpers/feature-helper');
const { GetMatch, C1, C2, B } = require('../../../../shared-behaviours');
const { itShouldReturnAnOpenBookingError } = require('../../../../shared-behaviours/errors');

const { expect } = chakram;
/* eslint-enable no-unused-vars */

FeatureHelper.describeFeature(module, {
testCategory: 'cancellation',
testFeature: 'customer-requested-cancellation',
testFeatureImplemented: true,
testIdentifier: 'patch-contains-excessive-properties-error',
testName: 'Successful booking and unsuccessful cancellation due to PatchContainsExcessivePropertiesError',
testDescription: 'PatchContainsExcessivePropertiesError returned because patch request includes other properties than @type, @context, orderProposalStatus and orderCustomerNote',
// The primary opportunity criteria to use for the primary OrderItem under test
testOpportunityCriteria: 'TestOpportunityBookableCancellable',
// The secondary opportunity criteria to use for multiple OrderItem tests
controlOpportunityCriteria: 'TestOpportunityBookable',
// TODO: Refactor 'Orders Feed' tests so they work with multiple OrderItems
skipMultiple: true,
},
function (configuration, orderItemCriteria, featureIsImplemented, logger) {
const state = new RequestState(logger, { uReqTemplateRef: 'excessiveProperties' });
const flow = new FlowHelper(state);

beforeAll(async function () {
await state.fetchOpportunities(orderItemCriteria);

return chakram.wait();
});

afterAll(async function () {
await state.deleteOrder();
return chakram.wait();
});

describe('Get Opportunity Feed Items', function () {
(new GetMatch({
state, flow, logger, orderItemCriteria,
}))
.beforeSetup()
.successChecks()
.validationTests();
});

describe('C1', function () {
(new C1({
state, flow, logger,
}))
.beforeSetup()
.successChecks()
.validationTests();
});

describe('C2', function () {
(new C2({
state, flow, logger,
}))
.beforeSetup()
.successChecks()
.validationTests();
});

describe('B', function () {
(new B({
state, flow, logger,
}))
.beforeSetup()
.successChecks()
.validationTests();
});

describe('Orders Feed', function () {
beforeAll(async function () {
await flow.U();
});

itShouldReturnAnOpenBookingError('PatchContainsExcessivePropertiesError', 400, () => state.uResponse);
});
});
Expand Up @@ -7,11 +7,30 @@ Support for AgentBroker mode
https://www.openactive.io/open-booking-api/EditorsDraft/#agentbroker

Coverage Status: **none**
### Test prerequisites
Opportunities that match the following criteria must exist in the booking system (for each configured `bookableOpportunityTypesInScope`) for the configured primary Seller in order to use `useRandomOpportunities: true`. Alternatively the following `testOpportunityCriteria` values must be supported by the [test interface](https://openactive.io/test-interface/) of the booking system for `useRandomOpportunities: false`.

[TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x4

*Note the test coverage for this feature is currently nonexistent. The test suite does not yet include non-stubbed tests for this feature.*


## 'Implemented' tests

This feature is **required** by the Open Booking API specification, and so must always be set to `true` by `default.json` within `packages/openactive-integration-tests/config/`:

```json
"implementedFeatures": {
...
"agent-broker": true,
...
}
```

| Identifier | Name | Description | Prerequisites per Opportunity Type |
|------------|------|-------------|---------------|
| [customer-not-included](./implemented/customer-not-included-test.js) | Customer not included in Order in AgentBroker mode | If customer is not included in Order in AgentBroker mode for B request, request shoud fail, returning 400 status code and IncompleteCustomerDetailsError. | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x4 |



## 'Not Implemented' tests
Expand Down
@@ -0,0 +1,71 @@
/* eslint-disable no-unused-vars */
const chakram = require('chakram');
const { FeatureHelper } = require('../../../../helpers/feature-helper');
const { GetMatch, C1, C2, B } = require('../../../../shared-behaviours');
const { FlowHelper } = require('../../../../helpers/flow-helper');
const { RequestState } = require('../../../../helpers/request-state');
const { itShouldReturnAnOpenBookingError } = require('../../../../shared-behaviours/errors');

/* eslint-enable no-unused-vars */

FeatureHelper.describeFeature(module, {
testCategory: 'core',
testFeature: 'agent-broker',
testFeatureImplemented: true,
testIdentifier: 'customer-not-included',
testName: 'Customer not included in Order in AgentBroker mode',
testDescription: 'If customer is not included in Order in AgentBroker mode for B request, request shoud fail, returning 400 status code and IncompleteCustomerDetailsError.',
// The primary opportunity criteria to use for the primary OrderItem under test
testOpportunityCriteria: 'TestOpportunityBookable',
// The secondary opportunity criteria to use for multiple OrderItem tests
controlOpportunityCriteria: 'TestOpportunityBookable',
},
function (configuration, orderItemCriteria, featureIsImplemented, logger) {
const state = new RequestState(logger, { bReqTemplateRef: 'noCustomer' });
const flow = new FlowHelper(state);

describe('Booking should fail as Customer is not included in Order', () => {
beforeAll(async function () {
await state.fetchOpportunities(orderItemCriteria);
return chakram.wait();
});

describe('Get Opportunity Feed Items', () => {
(new GetMatch({
state, flow, logger, orderItemCriteria,
}))
.beforeSetup()
.successChecks()
.validationTests();
});

describe('C1', () => {
(new C1({
state, flow, logger,
}))
.beforeSetup()
.successChecks()
.validationTests();
});

describe('C2', function () {
(new C2({
state, flow, logger,
}))
.beforeSetup()
.successChecks()
.validationTests();
});

describe('B', function () {
(new B({
state, flow, logger,
}))
.beforeSetup()
.itResponseReceived()
.validationTests();

itShouldReturnAnOpenBookingError('IncompleteCustomerDetailsError', 400, () => state.bResponse);
});
});
});
11 changes: 11 additions & 0 deletions packages/openactive-integration-tests/test/templates/b-req.js
Expand Up @@ -210,6 +210,16 @@ function createIncorrectOrderDueToMissingIdentifierInPaymentProperty(data) {
return dissocPath(['payment', 'identifier'], req);
}

/**
* Paid B request without customer.
*
* @param {BReqTemplateData} data
*/
function createBReqWithoutCustomer(data) {
const req = createStandardPaidBReq(data);
return dissocPath(['customer'], req);
}

/**
* Template functions are put into this object so that the function can be
* referred to by its key e.g. `standardFree`
Expand All @@ -223,6 +233,7 @@ const bReqTemplates = {
incorrectTotalPaymentDuePrice: createIncorrectTotalPaymentDuePriceBReq,
incorrectOrderDueToMissingPaymentProperty: createIncorrectOrderDueToMissingPaymentProperty,
incorrectOrderDueToMissingIdentifierInPaymentProperty: createIncorrectOrderDueToMissingIdentifierInPaymentProperty,
noCustomer: createBReqWithoutCustomer,
};

/**
Expand Down
11 changes: 11 additions & 0 deletions packages/openactive-integration-tests/test/templates/u-req.js
Expand Up @@ -42,9 +42,20 @@ function createNonExistantOrderUReq(data) {
};
}

/**
* @param {UReqTemplateData} data
*/
function createUReqWithExcessiveProperties(data) {
return {
...createStandardUReq(data),
'@id': 'excessiveField',
};
}

const uReqTemplates = {
standard: createStandardUReq,
nonExistantOrder: createNonExistantOrderUReq,
excessiveProperties: createUReqWithExcessiveProperties,
};

/**
Expand Down

0 comments on commit 57b9e23

Please sign in to comment.