@dashevo/wasm-dpp 0.23.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +5 -0
- package/.editorconfig +13 -0
- package/.eslintignore +1 -0
- package/.eslintrc +15 -0
- package/.mocharc.yml +4 -0
- package/CHANGELOG.md +397 -0
- package/LICENSE +20 -0
- package/README.md +37 -0
- package/karma.conf.js +53 -0
- package/package.json +107 -0
- package/test/.eslintrc +12 -0
- package/test/integration/DashPlatformProtocol.spec.js +53 -0
- package/test/integration/ajv/keywords/byteArray/addByteArrayKeyword.spec.js +148 -0
- package/test/integration/dataContract/DataContractFacade.spec.js +84 -0
- package/test/integration/dataContract/stateTransition/DataContractCreateTransition/validation/basic/validateDataContractCreateTransitionBasicFactory.spec.js +357 -0
- package/test/integration/dataContract/stateTransition/DataContractUpdateTransition/validation/basic/validateDataContractUpdateTransitionBasicFactory.spec.js +444 -0
- package/test/integration/dataContract/validation/validateDataContractFactory.spec.js +2191 -0
- package/test/integration/document/Document.spec.js +90 -0
- package/test/integration/document/DocumentFacade.spec.js +155 -0
- package/test/integration/document/stateTransition/DocumentsBatchTransition/DocumentBatchTransition.spec.js +83 -0
- package/test/integration/document/stateTransition/DocumentsBatchTransition/validation/basic/validateDocumentsBatchTransitionBasicFactory.spec.js +1146 -0
- package/test/integration/document/stateTransition/DocumentsBatchTransition/validation/state/executeDataTriggersFactory.spec.js +294 -0
- package/test/integration/document/validation/validateDocumentFactory.spec.js +447 -0
- package/test/integration/error/consensus/createConsensusError.spec.js +21 -0
- package/test/integration/identity/IdentityFacade.spec.js +187 -0
- package/test/integration/identity/stateTransition/IdentityCreateTransition/validation/basic/validateIdentityCreateTransitionBasicFactory.spec.js +422 -0
- package/test/integration/identity/stateTransition/IdentityTopUpTransition/validation/basic/validateIdentityTopUpTransitionBasicFactory.spec.js +361 -0
- package/test/integration/identity/stateTransition/IdentityUpdateTransition/validation/basic/validateIdentityUpdateTransitionBasicFactory.spec.js +595 -0
- package/test/integration/identity/stateTransition/IdentityUpdateTransition/validation/state/validateIdentityUpdateTransitionStateFactory.spec.js +299 -0
- package/test/integration/identity/stateTransition/IdentityUpdateTransition/validation/state/validatePublicKeysState.spec.js +66 -0
- package/test/integration/identity/stateTransition/assetLockProof/chain/validateChainAssetLockProofStructureFactory.spec.js +415 -0
- package/test/integration/identity/stateTransition/assetLockProof/fetchAssetLockTransactionOutputFactory.spec.js +134 -0
- package/test/integration/identity/stateTransition/assetLockProof/instant/validateInstantAssetLockProofStructureFactory.spec.js +401 -0
- package/test/integration/identity/stateTransition/assetLockProof/validateAssetLockTransactionFactory.spec.js +205 -0
- package/test/integration/identity/stateTransition/validatePublicKeySignaturesFactory.spec.js +127 -0
- package/test/integration/identity/validation/validateIdentityFactory.spec.js +370 -0
- package/test/integration/identity/validation/validatePublicKeysFactory.spec.js +497 -0
- package/test/integration/stateTransition/AbstractStateTransitionIdentitySigned.spec.js +507 -0
- package/test/integration/stateTransition/StateTransitionFacade.spec.js +418 -0
- package/test/integration/stateTransition/calculateStateTransitionFee.spec.js +35 -0
- package/test/integration/util/generateEntropy.spec.js +17 -0
- package/test/integration/util/serializer.spec.js +24 -0
- package/test/unit/DashPlatformProtocol.spec.js +79 -0
- package/test/unit/Identifier.spec.js +123 -0
- package/test/unit/Metadata.spec.js +37 -0
- package/test/unit/dataContract/DataContract.spec.js +407 -0
- package/test/unit/dataContract/DataContractFactory.spec.js +178 -0
- package/test/unit/dataContract/createDataContract.spec.js +57 -0
- package/test/unit/dataContract/errors/InvalidDataContractError.spec.js +46 -0
- package/test/unit/dataContract/generateDataContractId.spec.js +19 -0
- package/test/unit/dataContract/getBinaryPropertiesFromSchema.spec.js +103 -0
- package/test/unit/dataContract/getPropertyDefinitionByPath.spec.js +84 -0
- package/test/unit/dataContract/stateTransition/DataContractCreateTransition/DataContractCreateTransition.spec.js +160 -0
- package/test/unit/dataContract/stateTransition/DataContractCreateTransition/applyDataContractCreateTransitionFactory.spec.js +48 -0
- package/test/unit/dataContract/stateTransition/DataContractCreateTransition/validation/state/validateDataContractCreateTransitionStateFactory.spec.js +85 -0
- package/test/unit/dataContract/stateTransition/DataContractUpdateTransition/DataContractUpdateTransition.spec.js +158 -0
- package/test/unit/dataContract/stateTransition/DataContractUpdateTransition/applyDataContractUpdateTransitionFactory.spec.js +47 -0
- package/test/unit/dataContract/stateTransition/DataContractUpdateTransition/validation/basic/validateIndicesAreBackwardCompatible.spec.js +121 -0
- package/test/unit/dataContract/stateTransition/DataContractUpdateTransition/validation/state/validateDataContractUpdateTransitionStateFactory.spec.js +111 -0
- package/test/unit/dataContract/validation/validateDataContractMaxDepthFactory.spec.js +93 -0
- package/test/unit/dataContract/validation/validateDataContractPatternsFactory.spec.js +64 -0
- package/test/unit/dataTrigger/DataTrigger.spec.js +132 -0
- package/test/unit/dataTrigger/DataTriggerExecutionContext.spec.js +29 -0
- package/test/unit/dataTrigger/dashpayDataTriggers/createContactRequestDataTrigger.spec.js +109 -0
- package/test/unit/dataTrigger/dpnsTriggers/createDomainDataTrigger.spec.js +382 -0
- package/test/unit/dataTrigger/featureFlagDataTriggers/createFeatureFlagDataTrigger.spec.js +101 -0
- package/test/unit/dataTrigger/getDataTriggersFactory.spec.js +113 -0
- package/test/unit/dataTrigger/rejectDataTrigger.spec.js +51 -0
- package/test/unit/dataTrigger/rewardShareDataTriggers/createMasternodeRewardSharesDataTrigger.spec.js +200 -0
- package/test/unit/decodeProtocolEntityFactory.spec.js +75 -0
- package/test/unit/document/Document.spec.js +444 -0
- package/test/unit/document/DocumentFactory.spec.js +376 -0
- package/test/unit/document/errors/InvalidDocumentError.spec.js +46 -0
- package/test/unit/document/fetchAndValidateDataContractFactory.spec.js +66 -0
- package/test/unit/document/stateTransition/DocumetsBatchTransition/DocumentsBatchTransition.spec.js +168 -0
- package/test/unit/document/stateTransition/DocumetsBatchTransition/applyDocumentsBatchTransitionFactory.spec.js +171 -0
- package/test/unit/document/stateTransition/DocumetsBatchTransition/documentTransition/DocumentCreateTransition.spec.js +25 -0
- package/test/unit/document/stateTransition/DocumetsBatchTransition/validation/basic/findDuplicatesById.spec.js +31 -0
- package/test/unit/document/stateTransition/DocumetsBatchTransition/validation/basic/findDuplicatesByIndices.spec.js +122 -0
- package/test/unit/document/stateTransition/DocumetsBatchTransition/validation/basic/validatePartialCompoundIndices.spec.js +75 -0
- package/test/unit/document/stateTransition/DocumetsBatchTransition/validation/state/fetchDocumentsFactory.spec.js +128 -0
- package/test/unit/document/stateTransition/DocumetsBatchTransition/validation/state/validateDocumentsBatchTransitionStateFactory.spec.js +811 -0
- package/test/unit/document/stateTransition/DocumetsBatchTransition/validation/state/validateDocumentsUniquenessByIndicesFactory.spec.js +279 -0
- package/test/unit/errors/consensus/codes.spec.js +102 -0
- package/test/unit/identity/Identity.spec.js +243 -0
- package/test/unit/identity/IdentityFactory.spec.js +274 -0
- package/test/unit/identity/IdentityPublicKey.spec.js +273 -0
- package/test/unit/identity/creditsConverter.spec.js +34 -0
- package/test/unit/identity/errors/InvalidIdentityError.spec.js +46 -0
- package/test/unit/identity/stateTransition/IdentityCreateTransition/IdentityCreateTransition.spec.js +184 -0
- package/test/unit/identity/stateTransition/IdentityCreateTransition/applyIdentityCreateTransitionFactory.spec.js +90 -0
- package/test/unit/identity/stateTransition/IdentityCreateTransition/validation/state/validateIdentityCreateTransitionStateFactory.spec.js +71 -0
- package/test/unit/identity/stateTransition/IdentityTopUpTransition/IdentityTopUpTransition.spec.js +137 -0
- package/test/unit/identity/stateTransition/IdentityTopUpTransition/applyIdentityTopUpTransitionFactory.spec.js +108 -0
- package/test/unit/identity/stateTransition/IdentityTopUpTransition/validation/state/validateIdentityTopUpTransitionStateFactory.spec.js +22 -0
- package/test/unit/identity/stateTransition/IdentityUpdateTransition/IdentityUpdateTransition.spec.js +219 -0
- package/test/unit/identity/stateTransition/IdentityUpdateTransition/applyIdentityUpdateTransitionFactory.spec.js +149 -0
- package/test/unit/identity/stateTransition/assetLockProof/createAssetLockProofInstance.spec.js +21 -0
- package/test/unit/identity/stateTransition/assetLockProof/fetchAssetLockPublicKeyHashFactory.spec.js +36 -0
- package/test/unit/identity/validation/validateRequiredPurposeAndSecurityLevelFactory.spec.js +47 -0
- package/test/unit/stateTransition/StateTransitionFactory.spec.js +160 -0
- package/test/unit/stateTransition/createStateTransitionFactory.spec.js +72 -0
- package/test/unit/stateTransition/errors/InvalidStateTransitionError.spec.js +51 -0
- package/test/unit/stateTransition/validation/validateStateTransitionBasicFactory.spec.js +138 -0
- package/test/unit/stateTransition/validation/validateStateTransitionFeeFactory.spec.js +372 -0
- package/test/unit/stateTransition/validation/validateStateTransitionIdentitySignatureFactory.spec.js +339 -0
- package/test/unit/stateTransition/validation/validateStateTransitionKeySignatureFactory.spec.js +86 -0
- package/test/unit/stateTransition/validation/validateStateTransitionStateFactory.spec.js +89 -0
- package/test/unit/version/validateProtocolVersionFactory.spec.js +80 -0
- package/webpack.config.js +49 -0
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
const validateDocumentsBatchTransitionStateFactory = require('../../../../../../../lib/document/stateTransition/DocumentsBatchTransition/validation/state/validateDocumentsBatchTransitionStateFactory');
|
|
2
|
+
|
|
3
|
+
const Document = require('../../../../../../../lib/document/Document');
|
|
4
|
+
const DocumentsBatchTransition = require('../../../../../../../lib/document/stateTransition/DocumentsBatchTransition/DocumentsBatchTransition');
|
|
5
|
+
|
|
6
|
+
const DataTriggerExecutionContext = require('../../../../../../../lib/dataTrigger/DataTriggerExecutionContext');
|
|
7
|
+
const DataTriggerExecutionError = require('../../../../../../../lib/errors/consensus/state/dataContract/dataTrigger/DataTriggerExecutionError');
|
|
8
|
+
const DataTriggerExecutionResult = require('../../../../../../../lib/dataTrigger/DataTriggerExecutionResult');
|
|
9
|
+
|
|
10
|
+
const getDataContractFixture = require('../../../../../../../lib/test/fixtures/getDataContractFixture');
|
|
11
|
+
const getDocumentsFixture = require('../../../../../../../lib/test/fixtures/getDocumentsFixture');
|
|
12
|
+
const getDocumentTransitionsFixture = require('../../../../../../../lib/test/fixtures/getDocumentTransitionsFixture');
|
|
13
|
+
const createStateRepositoryMock = require('../../../../../../../lib/test/mocks/createStateRepositoryMock');
|
|
14
|
+
|
|
15
|
+
const ValidationResult = require('../../../../../../../lib/validation/ValidationResult');
|
|
16
|
+
|
|
17
|
+
const { expectValidationError } = require('../../../../../../../lib/test/expect/expectError');
|
|
18
|
+
|
|
19
|
+
const DataContractNotPresentError = require('../../../../../../../lib/errors/DataContractNotPresentError');
|
|
20
|
+
|
|
21
|
+
const DocumentAlreadyPresentError = require('../../../../../../../lib/errors/consensus/state/document/DocumentAlreadyPresentError');
|
|
22
|
+
const DocumentNotFoundError = require('../../../../../../../lib/errors/consensus/state/document/DocumentNotFoundError');
|
|
23
|
+
const InvalidDocumentRevisionError = require('../../../../../../../lib/errors/consensus/state/document/InvalidDocumentRevisionError');
|
|
24
|
+
const InvalidDocumentActionError = require('../../../../../../../lib/document/errors/InvalidDocumentActionError');
|
|
25
|
+
const DocumentOwnerIdMismatchError = require('../../../../../../../lib/errors/consensus/state/document/DocumentOwnerIdMismatchError');
|
|
26
|
+
const DocumentTimestampsMismatchError = require('../../../../../../../lib/errors/consensus/state/document/DocumentTimestampsMismatchError');
|
|
27
|
+
const DocumentTimestampWindowViolationError = require('../../../../../../../lib/errors/consensus/state/document/DocumentTimestampWindowViolationError');
|
|
28
|
+
|
|
29
|
+
const generateRandomIdentifier = require('../../../../../../../lib/test/utils/generateRandomIdentifier');
|
|
30
|
+
const SomeConsensusError = require('../../../../../../../lib/test/mocks/SomeConsensusError');
|
|
31
|
+
const StateTransitionExecutionContext = require('../../../../../../../lib/stateTransition/StateTransitionExecutionContext');
|
|
32
|
+
|
|
33
|
+
describe('validateDocumentsBatchTransitionStateFactory', () => {
|
|
34
|
+
let validateDocumentsBatchTransitionState;
|
|
35
|
+
let fetchDocumentsMock;
|
|
36
|
+
let stateTransition;
|
|
37
|
+
let documents;
|
|
38
|
+
let dataContract;
|
|
39
|
+
let ownerId;
|
|
40
|
+
let validateDocumentsUniquenessByIndicesMock;
|
|
41
|
+
let stateRepositoryMock;
|
|
42
|
+
let executeDataTriggersMock;
|
|
43
|
+
let documentTransitions;
|
|
44
|
+
let abciHeader;
|
|
45
|
+
let fakeTime;
|
|
46
|
+
let blockTime;
|
|
47
|
+
let executionContext;
|
|
48
|
+
|
|
49
|
+
beforeEach(function beforeEach() {
|
|
50
|
+
dataContract = getDataContractFixture();
|
|
51
|
+
documents = getDocumentsFixture(dataContract);
|
|
52
|
+
ownerId = getDocumentsFixture.ownerId;
|
|
53
|
+
|
|
54
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
55
|
+
create: documents,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
stateTransition = new DocumentsBatchTransition({
|
|
59
|
+
ownerId,
|
|
60
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
61
|
+
}, [dataContract]);
|
|
62
|
+
|
|
63
|
+
executionContext = new StateTransitionExecutionContext();
|
|
64
|
+
|
|
65
|
+
stateTransition.setExecutionContext(executionContext);
|
|
66
|
+
|
|
67
|
+
stateRepositoryMock = createStateRepositoryMock(this.sinonSandbox);
|
|
68
|
+
stateRepositoryMock.fetchDataContract.resolves(dataContract);
|
|
69
|
+
|
|
70
|
+
blockTime = new Date().getTime() / 1000;
|
|
71
|
+
|
|
72
|
+
abciHeader = {
|
|
73
|
+
time: {
|
|
74
|
+
seconds: blockTime,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
stateRepositoryMock.fetchLatestPlatformBlockHeader.resolves(abciHeader);
|
|
79
|
+
|
|
80
|
+
fetchDocumentsMock = this.sinonSandbox.stub().resolves([]);
|
|
81
|
+
|
|
82
|
+
executeDataTriggersMock = this.sinonSandbox.stub();
|
|
83
|
+
|
|
84
|
+
validateDocumentsUniquenessByIndicesMock = this.sinonSandbox.stub();
|
|
85
|
+
validateDocumentsUniquenessByIndicesMock.resolves(new ValidationResult());
|
|
86
|
+
|
|
87
|
+
validateDocumentsBatchTransitionState = validateDocumentsBatchTransitionStateFactory(
|
|
88
|
+
stateRepositoryMock,
|
|
89
|
+
fetchDocumentsMock,
|
|
90
|
+
validateDocumentsUniquenessByIndicesMock,
|
|
91
|
+
executeDataTriggersMock,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
fakeTime = this.sinonSandbox.useFakeTimers(new Date());
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
afterEach(() => {
|
|
98
|
+
fakeTime.reset();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should throw DataContractNotPresentError if data contract was not found', async () => {
|
|
102
|
+
stateRepositoryMock.fetchDataContract.resolves(null);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
await validateDocumentsBatchTransitionState(stateTransition);
|
|
106
|
+
|
|
107
|
+
expect.fail('should throw DataContractNotPresentError');
|
|
108
|
+
} catch (e) {
|
|
109
|
+
expect(e).to.be.instanceOf(DataContractNotPresentError);
|
|
110
|
+
|
|
111
|
+
expect(e.getDataContractId()).to.deep.equal(dataContract.getId());
|
|
112
|
+
|
|
113
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
114
|
+
dataContract.getId(),
|
|
115
|
+
new StateTransitionExecutionContext(),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
expect(fetchDocumentsMock).to.have.not.been.called();
|
|
119
|
+
expect(validateDocumentsUniquenessByIndicesMock).to.have.not.been.called();
|
|
120
|
+
expect(executeDataTriggersMock).to.have.not.been.called();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should return invalid result if document transition with action "create" is already present', async () => {
|
|
125
|
+
fetchDocumentsMock.resolves([documents[0]]);
|
|
126
|
+
|
|
127
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
128
|
+
|
|
129
|
+
expectValidationError(result, DocumentAlreadyPresentError);
|
|
130
|
+
|
|
131
|
+
const [error] = result.getErrors();
|
|
132
|
+
|
|
133
|
+
expect(error.getCode()).to.equal(4004);
|
|
134
|
+
expect(Buffer.isBuffer(error.getDocumentId())).to.be.true();
|
|
135
|
+
expect(error.getDocumentId()).to.deep.equal(documentTransitions[0].getId().toBuffer());
|
|
136
|
+
|
|
137
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
138
|
+
dataContract.getId(),
|
|
139
|
+
new StateTransitionExecutionContext(),
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
expect(fetchDocumentsMock.getCall(0).args[0].map((t) => t.toObject())).to.have.deep.members(
|
|
143
|
+
documentTransitions.map((t) => t.toObject()),
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
expect(validateDocumentsUniquenessByIndicesMock).to.have.not.been.called();
|
|
147
|
+
expect(executeDataTriggersMock).to.have.not.been.called();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should return invalid result if document transition with action "replace" is not present', async () => {
|
|
151
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
152
|
+
create: [],
|
|
153
|
+
replace: [documents[0]],
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
stateTransition = new DocumentsBatchTransition({
|
|
157
|
+
ownerId,
|
|
158
|
+
contractId: dataContract.getId(),
|
|
159
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
160
|
+
}, [dataContract]);
|
|
161
|
+
|
|
162
|
+
stateTransition.setExecutionContext(executionContext);
|
|
163
|
+
|
|
164
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
165
|
+
|
|
166
|
+
expectValidationError(result, DocumentNotFoundError);
|
|
167
|
+
|
|
168
|
+
const [error] = result.getErrors();
|
|
169
|
+
|
|
170
|
+
expect(error.getCode()).to.equal(4005);
|
|
171
|
+
expect(Buffer.isBuffer(error.getDocumentId())).to.be.true();
|
|
172
|
+
expect(error.getDocumentId()).to.deep.equal(documentTransitions[0].getId().toBuffer());
|
|
173
|
+
|
|
174
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
175
|
+
dataContract.getId(),
|
|
176
|
+
new StateTransitionExecutionContext(),
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(
|
|
180
|
+
documentTransitions,
|
|
181
|
+
executionContext,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
expect(validateDocumentsUniquenessByIndicesMock).to.have.not.been.called();
|
|
185
|
+
expect(executeDataTriggersMock).to.have.not.been.called();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should return invalid result if document transition with action "delete" is not present', async () => {
|
|
189
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
190
|
+
create: [],
|
|
191
|
+
delete: [documents[0]],
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
stateTransition = new DocumentsBatchTransition({
|
|
195
|
+
ownerId,
|
|
196
|
+
contractId: dataContract.getId(),
|
|
197
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
198
|
+
}, [dataContract]);
|
|
199
|
+
|
|
200
|
+
stateTransition.setExecutionContext(executionContext);
|
|
201
|
+
|
|
202
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
203
|
+
|
|
204
|
+
expectValidationError(result, DocumentNotFoundError);
|
|
205
|
+
|
|
206
|
+
const [error] = result.getErrors();
|
|
207
|
+
|
|
208
|
+
expect(error.getCode()).to.equal(4005);
|
|
209
|
+
expect(Buffer.isBuffer(error.getDocumentId())).to.be.true();
|
|
210
|
+
expect(error.getDocumentId()).to.deep.equal(documentTransitions[0].getId().toBuffer());
|
|
211
|
+
|
|
212
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
213
|
+
dataContract.getId(),
|
|
214
|
+
new StateTransitionExecutionContext(),
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(
|
|
218
|
+
documentTransitions,
|
|
219
|
+
executionContext,
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
expect(validateDocumentsUniquenessByIndicesMock).to.have.not.been.called();
|
|
223
|
+
expect(executeDataTriggersMock).to.have.not.been.called();
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should return invalid result if document transition with action "replace" has wrong revision', async () => {
|
|
227
|
+
const replaceDocument = new Document(documents[0].toObject(), dataContract);
|
|
228
|
+
replaceDocument.setRevision(3);
|
|
229
|
+
|
|
230
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
231
|
+
create: [],
|
|
232
|
+
replace: [replaceDocument],
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
stateTransition = new DocumentsBatchTransition({
|
|
236
|
+
ownerId,
|
|
237
|
+
contractId: dataContract.getId(),
|
|
238
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
239
|
+
}, [dataContract]);
|
|
240
|
+
|
|
241
|
+
stateTransition.setExecutionContext(executionContext);
|
|
242
|
+
|
|
243
|
+
documents[0].setCreatedAt(replaceDocument.getCreatedAt());
|
|
244
|
+
fetchDocumentsMock.resolves([documents[0]]);
|
|
245
|
+
|
|
246
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
247
|
+
|
|
248
|
+
expectValidationError(result, InvalidDocumentRevisionError);
|
|
249
|
+
|
|
250
|
+
const [error] = result.getErrors();
|
|
251
|
+
|
|
252
|
+
expect(error.getCode()).to.equal(4010);
|
|
253
|
+
expect(Buffer.isBuffer(error.getDocumentId())).to.be.true();
|
|
254
|
+
expect(error.getDocumentId()).to.deep.equal(documentTransitions[0].getId().toBuffer());
|
|
255
|
+
expect(error.getCurrentRevision()).to.deep.equal(documents[0].getRevision());
|
|
256
|
+
|
|
257
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
258
|
+
dataContract.getId(),
|
|
259
|
+
new StateTransitionExecutionContext(),
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(
|
|
263
|
+
documentTransitions,
|
|
264
|
+
executionContext,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
expect(validateDocumentsUniquenessByIndicesMock).to.have.not.been.called();
|
|
268
|
+
expect(executeDataTriggersMock).to.have.not.been.called();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should return invalid result if document transition with action "replace" has mismatch of ownerId with previous revision', async () => {
|
|
272
|
+
const replaceDocument = new Document(documents[0].toObject(), dataContract);
|
|
273
|
+
replaceDocument.setRevision(1);
|
|
274
|
+
|
|
275
|
+
const fetchedDocument = new Document(documents[0].toObject(), dataContract);
|
|
276
|
+
fetchedDocument.ownerId = generateRandomIdentifier();
|
|
277
|
+
|
|
278
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
279
|
+
create: [],
|
|
280
|
+
replace: [replaceDocument],
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
stateTransition = new DocumentsBatchTransition({
|
|
284
|
+
ownerId,
|
|
285
|
+
contractId: dataContract.getId(),
|
|
286
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
287
|
+
}, [dataContract]);
|
|
288
|
+
|
|
289
|
+
stateTransition.setExecutionContext(executionContext);
|
|
290
|
+
|
|
291
|
+
fetchDocumentsMock.resolves([fetchedDocument]);
|
|
292
|
+
|
|
293
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
294
|
+
|
|
295
|
+
expectValidationError(result, DocumentOwnerIdMismatchError);
|
|
296
|
+
|
|
297
|
+
const [error] = result.getErrors();
|
|
298
|
+
|
|
299
|
+
expect(error.getCode()).to.equal(4006);
|
|
300
|
+
expect(Buffer.isBuffer(error.getDocumentId())).to.be.true();
|
|
301
|
+
expect(error.getDocumentId()).to.deep.equal(documentTransitions[0].getId().toBuffer());
|
|
302
|
+
|
|
303
|
+
expect(Buffer.isBuffer(error.getDocumentOwnerId())).to.be.true();
|
|
304
|
+
expect(error.getDocumentOwnerId()).to.deep.equal(
|
|
305
|
+
replaceDocument.getOwnerId().toBuffer(),
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
expect(Buffer.isBuffer(error.getExistingDocumentOwnerId())).to.be.true();
|
|
309
|
+
expect(error.getExistingDocumentOwnerId()).to.deep.equal(
|
|
310
|
+
fetchedDocument.getOwnerId().toBuffer(),
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
314
|
+
dataContract.getId(),
|
|
315
|
+
new StateTransitionExecutionContext(),
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(
|
|
319
|
+
documentTransitions,
|
|
320
|
+
executionContext,
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
expect(validateDocumentsUniquenessByIndicesMock).to.have.not.been.called();
|
|
324
|
+
expect(executeDataTriggersMock).to.have.not.been.called();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('should throw an error if document transition has invalid action', async () => {
|
|
328
|
+
stateTransition = new DocumentsBatchTransition({
|
|
329
|
+
ownerId,
|
|
330
|
+
contractId: dataContract.getId(),
|
|
331
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
332
|
+
}, [dataContract]);
|
|
333
|
+
|
|
334
|
+
stateTransition.setExecutionContext(executionContext);
|
|
335
|
+
|
|
336
|
+
stateTransition.transitions[0].getAction = () => 5;
|
|
337
|
+
|
|
338
|
+
fetchDocumentsMock.resolves([documents[0]]);
|
|
339
|
+
|
|
340
|
+
try {
|
|
341
|
+
await validateDocumentsBatchTransitionState(stateTransition);
|
|
342
|
+
|
|
343
|
+
expect.fail('InvalidDocumentActionError should be thrown');
|
|
344
|
+
} catch (e) {
|
|
345
|
+
expect(e).to.be.an.instanceOf(InvalidDocumentActionError);
|
|
346
|
+
expect(e.getDocumentTransition().toObject()).to.deep.equal(
|
|
347
|
+
stateTransition.transitions[0].toObject(),
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
351
|
+
dataContract.getId(),
|
|
352
|
+
new StateTransitionExecutionContext(),
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(
|
|
356
|
+
stateTransition.transitions,
|
|
357
|
+
executionContext,
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
expect(validateDocumentsUniquenessByIndicesMock).to.have.not.been.called();
|
|
361
|
+
expect(executeDataTriggersMock).to.have.not.been.called();
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it('should return invalid result if there are duplicate document transitions according to unique indices', async () => {
|
|
366
|
+
const duplicateDocumentsError = new SomeConsensusError('error');
|
|
367
|
+
|
|
368
|
+
validateDocumentsUniquenessByIndicesMock.resolves(
|
|
369
|
+
new ValidationResult([duplicateDocumentsError]),
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
373
|
+
|
|
374
|
+
expectValidationError(result);
|
|
375
|
+
|
|
376
|
+
const [error] = result.getErrors();
|
|
377
|
+
|
|
378
|
+
expect(error).to.equal(duplicateDocumentsError);
|
|
379
|
+
|
|
380
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
381
|
+
dataContract.getId(),
|
|
382
|
+
new StateTransitionExecutionContext(),
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(
|
|
386
|
+
stateTransition.transitions,
|
|
387
|
+
executionContext,
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
const [callOwnerId, callDocumentTransitions, callDataContract] = (
|
|
391
|
+
validateDocumentsUniquenessByIndicesMock.getCall(0).args
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
const callArgs = [
|
|
395
|
+
callOwnerId,
|
|
396
|
+
callDocumentTransitions.map((t) => t.toObject()),
|
|
397
|
+
callDataContract,
|
|
398
|
+
];
|
|
399
|
+
|
|
400
|
+
expect(callArgs).to.have.deep.members([
|
|
401
|
+
ownerId,
|
|
402
|
+
documentTransitions.map((t) => t.toObject()),
|
|
403
|
+
dataContract,
|
|
404
|
+
]);
|
|
405
|
+
expect(executeDataTriggersMock).to.have.not.been.called();
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('should return invalid result if data triggers execution failed', async () => {
|
|
409
|
+
const dataTriggersExecutionContext = new DataTriggerExecutionContext(
|
|
410
|
+
stateRepositoryMock,
|
|
411
|
+
ownerId,
|
|
412
|
+
dataContract,
|
|
413
|
+
executionContext,
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
const dataTriggerExecutionError = new DataTriggerExecutionError(
|
|
417
|
+
documentTransitions[0],
|
|
418
|
+
dataTriggersExecutionContext.getDataContract(),
|
|
419
|
+
dataTriggersExecutionContext.getOwnerId(),
|
|
420
|
+
new Error('error'),
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
executeDataTriggersMock.resolves([
|
|
424
|
+
new DataTriggerExecutionResult([dataTriggerExecutionError]),
|
|
425
|
+
]);
|
|
426
|
+
|
|
427
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
428
|
+
|
|
429
|
+
expectValidationError(result, DataTriggerExecutionError);
|
|
430
|
+
|
|
431
|
+
const [error] = result.getErrors();
|
|
432
|
+
|
|
433
|
+
expect(error.getCode()).to.equal(4002);
|
|
434
|
+
expect(error).to.equal(dataTriggerExecutionError);
|
|
435
|
+
|
|
436
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
437
|
+
dataContract.getId(),
|
|
438
|
+
new StateTransitionExecutionContext(),
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(
|
|
442
|
+
stateTransition.transitions,
|
|
443
|
+
executionContext,
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
const [callOwnerId, callDocumentTransitions, callDataContract, callExecutionContext] = (
|
|
447
|
+
validateDocumentsUniquenessByIndicesMock.getCall(0).args
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
const callArgs = [
|
|
451
|
+
callOwnerId,
|
|
452
|
+
callDocumentTransitions.map((t) => t.toObject()),
|
|
453
|
+
callDataContract,
|
|
454
|
+
callExecutionContext,
|
|
455
|
+
];
|
|
456
|
+
|
|
457
|
+
expect(callArgs).to.have.deep.members([
|
|
458
|
+
ownerId,
|
|
459
|
+
documentTransitions.map((t) => t.toObject()),
|
|
460
|
+
dataContract,
|
|
461
|
+
executionContext,
|
|
462
|
+
]);
|
|
463
|
+
|
|
464
|
+
const [triggerCallDocumentTransitions, triggerCallDataTriggersExecutionContext] = (
|
|
465
|
+
executeDataTriggersMock.getCall(0).args
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
const triggerCallArgs = [
|
|
469
|
+
triggerCallDocumentTransitions.map((t) => t.toObject()),
|
|
470
|
+
triggerCallDataTriggersExecutionContext,
|
|
471
|
+
];
|
|
472
|
+
|
|
473
|
+
expect(triggerCallArgs).to.have.deep.members([
|
|
474
|
+
documentTransitions.map((t) => t.toObject()),
|
|
475
|
+
dataTriggersExecutionContext,
|
|
476
|
+
]);
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
describe('Timestamps', () => {
|
|
480
|
+
let timeWindowStart;
|
|
481
|
+
let timeWindowEnd;
|
|
482
|
+
|
|
483
|
+
beforeEach(() => {
|
|
484
|
+
timeWindowStart = new Date(blockTime * 1000);
|
|
485
|
+
timeWindowStart.setMinutes(
|
|
486
|
+
timeWindowStart.getMinutes() - 5,
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
timeWindowEnd = new Date(blockTime * 1000);
|
|
490
|
+
timeWindowEnd.setMinutes(
|
|
491
|
+
timeWindowEnd.getMinutes() + 5,
|
|
492
|
+
);
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
describe('CREATE transition', () => {
|
|
496
|
+
it('should return invalid result if timestamps mismatch', async () => {
|
|
497
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
498
|
+
create: [documents[0]],
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
stateTransition = new DocumentsBatchTransition({
|
|
502
|
+
ownerId,
|
|
503
|
+
contractId: dataContract.getId(),
|
|
504
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
505
|
+
}, [dataContract]);
|
|
506
|
+
|
|
507
|
+
stateTransition.transitions.forEach((t) => {
|
|
508
|
+
// eslint-disable-next-line no-param-reassign
|
|
509
|
+
t.updatedAt = new Date();
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
513
|
+
|
|
514
|
+
expectValidationError(result, DocumentTimestampsMismatchError);
|
|
515
|
+
|
|
516
|
+
const [error] = result.getErrors();
|
|
517
|
+
|
|
518
|
+
expect(error.getCode()).to.equal(4007);
|
|
519
|
+
|
|
520
|
+
documentTransitions[0].updatedAt = new Date();
|
|
521
|
+
|
|
522
|
+
expect(Buffer.isBuffer(error.getDocumentId())).to.be.true();
|
|
523
|
+
expect(error.getDocumentId()).to.deep.equal(documentTransitions[0].getId().toBuffer());
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('should return invalid result if "$createdAt" have violated time window', async () => {
|
|
527
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
528
|
+
create: [documents[0]],
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
stateTransition = new DocumentsBatchTransition({
|
|
532
|
+
ownerId,
|
|
533
|
+
contractId: dataContract.getId(),
|
|
534
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
535
|
+
}, [dataContract]);
|
|
536
|
+
|
|
537
|
+
stateTransition.transitions.forEach((t) => {
|
|
538
|
+
// eslint-disable-next-line no-param-reassign
|
|
539
|
+
t.createdAt.setMinutes(t.createdAt.getMinutes() - 6);
|
|
540
|
+
// eslint-disable-next-line no-param-reassign
|
|
541
|
+
t.updatedAt = undefined;
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
545
|
+
|
|
546
|
+
expectValidationError(result, DocumentTimestampWindowViolationError);
|
|
547
|
+
|
|
548
|
+
const [error] = result.getErrors();
|
|
549
|
+
|
|
550
|
+
expect(error.getCode()).to.equal(4008);
|
|
551
|
+
|
|
552
|
+
documentTransitions[0].createdAt.setMinutes(
|
|
553
|
+
documentTransitions[0].createdAt.getMinutes() - 6,
|
|
554
|
+
);
|
|
555
|
+
documentTransitions[0].updatedAt = undefined;
|
|
556
|
+
|
|
557
|
+
expect(Buffer.isBuffer(error.getDocumentId())).to.be.true();
|
|
558
|
+
expect(error.getDocumentId()).to.deep.equal(documentTransitions[0].getId().toBuffer());
|
|
559
|
+
expect(error.getTimestampName()).to.equal('createdAt');
|
|
560
|
+
expect(error.getTimestamp()).to.deep.equal(documentTransitions[0].createdAt);
|
|
561
|
+
expect(error.getTimeWindowStart()).to.deep.equal(timeWindowStart);
|
|
562
|
+
expect(error.getTimeWindowEnd()).to.deep.equal(timeWindowEnd);
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
it('should return invalid result if "$updatedAt" have violated time window', async () => {
|
|
566
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
567
|
+
create: [documents[1]],
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
stateTransition = new DocumentsBatchTransition({
|
|
571
|
+
ownerId,
|
|
572
|
+
contractId: dataContract.getId(),
|
|
573
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
574
|
+
}, [dataContract]);
|
|
575
|
+
|
|
576
|
+
stateTransition.transitions.forEach((t) => {
|
|
577
|
+
// eslint-disable-next-line no-param-reassign
|
|
578
|
+
t.updatedAt.setMinutes(t.updatedAt.getMinutes() - 6);
|
|
579
|
+
// eslint-disable-next-line no-param-reassign
|
|
580
|
+
t.createdAt = undefined;
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
584
|
+
|
|
585
|
+
expectValidationError(result, DocumentTimestampWindowViolationError);
|
|
586
|
+
|
|
587
|
+
const [error] = result.getErrors();
|
|
588
|
+
|
|
589
|
+
expect(error.getCode()).to.equal(4008);
|
|
590
|
+
|
|
591
|
+
documentTransitions[0].updatedAt.setMinutes(
|
|
592
|
+
documentTransitions[0].updatedAt.getMinutes() - 6,
|
|
593
|
+
);
|
|
594
|
+
documentTransitions[0].createdAt = undefined;
|
|
595
|
+
|
|
596
|
+
expect(Buffer.isBuffer(error.getDocumentId())).to.be.true();
|
|
597
|
+
expect(error.getDocumentId()).to.deep.equal(documentTransitions[0].getId().toBuffer());
|
|
598
|
+
expect(error.getTimestampName()).to.equal('updatedAt');
|
|
599
|
+
expect(error.getTimestamp()).to.deep.equal(documentTransitions[0].updatedAt);
|
|
600
|
+
expect(error.getTimeWindowStart()).to.deep.equal(timeWindowStart);
|
|
601
|
+
expect(error.getTimeWindowEnd()).to.deep.equal(timeWindowEnd);
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it('should not validate time in block window on dry run', async () => {
|
|
605
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
606
|
+
create: [documents[1]],
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
executeDataTriggersMock.resolves([
|
|
610
|
+
new DataTriggerExecutionResult(),
|
|
611
|
+
]);
|
|
612
|
+
|
|
613
|
+
stateTransition = new DocumentsBatchTransition({
|
|
614
|
+
ownerId,
|
|
615
|
+
contractId: dataContract.getId(),
|
|
616
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
617
|
+
}, [dataContract]);
|
|
618
|
+
|
|
619
|
+
stateTransition.transitions.forEach((t) => {
|
|
620
|
+
// eslint-disable-next-line no-param-reassign
|
|
621
|
+
t.updatedAt.setMinutes(t.updatedAt.getMinutes() - 6);
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
stateTransition.getExecutionContext().enableDryRun();
|
|
625
|
+
|
|
626
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
627
|
+
|
|
628
|
+
stateTransition.getExecutionContext().disableDryRun();
|
|
629
|
+
|
|
630
|
+
expect(result).to.be.an.instanceOf(ValidationResult);
|
|
631
|
+
expect(result.isValid()).to.be.true();
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
it('should return valid result if timestamps mismatch on dry run', async () => {
|
|
635
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
636
|
+
create: [documents[0]],
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
executeDataTriggersMock.resolves([
|
|
640
|
+
new DataTriggerExecutionResult(),
|
|
641
|
+
]);
|
|
642
|
+
|
|
643
|
+
stateTransition = new DocumentsBatchTransition({
|
|
644
|
+
ownerId,
|
|
645
|
+
contractId: dataContract.getId(),
|
|
646
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
647
|
+
}, [dataContract]);
|
|
648
|
+
|
|
649
|
+
stateTransition.transitions.forEach((t) => {
|
|
650
|
+
// eslint-disable-next-line no-param-reassign
|
|
651
|
+
t.updatedAt = new Date();
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
stateTransition.getExecutionContext().enableDryRun();
|
|
655
|
+
|
|
656
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
657
|
+
|
|
658
|
+
stateTransition.getExecutionContext().disableDryRun();
|
|
659
|
+
|
|
660
|
+
expect(result).to.be.an.instanceOf(ValidationResult);
|
|
661
|
+
expect(result.isValid()).to.be.true();
|
|
662
|
+
});
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
describe('REPLACE transition', () => {
|
|
666
|
+
it('should return invalid result if documents with action "replace" have violated time window', async () => {
|
|
667
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
668
|
+
create: [],
|
|
669
|
+
replace: [documents[1]],
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
stateTransition = new DocumentsBatchTransition({
|
|
673
|
+
ownerId,
|
|
674
|
+
contractId: dataContract.getId(),
|
|
675
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
676
|
+
}, [dataContract]);
|
|
677
|
+
|
|
678
|
+
documents[1].updatedAt.setMinutes(
|
|
679
|
+
documents[1].updatedAt.getMinutes() - 6,
|
|
680
|
+
);
|
|
681
|
+
|
|
682
|
+
fetchDocumentsMock.resolves([documents[1]]);
|
|
683
|
+
|
|
684
|
+
stateTransition.transitions.forEach((t) => {
|
|
685
|
+
// eslint-disable-next-line no-param-reassign
|
|
686
|
+
t.updatedAt.setMinutes(t.updatedAt.getMinutes() - 6);
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
690
|
+
|
|
691
|
+
expectValidationError(result, DocumentTimestampWindowViolationError);
|
|
692
|
+
|
|
693
|
+
const [error] = result.getErrors();
|
|
694
|
+
|
|
695
|
+
expect(error.getCode()).to.equal(4008);
|
|
696
|
+
|
|
697
|
+
documentTransitions[0].updatedAt.setMinutes(
|
|
698
|
+
documentTransitions[0].updatedAt.getMinutes() - 6,
|
|
699
|
+
);
|
|
700
|
+
|
|
701
|
+
expect(Buffer.isBuffer(error.getDocumentId())).to.be.true();
|
|
702
|
+
expect(error.getDocumentId()).to.deep.equal(documentTransitions[0].getId().toBuffer());
|
|
703
|
+
expect(error.getTimestampName()).to.equal('updatedAt');
|
|
704
|
+
expect(error.getTimestamp()).to.deep.equal(documentTransitions[0].updatedAt);
|
|
705
|
+
expect(error.getTimeWindowStart()).to.deep.equal(timeWindowStart);
|
|
706
|
+
expect(error.getTimeWindowEnd()).to.deep.equal(timeWindowEnd);
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
it('should return valid result if documents with action "replace" have violated time window on dry run', async () => {
|
|
710
|
+
executeDataTriggersMock.resolves([
|
|
711
|
+
new DataTriggerExecutionResult(),
|
|
712
|
+
]);
|
|
713
|
+
|
|
714
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
715
|
+
create: [],
|
|
716
|
+
replace: [documents[1]],
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
stateTransition = new DocumentsBatchTransition({
|
|
720
|
+
ownerId,
|
|
721
|
+
contractId: dataContract.getId(),
|
|
722
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
723
|
+
}, [dataContract]);
|
|
724
|
+
|
|
725
|
+
documents[1].updatedAt.setMinutes(
|
|
726
|
+
documents[1].updatedAt.getMinutes() - 6,
|
|
727
|
+
);
|
|
728
|
+
|
|
729
|
+
fetchDocumentsMock.resolves([documents[1]]);
|
|
730
|
+
|
|
731
|
+
stateTransition.transitions.forEach((t) => {
|
|
732
|
+
// eslint-disable-next-line no-param-reassign
|
|
733
|
+
t.updatedAt.setMinutes(t.updatedAt.getMinutes() - 6);
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
stateTransition.getExecutionContext().enableDryRun();
|
|
737
|
+
|
|
738
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
739
|
+
|
|
740
|
+
stateTransition.getExecutionContext().disableDryRun();
|
|
741
|
+
|
|
742
|
+
expect(result).to.be.an.instanceOf(ValidationResult);
|
|
743
|
+
expect(result.isValid()).to.be.true();
|
|
744
|
+
});
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
it('should return valid result if document transitions are valid', async () => {
|
|
749
|
+
const fetchedDocuments = [
|
|
750
|
+
new Document(documents[1].toObject(), dataContract),
|
|
751
|
+
new Document(documents[2].toObject(), dataContract),
|
|
752
|
+
];
|
|
753
|
+
|
|
754
|
+
fetchDocumentsMock.resolves(fetchedDocuments);
|
|
755
|
+
|
|
756
|
+
documents[1].setRevision(1);
|
|
757
|
+
documents[2].setRevision(1);
|
|
758
|
+
|
|
759
|
+
documentTransitions = getDocumentTransitionsFixture({
|
|
760
|
+
create: [],
|
|
761
|
+
replace: [documents[1]],
|
|
762
|
+
delete: [documents[2]],
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
stateTransition = new DocumentsBatchTransition({
|
|
766
|
+
ownerId,
|
|
767
|
+
contractId: dataContract.getId(),
|
|
768
|
+
transitions: documentTransitions.map((t) => t.toObject()),
|
|
769
|
+
}, [dataContract]);
|
|
770
|
+
|
|
771
|
+
stateTransition.setExecutionContext(executionContext);
|
|
772
|
+
|
|
773
|
+
const dataTriggersExecutionContext = new DataTriggerExecutionContext(
|
|
774
|
+
stateRepositoryMock,
|
|
775
|
+
ownerId,
|
|
776
|
+
dataContract,
|
|
777
|
+
executionContext,
|
|
778
|
+
);
|
|
779
|
+
|
|
780
|
+
executeDataTriggersMock.resolves([
|
|
781
|
+
new DataTriggerExecutionResult(),
|
|
782
|
+
]);
|
|
783
|
+
|
|
784
|
+
const result = await validateDocumentsBatchTransitionState(stateTransition);
|
|
785
|
+
|
|
786
|
+
expect(result).to.be.an.instanceOf(ValidationResult);
|
|
787
|
+
expect(result.isValid()).to.be.true();
|
|
788
|
+
|
|
789
|
+
expect(stateRepositoryMock.fetchDataContract).to.have.been.calledOnceWithExactly(
|
|
790
|
+
dataContract.getId(),
|
|
791
|
+
new StateTransitionExecutionContext(),
|
|
792
|
+
);
|
|
793
|
+
|
|
794
|
+
expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(
|
|
795
|
+
stateTransition.transitions,
|
|
796
|
+
executionContext,
|
|
797
|
+
);
|
|
798
|
+
|
|
799
|
+
expect(validateDocumentsUniquenessByIndicesMock).to.have.been.calledOnceWithExactly(
|
|
800
|
+
ownerId,
|
|
801
|
+
[documentTransitions[0]],
|
|
802
|
+
dataContract,
|
|
803
|
+
executionContext,
|
|
804
|
+
);
|
|
805
|
+
|
|
806
|
+
expect(executeDataTriggersMock).to.have.been.calledOnceWithExactly(
|
|
807
|
+
documentTransitions,
|
|
808
|
+
dataTriggersExecutionContext,
|
|
809
|
+
);
|
|
810
|
+
});
|
|
811
|
+
});
|