azure-mock 4.0.0 → 4.1.0
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/dist/index.d.ts +5 -2
- package/dist/index.js +56 -43
- package/package.json +7 -8
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { CreateTableEntityResponse, GetAccessPolicyResponse, GetTableEntityRespo
|
|
|
10
10
|
//#region src/constants.d.ts
|
|
11
11
|
export declare const BLOB_NOT_FOUND_ERROR_CODE = "BlobNotFound";
|
|
12
12
|
export declare const BLOB_NOT_FOUND_MESSAGE = "The specified blob does not exist.";
|
|
13
|
+
export declare const CONDITION_NOT_MET_ERROR_CODE = "ConditionNotMet";
|
|
14
|
+
export declare const CONDITION_NOT_MET_MESSAGE = "The condition specified using HTTP conditional header(s) is not met.";
|
|
13
15
|
export declare const MOCK_BLOB_BASE_URL = "https://mockaccount.blob.core.windows.net";
|
|
14
16
|
export declare const MOCK_QUEUE_BASE_URL = "https://mockaccount.queue.core.windows.net";
|
|
15
17
|
export declare const MOCK_SEARCH_BASE_URL = "https://mockaccount.search.windows.net";
|
|
@@ -39,7 +41,7 @@ export declare class MockBlobBatchClient implements BlobBatchClient {
|
|
|
39
41
|
* underlying MockContainerDatabase, and builds a response object that reports
|
|
40
42
|
* which deletions succeeded and which failed (e.g. for blobs that didn't exist).
|
|
41
43
|
*/
|
|
42
|
-
deleteBlobs(urls: string[], credential: AnonymousCredential | StorageSharedKeyCredential,
|
|
44
|
+
deleteBlobs(urls: string[], credential: AnonymousCredential | StorageSharedKeyCredential, options?: BlobDeleteOptions): Promise<BlobBatchDeleteBlobsResponse>;
|
|
43
45
|
getContainer(containerName: string): MapValue<typeof MockContainerDatabase>;
|
|
44
46
|
}
|
|
45
47
|
//#endregion
|
|
@@ -1234,4 +1236,5 @@ export declare const MockContainerBlobMetadataDatabase: Map<string, Record<strin
|
|
|
1234
1236
|
//#endregion
|
|
1235
1237
|
//#region src/store/MockEventGridDatabase.d.ts
|
|
1236
1238
|
export declare const MockEventGridDatabase: Map<string, EventGridEvent<unknown>[]>;
|
|
1237
|
-
//#endregion
|
|
1239
|
+
//#endregion
|
|
1240
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
import { ID_SEPARATOR, InvalidOperationError, Operation, chunk, exhaustiveGuard, getDecodedUriComponent, getOrCreate, getResult, html, noop, streamToText, takeOne } from "@esposter/shared";
|
|
1
|
+
import { ID_SEPARATOR, InvalidOperationError, Operation, checkIsDeepEqual, chunk, exhaustiveGuard, getDecodedUriComponent, getOrCreate, getResult, html, noop, streamToText, takeOne } from "@esposter/shared";
|
|
2
2
|
import { toHttpHeadersLike } from "@azure/core-http-compat";
|
|
3
3
|
import { RestError, createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
|
4
4
|
import { AnonymousCredential } from "@azure/storage-blob";
|
|
5
5
|
import { Readable } from "node:stream";
|
|
6
6
|
import { AZURE_MAX_PAGE_SIZE, AZURE_MAX_QUEUE_VISIBILITY_TIMEOUT_MS, BinaryOperator, deserializeClause, deserializeKey, getTableNullClause, serializeClauses } from "@esposter/azure";
|
|
7
|
-
import deepEqual from "fast-deep-equal";
|
|
8
7
|
//#region src/constants.ts
|
|
9
8
|
const BLOB_NOT_FOUND_ERROR_CODE = "BlobNotFound";
|
|
10
9
|
const BLOB_NOT_FOUND_MESSAGE = "The specified blob does not exist.";
|
|
10
|
+
const CONDITION_NOT_MET_ERROR_CODE = "ConditionNotMet";
|
|
11
|
+
const CONDITION_NOT_MET_MESSAGE = "The condition specified using HTTP conditional header(s) is not met.";
|
|
11
12
|
const MOCK_BLOB_BASE_URL = "https://mockaccount.blob.core.windows.net";
|
|
12
13
|
const MOCK_QUEUE_BASE_URL = "https://mockaccount.queue.core.windows.net";
|
|
13
14
|
const MOCK_SEARCH_BASE_URL = "https://mockaccount.search.windows.net";
|
|
14
15
|
const MOCK_TABLE_BASE_URL = "https://mockaccount.table.core.windows.net";
|
|
15
16
|
//#endregion
|
|
17
|
+
//#region src/models/shared/NotImplementedError.ts
|
|
18
|
+
var NotImplementedError = class extends Error {
|
|
19
|
+
constructor(name) {
|
|
20
|
+
super(`${name} is not implemented in the mock`);
|
|
21
|
+
this.name = "NotImplementedError";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
16
25
|
//#region src/services/container/getMockBlobKey.ts
|
|
17
26
|
const getMockBlobKey = (containerName, blobName) => `${encodeURIComponent(containerName)}${ID_SEPARATOR}${encodeURIComponent(blobName)}`;
|
|
18
27
|
//#endregion
|
|
@@ -76,14 +85,17 @@ const getBlobUrlParts = (url) => {
|
|
|
76
85
|
};
|
|
77
86
|
};
|
|
78
87
|
//#endregion
|
|
79
|
-
//#region src/
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
//#region src/services/container/constants.ts
|
|
89
|
+
const MOCK_BLOB_SEEDED_DATE = /* @__PURE__ */ new Date(-864e13);
|
|
90
|
+
const MOCK_BLOB_SEEDED_PROPERTIES = {
|
|
91
|
+
createdOn: MOCK_BLOB_SEEDED_DATE,
|
|
92
|
+
etag: "\"seeded\"",
|
|
93
|
+
lastModified: MOCK_BLOB_SEEDED_DATE
|
|
85
94
|
};
|
|
86
95
|
//#endregion
|
|
96
|
+
//#region src/services/container/readMockBlobDates.ts
|
|
97
|
+
const readMockBlobDates = (containerName, blobName) => MockContainerBlobDatesDatabase.get(getMockBlobKey(containerName, blobName)) ?? MOCK_BLOB_SEEDED_PROPERTIES;
|
|
98
|
+
//#endregion
|
|
87
99
|
//#region src/services/container/toWebResourceLike.ts
|
|
88
100
|
const toWebResourceLike = (request) => ({
|
|
89
101
|
abortSignal: request.abortSignal,
|
|
@@ -131,7 +143,10 @@ var MockBlobBatchClient = class {
|
|
|
131
143
|
* underlying MockContainerDatabase, and builds a response object that reports
|
|
132
144
|
* which deletions succeeded and which failed (e.g. for blobs that didn't exist).
|
|
133
145
|
*/
|
|
134
|
-
deleteBlobs(urls, credential,
|
|
146
|
+
deleteBlobs(urls, credential, options) {
|
|
147
|
+
const { ifUnmodifiedSince, ...unsupportedConditions } = options?.conditions ?? {};
|
|
148
|
+
const unsupportedConditionName = Object.entries(unsupportedConditions).find(([, value]) => value !== void 0)?.[0];
|
|
149
|
+
if (unsupportedConditionName !== void 0) return Promise.reject(new NotImplementedError(`deleteBlobs with ${unsupportedConditionName}`));
|
|
135
150
|
const subResponses = [];
|
|
136
151
|
let subResponsesSucceededCount = 0;
|
|
137
152
|
let subResponsesFailedCount = 0;
|
|
@@ -143,6 +158,11 @@ var MockBlobBatchClient = class {
|
|
|
143
158
|
continue;
|
|
144
159
|
}
|
|
145
160
|
const { blobName, containerName } = urlParts;
|
|
161
|
+
if (this.#checkIsModifiedSince(containerName, blobName, ifUnmodifiedSince)) {
|
|
162
|
+
subResponses.push(this.#createFailedSubResponse(credential, 412, CONDITION_NOT_MET_ERROR_CODE, CONDITION_NOT_MET_MESSAGE));
|
|
163
|
+
subResponsesFailedCount++;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
146
166
|
if (deleteMockBlob(containerName, blobName)) {
|
|
147
167
|
subResponses.push({
|
|
148
168
|
_request: {
|
|
@@ -175,6 +195,9 @@ var MockBlobBatchClient = class {
|
|
|
175
195
|
getContainer(containerName) {
|
|
176
196
|
return getMockContainer(containerName);
|
|
177
197
|
}
|
|
198
|
+
#checkIsModifiedSince(containerName, blobName, ifUnmodifiedSince) {
|
|
199
|
+
return ifUnmodifiedSince !== void 0 && getMockContainer(containerName).has(blobName) && readMockBlobDates(containerName, blobName).lastModified > ifUnmodifiedSince;
|
|
200
|
+
}
|
|
178
201
|
#createFailedSubResponse(credential, status, errorCode, statusMessage) {
|
|
179
202
|
return {
|
|
180
203
|
_request: {
|
|
@@ -201,17 +224,6 @@ var MockRestError = class extends RestError {
|
|
|
201
224
|
//#region src/services/container/getBlobUrl.ts
|
|
202
225
|
const getBlobUrl = (containerName, blobName) => `${MOCK_BLOB_BASE_URL}/${containerName}/${blobName.split("/").map((segment) => encodeURIComponent(segment)).join("/")}`;
|
|
203
226
|
//#endregion
|
|
204
|
-
//#region src/services/container/constants.ts
|
|
205
|
-
const MOCK_BLOB_SEEDED_DATE = /* @__PURE__ */ new Date(-864e13);
|
|
206
|
-
const MOCK_BLOB_SEEDED_PROPERTIES = {
|
|
207
|
-
createdOn: MOCK_BLOB_SEEDED_DATE,
|
|
208
|
-
etag: "\"seeded\"",
|
|
209
|
-
lastModified: MOCK_BLOB_SEEDED_DATE
|
|
210
|
-
};
|
|
211
|
-
//#endregion
|
|
212
|
-
//#region src/services/container/readMockBlobDates.ts
|
|
213
|
-
const readMockBlobDates = (containerName, blobName) => MockContainerBlobDatesDatabase.get(getMockBlobKey(containerName, blobName)) ?? MOCK_BLOB_SEEDED_PROPERTIES;
|
|
214
|
-
//#endregion
|
|
215
227
|
//#region src/services/container/storeMockBlobWrite.ts
|
|
216
228
|
const storeMockBlobWrite = (containerName, blobName, isExisting) => {
|
|
217
229
|
const key = getMockBlobKey(containerName, blobName);
|
|
@@ -290,9 +302,11 @@ var MockBlobClient = class {
|
|
|
290
302
|
}
|
|
291
303
|
download() {
|
|
292
304
|
const buffer = this.container.get(this.name);
|
|
305
|
+
if (!buffer) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
|
|
293
306
|
return Promise.resolve({
|
|
294
|
-
_response: createMockResponse(
|
|
295
|
-
|
|
307
|
+
_response: createMockResponse(200),
|
|
308
|
+
etag: readMockBlobDates(this.containerName, this.name).etag,
|
|
309
|
+
readableStreamBody: Readable.from(buffer)
|
|
296
310
|
});
|
|
297
311
|
}
|
|
298
312
|
downloadToBuffer() {
|
|
@@ -436,7 +450,11 @@ var MockBlockBlobClient = class extends MockBlobClient {
|
|
|
436
450
|
storeMockBlobWrite(this.containerName, this.name, this.container.has(this.name));
|
|
437
451
|
storeMockBlobMetadata(this.containerName, this.name, options?.metadata);
|
|
438
452
|
this.container.set(this.name, buffer);
|
|
439
|
-
|
|
453
|
+
const { etag } = readMockBlobDates(this.containerName, this.name);
|
|
454
|
+
return {
|
|
455
|
+
_response: createMockResponse(201),
|
|
456
|
+
etag
|
|
457
|
+
};
|
|
440
458
|
}
|
|
441
459
|
uploadBrowserData() {
|
|
442
460
|
throw new NotImplementedError(this.uploadBrowserData.name);
|
|
@@ -865,7 +883,7 @@ var MockQueueClient = class {
|
|
|
865
883
|
//#region src/services/filter/checkIsNullClause.ts
|
|
866
884
|
const checkIsNullClause = (clause) => {
|
|
867
885
|
const tableNullClause = getTableNullClause(clause.key);
|
|
868
|
-
return
|
|
886
|
+
return checkIsDeepEqual(clause, tableNullClause);
|
|
869
887
|
};
|
|
870
888
|
//#endregion
|
|
871
889
|
//#region src/services/filter/compare.ts
|
|
@@ -1233,28 +1251,12 @@ var MockTableClient = class {
|
|
|
1233
1251
|
const existingEntity = this.table.get(key);
|
|
1234
1252
|
if (!existingEntity) throw new MockRestError("The specified resource does not exist.", 404);
|
|
1235
1253
|
this.#assertEtag(existingEntity.etag, etag);
|
|
1236
|
-
|
|
1237
|
-
...existingEntity,
|
|
1238
|
-
...entity,
|
|
1239
|
-
etag: this.#getEtag()
|
|
1240
|
-
});
|
|
1241
|
-
else this.table.set(key, {
|
|
1242
|
-
...entity,
|
|
1243
|
-
etag: this.#getEtag()
|
|
1244
|
-
});
|
|
1254
|
+
this.#writeEntity(key, entity, mode, existingEntity);
|
|
1245
1255
|
}
|
|
1246
1256
|
#applyUpsert(entity, mode = "Merge") {
|
|
1247
1257
|
const key = this.#getCompositeKey(entity.partitionKey, entity.rowKey);
|
|
1248
1258
|
const existingEntity = this.table.get(key);
|
|
1249
|
-
|
|
1250
|
-
...existingEntity,
|
|
1251
|
-
...entity,
|
|
1252
|
-
etag: this.#getEtag()
|
|
1253
|
-
});
|
|
1254
|
-
else this.table.set(key, {
|
|
1255
|
-
...entity,
|
|
1256
|
-
etag: this.#getEtag()
|
|
1257
|
-
});
|
|
1259
|
+
this.#writeEntity(key, entity, mode, existingEntity);
|
|
1258
1260
|
}
|
|
1259
1261
|
#assertEtag(existingEtag, etag) {
|
|
1260
1262
|
if (etag !== void 0 && etag !== "*" && etag !== existingEtag) throw new MockRestError("The update condition specified in the request was not satisfied.", 412);
|
|
@@ -1271,6 +1273,17 @@ var MockTableClient = class {
|
|
|
1271
1273
|
etag: entity.etag ?? this.#getEtag()
|
|
1272
1274
|
};
|
|
1273
1275
|
}
|
|
1276
|
+
#writeEntity(key, entity, mode, existingEntity) {
|
|
1277
|
+
if (existingEntity && mode === "Merge") this.table.set(key, {
|
|
1278
|
+
...existingEntity,
|
|
1279
|
+
...entity,
|
|
1280
|
+
etag: this.#getEtag()
|
|
1281
|
+
});
|
|
1282
|
+
else this.table.set(key, {
|
|
1283
|
+
...entity,
|
|
1284
|
+
etag: this.#getEtag()
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1274
1287
|
};
|
|
1275
1288
|
//#endregion
|
|
1276
1289
|
//#region src/models/webPubSub/MockWebPubSubServiceClient.ts
|
|
@@ -1290,4 +1303,4 @@ const applyFilter = (documents, clauses) => {
|
|
|
1290
1303
|
return documents.filter((document) => predicate(document));
|
|
1291
1304
|
};
|
|
1292
1305
|
//#endregion
|
|
1293
|
-
export { BLOB_NOT_FOUND_ERROR_CODE, BLOB_NOT_FOUND_MESSAGE, MOCK_BLOB_BASE_URL, MOCK_BLOB_SEEDED_DATE, MOCK_BLOB_SEEDED_PROPERTIES, MOCK_QUEUE_BASE_URL, MOCK_SEARCH_BASE_URL, MOCK_TABLE_BASE_URL, MockBlobBatchClient, MockBlobClient, MockBlockBlobClient, MockContainerBlobDatesDatabase, MockContainerBlobMetadataDatabase, MockContainerClient, MockContainerDatabase, MockEventGridDatabase, MockEventGridPublisherClient, MockQueueClient, MockQueueDatabase, MockRestError, MockSearchClient, MockSearchDatabase, MockServiceBusDatabase, MockServiceBusSender, MockTableClient, MockTableDatabase, MockWebPubSubServiceClient, NotImplementedError, applyFilter, bodyToBuffer, checkIsNullClause, checkIsReadableStream, compare, compareByCompositeKey, createFilterPredicate, createMockResponse, deleteMockBlob, getAzureErrorXml, getBlobItemXml, getBlobPrefixXml, getBlobUrl, getBlobUrlParts, getListBlobsSegmentResponse, getListBlobsXml, getMockBlobKey, getMockContainer, getMockQueueMessageItem, getMockSasUrl, readMockBlobDates, readMockBlobMetadata, storeMockBlobMetadata, storeMockBlobWrite, toWebResourceLike };
|
|
1306
|
+
export { BLOB_NOT_FOUND_ERROR_CODE, BLOB_NOT_FOUND_MESSAGE, CONDITION_NOT_MET_ERROR_CODE, CONDITION_NOT_MET_MESSAGE, MOCK_BLOB_BASE_URL, MOCK_BLOB_SEEDED_DATE, MOCK_BLOB_SEEDED_PROPERTIES, MOCK_QUEUE_BASE_URL, MOCK_SEARCH_BASE_URL, MOCK_TABLE_BASE_URL, MockBlobBatchClient, MockBlobClient, MockBlockBlobClient, MockContainerBlobDatesDatabase, MockContainerBlobMetadataDatabase, MockContainerClient, MockContainerDatabase, MockEventGridDatabase, MockEventGridPublisherClient, MockQueueClient, MockQueueDatabase, MockRestError, MockSearchClient, MockSearchDatabase, MockServiceBusDatabase, MockServiceBusSender, MockTableClient, MockTableDatabase, MockWebPubSubServiceClient, NotImplementedError, applyFilter, bodyToBuffer, checkIsNullClause, checkIsReadableStream, compare, compareByCompositeKey, createFilterPredicate, createMockResponse, deleteMockBlob, getAzureErrorXml, getBlobItemXml, getBlobPrefixXml, getBlobUrl, getBlobUrlParts, getListBlobsSegmentResponse, getListBlobsXml, getMockBlobKey, getMockContainer, getMockQueueMessageItem, getMockSasUrl, readMockBlobDates, readMockBlobMetadata, storeMockBlobMetadata, storeMockBlobWrite, toWebResourceLike };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azure-mock",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "A library that contains azure mock classes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"azure",
|
|
@@ -53,18 +53,17 @@
|
|
|
53
53
|
"typecheck": "tsc"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@esposter/azure": "4.
|
|
57
|
-
"@esposter/shared": "4.
|
|
58
|
-
"fast-deep-equal": "^3.1.3"
|
|
56
|
+
"@esposter/azure": "4.1.0",
|
|
57
|
+
"@esposter/shared": "4.1.0"
|
|
59
58
|
},
|
|
60
59
|
"devDependencies": {
|
|
61
60
|
"@arethetypeswrong/core": "^0.18.5",
|
|
62
|
-
"@esposter/configuration": "4.
|
|
61
|
+
"@esposter/configuration": "4.1.0",
|
|
63
62
|
"publint": "^0.3.25",
|
|
64
|
-
"tsdown": "^0.23.
|
|
63
|
+
"tsdown": "^0.23.1",
|
|
65
64
|
"type-fest": "^5.10.0",
|
|
66
65
|
"typedoc": "^0.28.20",
|
|
67
|
-
"vitest": "^5.0.
|
|
66
|
+
"vitest": "^5.0.4"
|
|
68
67
|
},
|
|
69
68
|
"peerDependencies": {
|
|
70
69
|
"@azure/core-http-compat": "^2.5.0",
|
|
@@ -79,5 +78,5 @@
|
|
|
79
78
|
"inlinedDependencies": {
|
|
80
79
|
"type-fest": "5.10.0"
|
|
81
80
|
},
|
|
82
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "68de4c22fa7591bf6f6cc0fab2c9a906d8c4d71a"
|
|
83
82
|
}
|