diff --git a/.github/workflows/reference-implementation.yml b/.github/workflows/reference-implementation.yml
index b59bc537c9..230fde8402 100644
--- a/.github/workflows/reference-implementation.yml
+++ b/.github/workflows/reference-implementation.yml
@@ -8,7 +8,7 @@ on:
jobs:
tests:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
@@ -98,7 +98,7 @@ jobs:
# Master branch only
if: ${{ github.ref == 'refs/heads/master' }}
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
# Checkout the repo to seed the contents of ./tests/publish/
diff --git a/config/default.json b/config/default.json
index 514120bf6a..b487b8baee 100644
--- a/config/default.json
+++ b/config/default.json
@@ -61,6 +61,7 @@
"dataset-site": true,
"availability-check": true,
"common-error-conditions": true,
+ "past-opportunities": true,
"amending-order-quote": true,
"order-deletion": true,
"agent-broker": true,
diff --git a/packages/openactive-broker-microservice/package-lock.json b/packages/openactive-broker-microservice/package-lock.json
index 8b35913088..f53168f7d7 100644
--- a/packages/openactive-broker-microservice/package-lock.json
+++ b/packages/openactive-broker-microservice/package-lock.json
@@ -12,7 +12,7 @@
"@openactive/data-model-validator": "^2.0.83",
"@openactive/data-models": "^2.0.318",
"@openactive/dataset-utils": "^1.0.1",
- "@openactive/harvesting-utils": "github:openactive/harvesting-utils#1b2877834055549572fa059a491ac17d306942fd",
+ "@openactive/harvesting-utils": "^0.1.2",
"@openactive/openactive-openid-browser-automation": "file:../openactive-openid-browser-automation",
"@openactive/openactive-openid-client": "file:../openactive-openid-client",
"@openactive/rpde-validator": "^2.0.20",
@@ -14724,10 +14724,9 @@
}
},
"node_modules/@openactive/harvesting-utils": {
- "version": "0.1.0",
- "resolved": "git+ssh://git@github.com/openactive/harvesting-utils.git#1b2877834055549572fa059a491ac17d306942fd",
- "integrity": "sha512-jjT4kad88PKp/JXDBOjkD47KCradEu6KmvNIfWKsHh2q6mfQHP5NIrWZreeeWkVlOO1t++lZESGpbmPfnopXmg==",
- "license": "MIT",
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@openactive/harvesting-utils/-/harvesting-utils-0.1.2.tgz",
+ "integrity": "sha512-IiuR+xeKihV0HFci857pea36btPIFo+QZj/EEouhwpUWmgt+dhRvpM4/OAhAa9aguChOHwXQ43HzInjfD2HoGw==",
"dependencies": {
"@openactive/rpde-validator": "^2.0.19",
"axios": "^1.6.7",
diff --git a/packages/openactive-integration-tests/test/features/README.md b/packages/openactive-integration-tests/test/features/README.md
index e77d79c14e..2d60821e66 100644
--- a/packages/openactive-integration-tests/test/features/README.md
+++ b/packages/openactive-integration-tests/test/features/README.md
@@ -14,7 +14,7 @@ The tests for these features cover all known edge cases, including both happy an
| core | AgentBroker mode ([agent-broker](./core/agent-broker/README.md)) | Required
[View Spec](https://www.openactive.io/open-booking-api/EditorsDraft/#agentbroker) | Support for AgentBroker mode | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x8 | |
| core | Amending the OrderQuote before B ([amending-order-quote](./core/amending-order-quote/README.md)) | Required
[View Spec](https://www.openactive.io/open-booking-api/EditorsDraft/#amending-the-orderquote-before-b) | Allows the basket to be updated for a particular order | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x32 | |
| core | Availability Checking ([availability-check](./core/availability-check/README.md)) | Required
[View Spec](https://www.openactive.io/open-booking-api/EditorsDraft/#step-by-step-process-description-0) | Runs only C1 and C2, to confirm availability checks work as expected | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x5, [TestOpportunityBookableNoSpaces](https://openactive.io/test-interface#TestOpportunityBookableNoSpaces) x3 | |
-| core | Common error conditions ([common-error-conditions](./core/common-error-conditions/README.md)) | Required
[View Spec](https://openactive.io/open-booking-api/EditorsDraft/#error-model) | Tests C1, C2 and B for common error conditions applicable to all implementations | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x29, [TestOpportunityBookableInPast](https://openactive.io/test-interface#TestOpportunityBookableInPast) x3 | |
+| core | Common error conditions ([common-error-conditions](./core/common-error-conditions/README.md)) | Required
[View Spec](https://openactive.io/open-booking-api/EditorsDraft/#error-model) | Tests C1, C2 and B for common error conditions applicable to all implementations | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x28 | |
| core | Dataset Site ([dataset-site](./core/dataset-site/README.md)) | Required
[View Spec](https://www.openactive.io/open-booking-api/EditorsDraft/#endpoints) | Discoverable open data | | |
| core | Order Deletion Endpoint ([order-deletion](./core/order-deletion/README.md)) | Required
[View Spec](https://www.openactive.io/open-booking-api/EditorsDraft/#order-deletion) | Check that Order Deletion correctly soft-deletes an Order that has already been emitted in the Orders feed | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x12 | [SellerRequestedCancellationSimulateAction](https://openactive.io/test-interface#SellerRequestedCancellationSimulateAction) |
| access | accessChannel - Seller provided remote access ([access-channel](./access/access-channel/README.md)) | Optional
[View Spec](https://github.com/openactive/open-booking-api/issues/176) | For online opportunities, an accessChannel (or a customerNotice indicating that an accessChannel will be sent soon) is provided upon booking with B | [TestOpportunityOnlineBookable](https://openactive.io/test-interface#TestOpportunityOnlineBookable) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1 | |
@@ -37,6 +37,7 @@ The tests for these features cover all known edge cases, including both happy an
| cancellation | cancellationMessage for Seller Requested Cancellation ([seller-requested-cancellation-message](./cancellation/seller-requested-cancellation-message/README.md)) | Optional
[View Spec](https://www.openactive.io/open-booking-api/EditorsDraft/#seller-requested-cancellation) | A message associated with a Cancellation triggered by the Seller through the Booking System | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x4 | [SellerRequestedCancellationWithMessageSimulateAction](https://openactive.io/test-interface#SellerRequestedCancellationWithMessageSimulateAction) |
| cancellation | Seller Requested Replacement ([seller-requested-replacement](./cancellation/seller-requested-replacement/README.md)) | Optional
[View Spec](https://www.openactive.io/open-booking-api/EditorsDraft/#cancellation-replacement-refund-calculation-and-notification) | Replacement triggered by the Seller through the Booking System | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x4 | [ReplacementSimulateAction](https://openactive.io/test-interface#ReplacementSimulateAction) |
| core | Multiple Sellers ([multiple-sellers](./core/multiple-sellers/README.md)) | Optional
[View Spec](https://openactive.io/open-booking-api/EditorsDraft/#booking-pre-conditions) | The booking system is multi-tenanted and provides services to multiple sellers. | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x6 | |
+| core | Past opportunities ([past-opportunities](./core/past-opportunities/README.md)) | Optional
[View Spec](https://openactive.io/open-booking-api/EditorsDraft/#error-model) | For booking systems that support opportunities in the past, ensure that these are not bookable | [TestOpportunityBookableInPast](https://openactive.io/test-interface#TestOpportunityBookableInPast) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1 | |
| core | Single Seller ([single-seller](./core/single-seller/README.md)) | Optional
[View Spec](https://openactive.io/open-booking-api/EditorsDraft/#booking-pre-conditions) | The booking system only supports providing services to one seller. | | |
| core | Test interface ([test-interface](./core/test-interface/README.md)) | Optional
[View Spec](https://openactive.io/test-interface/) | Open Booking API Test Interface implementation | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1 | |
| details-capture | Additional Details capture ([additional-details-capture](./details-capture/additional-details-capture/README.md)) | Optional
[View Spec](https://www.openactive.io/open-booking-api/EditorsDraft/#additional-details-capture) | Support for capturing additional details with required set to true | [TestOpportunityBookableAdditionalDetails](https://openactive.io/test-interface#TestOpportunityBookableAdditionalDetails) x9, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x3 | |
diff --git a/packages/openactive-integration-tests/test/features/categories.json b/packages/openactive-integration-tests/test/features/categories.json
index b91bf324b5..8f884c6b90 100644
--- a/packages/openactive-integration-tests/test/features/categories.json
+++ b/packages/openactive-integration-tests/test/features/categories.json
@@ -10,6 +10,7 @@
"order-deletion": true,
"multiple-sellers": true,
"opportunity-feed": true,
+ "past-opportunities": true,
"single-seller": true,
"test-interface": true
},
diff --git a/packages/openactive-integration-tests/test/features/core/common-error-conditions/README.md b/packages/openactive-integration-tests/test/features/core/common-error-conditions/README.md
index dbaa7fc926..0cbd7907b9 100644
--- a/packages/openactive-integration-tests/test/features/core/common-error-conditions/README.md
+++ b/packages/openactive-integration-tests/test/features/core/common-error-conditions/README.md
@@ -10,7 +10,7 @@ Coverage Status: **complete**
### Test prerequisites - Opportunities
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) x29, [TestOpportunityBookableInPast](https://openactive.io/test-interface#TestOpportunityBookableInPast) x3
+[TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x28
@@ -40,7 +40,6 @@ This feature is **required** by the Open Booking API specification, and so must
| [incomplete-customer-details](./implemented/incomplete-customer-details-test.js) | Expect an IncompleteCustomerDetailsError when customer details are missing the required email property | Run each of C2 and B for a valid opportunity, with customer details missing the required email property, expecting an IncompleteCustomerDetailsError to be returned (C1 is ignored because customer details are not accepted for C1) | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x8 | |
| [incomplete-order-item-no-offer](./implemented/incomplete-order-item-no-offer-test.js) | Test for IncompleteOrderItemError with missing `acceptedOffer` | Test for IncompleteOrderItemError (at C1, C2 and B). If there is a missing `acceptedOffer` property on the OrderItem. | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x4 | |
| [incomplete-order-item-no-opportunity](./implemented/incomplete-order-item-no-opportunity-test.js) | Test for IncompleteOrderItemError with missing `orderedItem` | Test for IncompleteOrderItemError (at C1, C2 and B). If there is a missing `orderedItem` property on the OrderItem. | [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x4 | |
-| [opportunity-in-past](./implemented/opportunity-in-past-test.js) | Expect an OpportunityOfferPairNotBookableError when opportunity is in the past | Runs C1, C2 and B for an opportunity in the past, expecting an OpportunityOfferPairNotBookableError to be returned at C1, C2, and B | [TestOpportunityBookableInPast](https://openactive.io/test-interface#TestOpportunityBookableInPast) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1 | |
| [unknown-endpoint](./implemented/unknown-endpoint-test.js) | Expect an UnknownOrIncorrectEndpointError for requests to unknown endpoints | Send a request to an endpoint that does not exist, and expect an UnknownOrIncorrectEndpointError to be returned | | |
diff --git a/packages/openactive-integration-tests/test/features/core/past-opportunities/README.md b/packages/openactive-integration-tests/test/features/core/past-opportunities/README.md
new file mode 100644
index 0000000000..bdf6af5caa
--- /dev/null
+++ b/packages/openactive-integration-tests/test/features/core/past-opportunities/README.md
@@ -0,0 +1,58 @@
+[< Return to Overview](../../README.md)
+# Past opportunities (past-opportunities)
+
+For booking systems that support opportunities in the past, ensure that these are not bookable
+
+
+https://openactive.io/open-booking-api/EditorsDraft/#error-model
+
+Coverage Status: **complete**
+### Test prerequisites - Opportunities
+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`.
+
+[TestOpportunityBookableInPast](https://openactive.io/test-interface#TestOpportunityBookableInPast) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1
+
+
+
+### Running tests for only this feature
+
+```bash
+npm start -- --runInBand test/features/core/past-opportunities/
+```
+
+
+
+## 'Implemented' tests
+
+Update `default.json` within `packages/openactive-integration-tests/config/` as follows to enable 'Implemented' testing for this feature:
+
+```json
+"implementedFeatures": {
+ ...
+ "past-opportunities": true,
+ ...
+}
+```
+
+| Identifier | Name | Description | Prerequisites per Opportunity Type | Required Test Interface Actions |
+|------------|------|-------------|---------------|-------------------|
+| [opportunity-in-past](./implemented/opportunity-in-past-test.js) | Expect an OpportunityOfferPairNotBookableError when opportunity is in the past | Runs C1, C2 and B for an opportunity in the past, expecting an OpportunityOfferPairNotBookableError to be returned at C1, C2, and B | [TestOpportunityBookableInPast](https://openactive.io/test-interface#TestOpportunityBookableInPast) x3, [TestOpportunityBookable](https://openactive.io/test-interface#TestOpportunityBookable) x1 | |
+
+
+
+## 'Not Implemented' tests
+
+
+Update `default.json` within `packages/openactive-integration-tests/config/` as follows to enable 'Not Implemented' testing for this feature:
+
+```json
+"implementedFeatures": {
+ ...
+ "past-opportunities": false,
+ ...
+}
+```
+
+| Identifier | Name | Description | Prerequisites per Opportunity Type | Required Test Interface Actions |
+|------------|------|-------------|---------------|-------------------|
+| [no-past-opportunities](./not-implemented/no-past-opportunities-test.js) | The open data feeds must not contain any opportunities with `startDate` in the past | Assert that no opportunities that match criteria 'TestOpportunityBookableInPast' are available in the opportunity feeds. | | |
diff --git a/packages/openactive-integration-tests/test/features/core/past-opportunities/feature.json b/packages/openactive-integration-tests/test/features/core/past-opportunities/feature.json
new file mode 100644
index 0000000000..080831f507
--- /dev/null
+++ b/packages/openactive-integration-tests/test/features/core/past-opportunities/feature.json
@@ -0,0 +1,10 @@
+{
+ "category": "core",
+ "identifier": "past-opportunities",
+ "name": "Past opportunities",
+ "description": "For booking systems that support opportunities in the past, ensure that these are not bookable",
+ "explainer": "",
+ "specificationReference": "https://openactive.io/open-booking-api/EditorsDraft/#error-model",
+ "required": false,
+ "coverageStatus": "complete"
+}
\ No newline at end of file
diff --git a/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/opportunity-in-past-test.js b/packages/openactive-integration-tests/test/features/core/past-opportunities/implemented/opportunity-in-past-test.js
similarity index 98%
rename from packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/opportunity-in-past-test.js
rename to packages/openactive-integration-tests/test/features/core/past-opportunities/implemented/opportunity-in-past-test.js
index c0648ae205..638985eb77 100644
--- a/packages/openactive-integration-tests/test/features/core/common-error-conditions/implemented/opportunity-in-past-test.js
+++ b/packages/openactive-integration-tests/test/features/core/past-opportunities/implemented/opportunity-in-past-test.js
@@ -9,7 +9,7 @@ const { itShouldIncludeErrorForOnlyPrimaryOrderItems } = require('../../../../sh
FeatureHelper.describeFeature(module, {
testCategory: 'core',
- testFeature: 'common-error-conditions',
+ testFeature: 'past-opportunities',
testFeatureImplemented: true,
testIdentifier: 'opportunity-in-past',
testName: 'Expect an OpportunityOfferPairNotBookableError when opportunity is in the past',
diff --git a/packages/openactive-integration-tests/test/features/core/past-opportunities/not-implemented/no-past-opportunities-test.js b/packages/openactive-integration-tests/test/features/core/past-opportunities/not-implemented/no-past-opportunities-test.js
new file mode 100644
index 0000000000..595cfaadfd
--- /dev/null
+++ b/packages/openactive-integration-tests/test/features/core/past-opportunities/not-implemented/no-past-opportunities-test.js
@@ -0,0 +1,12 @@
+const { FeatureHelper } = require('../../../../helpers/feature-helper');
+
+FeatureHelper.describeUnmatchedCriteriaFeature(module, {
+ testCategory: 'core',
+ testFeature: 'past-opportunities',
+ testFeatureImplemented: false,
+ testIdentifier: 'no-past-opportunities',
+ testName: 'The open data feeds must not contain any opportunities with `startDate` in the past',
+ unmatchedOpportunityCriteria: [
+ 'TestOpportunityBookableInPast',
+ ],
+});
diff --git a/packages/openactive-integration-tests/test/features/feature-requirements.json b/packages/openactive-integration-tests/test/features/feature-requirements.json
index d5d53eaa83..5f0d27c317 100644
--- a/packages/openactive-integration-tests/test/features/feature-requirements.json
+++ b/packages/openactive-integration-tests/test/features/feature-requirements.json
@@ -29,8 +29,7 @@
"common-error-conditions": {
"criteriaRequirements": {
"primary": {
- "TestOpportunityBookable": 29,
- "TestOpportunityBookableInPast": 3
+ "TestOpportunityBookable": 28
}
},
"testInterfaceActionImplementationRequirements": []
@@ -245,6 +244,15 @@
"criteriaRequirements": {},
"testInterfaceActionImplementationRequirements": []
},
+ "past-opportunities": {
+ "criteriaRequirements": {
+ "primary": {
+ "TestOpportunityBookableInPast": 3,
+ "TestOpportunityBookable": 1
+ }
+ },
+ "testInterfaceActionImplementationRequirements": []
+ },
"single-seller": {
"criteriaRequirements": {},
"testInterfaceActionImplementationRequirements": []
diff --git a/packages/openactive-integration-tests/test/features/tests-implemented.json b/packages/openactive-integration-tests/test/features/tests-implemented.json
index e976c6929f..4c2cb3b4c0 100644
--- a/packages/openactive-integration-tests/test/features/tests-implemented.json
+++ b/packages/openactive-integration-tests/test/features/tests-implemented.json
@@ -14,7 +14,7 @@
"notImplementedTestFiles": 1
},
"common-error-conditions": {
- "implementedTestFiles": 6,
+ "implementedTestFiles": 5,
"notImplementedTestFiles": 1
},
"dataset-site": {
@@ -121,6 +121,10 @@
"implementedTestFiles": 0,
"notImplementedTestFiles": 0
},
+ "past-opportunities": {
+ "implementedTestFiles": 1,
+ "notImplementedTestFiles": 1
+ },
"single-seller": {
"implementedTestFiles": 1,
"notImplementedTestFiles": 1