@tellescope/sdk 1.252.3 → 1.253.1
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/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js +256 -0
- package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
- package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js +168 -0
- package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
- package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +325 -0
- package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/set_fields_order_templates.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/set_fields_order_templates.test.js +177 -0
- package/lib/cjs/tests/api_tests/set_fields_order_templates.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/user_portal_settings.test.js +104 -28
- package/lib/cjs/tests/api_tests/user_portal_settings.test.js.map +1 -1
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +444 -174
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/beluga_manual_sync.test.js +252 -0
- package/lib/esm/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
- package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
- package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/gcal_sync_retry.test.js +164 -0
- package/lib/esm/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
- package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +321 -0
- package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
- package/lib/esm/tests/api_tests/set_fields_order_templates.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/set_fields_order_templates.test.js +177 -0
- package/lib/esm/tests/api_tests/set_fields_order_templates.test.js.map +1 -1
- package/lib/esm/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/user_portal_settings.test.js +104 -28
- package/lib/esm/tests/api_tests/user_portal_settings.test.js.map +1 -1
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +444 -174
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/tests/api_tests/beluga_manual_sync.test.ts +159 -0
- package/src/tests/api_tests/gcal_sync_retry.test.ts +104 -0
- package/src/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.ts +214 -0
- package/src/tests/api_tests/set_fields_order_templates.test.ts +122 -0
- package/src/tests/api_tests/user_portal_settings.test.ts +71 -1
- package/src/tests/tests.ts +222 -6
- package/test_generated.pdf +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beluga_manual_sync.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/api_tests/beluga_manual_sync.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAkBnC,eAAO,MAAM,wBAAwB;SAAuC,OAAO;iBAAe,OAAO;mBAqHxG,CAAA"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.beluga_manual_sync_tests = void 0;
|
|
40
|
+
require('source-map-support').install();
|
|
41
|
+
var sdk_1 = require("../../sdk");
|
|
42
|
+
var testing_1 = require("@tellescope/testing");
|
|
43
|
+
var setup_1 = require("../setup");
|
|
44
|
+
var constants_1 = require("@tellescope/constants");
|
|
45
|
+
var host = process.env.API_URL || 'http://localhost:8080';
|
|
46
|
+
// Manual Beluga re-sync guard tests (CU-86e1uxz1n).
|
|
47
|
+
// - form_responses.push_to_EHR with target === BELUGA_TITLE
|
|
48
|
+
// - files.push with destination === BELUGA_TITLE
|
|
49
|
+
//
|
|
50
|
+
// Fast / no-upload: this only verifies the bad-input / guard branches that reject before any
|
|
51
|
+
// Beluga call. It performs NO S3 file uploads and triggers NO actual sync (both slow and require
|
|
52
|
+
// live Beluga sandbox credentials). File records are created via prepare_file_upload alone — that
|
|
53
|
+
// inserts the DB record, which is all the guards need.
|
|
54
|
+
var beluga_manual_sync_tests = function (_a) {
|
|
55
|
+
var sdk = _a.sdk, sdkNonAdmin = _a.sdkNonAdmin;
|
|
56
|
+
return __awaiter(void 0, void 0, void 0, function () {
|
|
57
|
+
var errorMessage, enduserId, belugaFormId, plainFormId, fileIds, createdBelugaIntegrationId, enduser_1, belugaForm, plainForm, plainField_1, submitForm, createFileRecord, draft_1, plainResponseId_1, belugaIntegrationAvailable, existing, _b, created, e_1, unlinkedFile_1, _i, fileIds_1, id;
|
|
58
|
+
return __generator(this, function (_c) {
|
|
59
|
+
switch (_c.label) {
|
|
60
|
+
case 0:
|
|
61
|
+
(0, testing_1.log_header)("Beluga Manual Sync Guard Tests (FormResponses & Files)");
|
|
62
|
+
errorMessage = function (e) { var _a; return ((e === null || e === void 0 ? void 0 : e.message) || ((_a = e === null || e === void 0 ? void 0 : e.toString) === null || _a === void 0 ? void 0 : _a.call(e)) || JSON.stringify(e)); };
|
|
63
|
+
fileIds = [];
|
|
64
|
+
_c.label = 1;
|
|
65
|
+
case 1:
|
|
66
|
+
_c.trys.push([1, , 22, 35]);
|
|
67
|
+
return [4 /*yield*/, sdk.api.endusers.createOne({
|
|
68
|
+
fname: 'beluga-sync',
|
|
69
|
+
email: "beluga_manual_sync_".concat(Date.now(), "@test.tellescope.com"),
|
|
70
|
+
})];
|
|
71
|
+
case 2:
|
|
72
|
+
enduser_1 = _c.sent();
|
|
73
|
+
enduserId = enduser_1.id;
|
|
74
|
+
return [4 /*yield*/, sdk.api.forms.createOne({ title: 'Beluga Manual Sync Form', belugaVisitType: 'sync' })];
|
|
75
|
+
case 3:
|
|
76
|
+
belugaForm = _c.sent();
|
|
77
|
+
belugaFormId = belugaForm.id;
|
|
78
|
+
return [4 /*yield*/, sdk.api.forms.createOne({ title: 'Non-Beluga Manual Sync Form' })];
|
|
79
|
+
case 4:
|
|
80
|
+
plainForm = _c.sent();
|
|
81
|
+
plainFormId = plainForm.id;
|
|
82
|
+
return [4 /*yield*/, sdk.api.form_fields.createOne({
|
|
83
|
+
formId: plainForm.id, type: 'string', title: 'Field', previousFields: [{ type: 'root', info: {} }],
|
|
84
|
+
})];
|
|
85
|
+
case 5:
|
|
86
|
+
plainField_1 = _c.sent();
|
|
87
|
+
submitForm = function (formId) { return __awaiter(void 0, void 0, void 0, function () {
|
|
88
|
+
var _a, accessCode, response;
|
|
89
|
+
return __generator(this, function (_b) {
|
|
90
|
+
switch (_b.label) {
|
|
91
|
+
case 0: return [4 /*yield*/, sdk.api.form_responses.prepare_form_response({ enduserId: enduser_1.id, formId: formId })];
|
|
92
|
+
case 1:
|
|
93
|
+
_a = _b.sent(), accessCode = _a.accessCode, response = _a.response;
|
|
94
|
+
return [4 /*yield*/, sdk.api.form_responses.submit_form_response({
|
|
95
|
+
accessCode: accessCode,
|
|
96
|
+
responses: [{ fieldId: plainField_1.id, fieldTitle: 'Field', answer: { type: 'string', value: 'x' } }],
|
|
97
|
+
})];
|
|
98
|
+
case 2:
|
|
99
|
+
_b.sent();
|
|
100
|
+
return [2 /*return*/, response.id];
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}); };
|
|
104
|
+
createFileRecord = function (name) { return __awaiter(void 0, void 0, void 0, function () {
|
|
105
|
+
var file;
|
|
106
|
+
return __generator(this, function (_a) {
|
|
107
|
+
switch (_a.label) {
|
|
108
|
+
case 0: return [4 /*yield*/, sdk.api.files.prepare_file_upload({
|
|
109
|
+
name: name,
|
|
110
|
+
type: 'text/plain', size: 1, enduserId: enduser_1.id,
|
|
111
|
+
})];
|
|
112
|
+
case 1:
|
|
113
|
+
file = (_a.sent()).file;
|
|
114
|
+
fileIds.push(file.id);
|
|
115
|
+
return [2 /*return*/, file];
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}); };
|
|
119
|
+
return [4 /*yield*/, sdk.api.form_responses.prepare_form_response({ enduserId: enduser_1.id, formId: belugaForm.id })];
|
|
120
|
+
case 6:
|
|
121
|
+
draft_1 = (_c.sent()).response;
|
|
122
|
+
return [4 /*yield*/, (0, testing_1.async_test)("push_to_EHR(target=BELUGA) rejects an unsubmitted form response", function () { return sdk.api.form_responses.push_to_EHR({ id: draft_1.id, target: constants_1.BELUGA_TITLE }); }, { shouldError: true, onError: function (e) { return /has not been submitted/i.test(errorMessage(e)); } })
|
|
123
|
+
// Submitted, but the form has no belugaVisitType → rejected as not configured
|
|
124
|
+
];
|
|
125
|
+
case 7:
|
|
126
|
+
_c.sent();
|
|
127
|
+
return [4 /*yield*/, submitForm(plainForm.id)];
|
|
128
|
+
case 8:
|
|
129
|
+
plainResponseId_1 = _c.sent();
|
|
130
|
+
return [4 /*yield*/, (0, testing_1.async_test)("push_to_EHR(target=BELUGA) rejects a form not configured for Beluga", function () { return sdk.api.form_responses.push_to_EHR({ id: plainResponseId_1, target: constants_1.BELUGA_TITLE }); }, { shouldError: true, onError: function (e) { return /not configured for Beluga/i.test(errorMessage(e)); } })
|
|
131
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
132
|
+
// 2. files.push(destination=BELUGA) guard — the endpoint resolves the destination
|
|
133
|
+
// integration first, so a Beluga integration must exist for the branch to be reached.
|
|
134
|
+
// Create a placeholder if the org has none; skip gracefully if that's not permitted.
|
|
135
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
136
|
+
];
|
|
137
|
+
case 9:
|
|
138
|
+
_c.sent();
|
|
139
|
+
belugaIntegrationAvailable = false;
|
|
140
|
+
_c.label = 10;
|
|
141
|
+
case 10:
|
|
142
|
+
_c.trys.push([10, 12, , 13]);
|
|
143
|
+
return [4 /*yield*/, sdk.api.integrations.load_redacted({})];
|
|
144
|
+
case 11:
|
|
145
|
+
existing = _c.sent();
|
|
146
|
+
belugaIntegrationAvailable = !!existing.integrations.find(function (i) { return i.title === constants_1.BELUGA_TITLE; });
|
|
147
|
+
return [3 /*break*/, 13];
|
|
148
|
+
case 12:
|
|
149
|
+
_b = _c.sent();
|
|
150
|
+
return [3 /*break*/, 13];
|
|
151
|
+
case 13:
|
|
152
|
+
if (!!belugaIntegrationAvailable) return [3 /*break*/, 17];
|
|
153
|
+
_c.label = 14;
|
|
154
|
+
case 14:
|
|
155
|
+
_c.trys.push([14, 16, , 17]);
|
|
156
|
+
return [4 /*yield*/, sdk.api.integrations.createOne({
|
|
157
|
+
title: constants_1.BELUGA_TITLE,
|
|
158
|
+
authentication: {
|
|
159
|
+
type: 'oauth2',
|
|
160
|
+
info: { access_token: 'test-access-token', refresh_token: 'test-refresh-token', scope: '', token_type: 'Bearer', expiry_date: new Date().getTime() },
|
|
161
|
+
},
|
|
162
|
+
})];
|
|
163
|
+
case 15:
|
|
164
|
+
created = _c.sent();
|
|
165
|
+
createdBelugaIntegrationId = created.id;
|
|
166
|
+
belugaIntegrationAvailable = true;
|
|
167
|
+
return [3 /*break*/, 17];
|
|
168
|
+
case 16:
|
|
169
|
+
e_1 = _c.sent();
|
|
170
|
+
console.log("Could not create a Beluga integration for testing; skipping files.push guard:", errorMessage(e_1));
|
|
171
|
+
return [3 /*break*/, 17];
|
|
172
|
+
case 17:
|
|
173
|
+
if (!belugaIntegrationAvailable) return [3 /*break*/, 20];
|
|
174
|
+
return [4 /*yield*/, createFileRecord('beluga-unlinked.txt')];
|
|
175
|
+
case 18:
|
|
176
|
+
unlinkedFile_1 = _c.sent();
|
|
177
|
+
return [4 /*yield*/, (0, testing_1.async_test)("files.push(destination=BELUGA) rejects a file with no associated form response", function () { return sdk.api.files.push({ id: unlinkedFile_1.id, destination: constants_1.BELUGA_TITLE }); }, { shouldError: true, onError: function (e) { return /not associated with a form response/i.test(errorMessage(e)); } })];
|
|
178
|
+
case 19:
|
|
179
|
+
_c.sent();
|
|
180
|
+
return [3 /*break*/, 21];
|
|
181
|
+
case 20:
|
|
182
|
+
console.log("⏭️ Skipping files.push(destination=BELUGA) guard (no Beluga integration available)");
|
|
183
|
+
_c.label = 21;
|
|
184
|
+
case 21: return [3 /*break*/, 35];
|
|
185
|
+
case 22:
|
|
186
|
+
_i = 0, fileIds_1 = fileIds;
|
|
187
|
+
_c.label = 23;
|
|
188
|
+
case 23:
|
|
189
|
+
if (!(_i < fileIds_1.length)) return [3 /*break*/, 26];
|
|
190
|
+
id = fileIds_1[_i];
|
|
191
|
+
return [4 /*yield*/, sdk.api.files.deleteOne(id).catch(console.error)];
|
|
192
|
+
case 24:
|
|
193
|
+
_c.sent();
|
|
194
|
+
_c.label = 25;
|
|
195
|
+
case 25:
|
|
196
|
+
_i++;
|
|
197
|
+
return [3 /*break*/, 23];
|
|
198
|
+
case 26:
|
|
199
|
+
if (!belugaFormId) return [3 /*break*/, 28];
|
|
200
|
+
return [4 /*yield*/, sdk.api.forms.deleteOne(belugaFormId).catch(console.error)];
|
|
201
|
+
case 27:
|
|
202
|
+
_c.sent();
|
|
203
|
+
_c.label = 28;
|
|
204
|
+
case 28:
|
|
205
|
+
if (!plainFormId) return [3 /*break*/, 30];
|
|
206
|
+
return [4 /*yield*/, sdk.api.forms.deleteOne(plainFormId).catch(console.error)];
|
|
207
|
+
case 29:
|
|
208
|
+
_c.sent();
|
|
209
|
+
_c.label = 30;
|
|
210
|
+
case 30:
|
|
211
|
+
if (!enduserId) return [3 /*break*/, 32];
|
|
212
|
+
return [4 /*yield*/, sdk.api.endusers.deleteOne(enduserId).catch(console.error)];
|
|
213
|
+
case 31:
|
|
214
|
+
_c.sent();
|
|
215
|
+
_c.label = 32;
|
|
216
|
+
case 32:
|
|
217
|
+
if (!createdBelugaIntegrationId) return [3 /*break*/, 34];
|
|
218
|
+
return [4 /*yield*/, sdk.api.integrations.deleteOne(createdBelugaIntegrationId).catch(console.error)];
|
|
219
|
+
case 33:
|
|
220
|
+
_c.sent();
|
|
221
|
+
_c.label = 34;
|
|
222
|
+
case 34: return [7 /*endfinally*/];
|
|
223
|
+
case 35: return [2 /*return*/];
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
};
|
|
228
|
+
exports.beluga_manual_sync_tests = beluga_manual_sync_tests;
|
|
229
|
+
if (require.main === module) {
|
|
230
|
+
console.log("Using API URL: ".concat(host));
|
|
231
|
+
var sdk_2 = new sdk_1.Session({ host: host });
|
|
232
|
+
var sdkNonAdmin_1 = new sdk_1.Session({ host: host });
|
|
233
|
+
var runTests = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
234
|
+
return __generator(this, function (_a) {
|
|
235
|
+
switch (_a.label) {
|
|
236
|
+
case 0: return [4 /*yield*/, (0, setup_1.setup_tests)(sdk_2, sdkNonAdmin_1)];
|
|
237
|
+
case 1:
|
|
238
|
+
_a.sent();
|
|
239
|
+
return [4 /*yield*/, (0, exports.beluga_manual_sync_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
|
|
240
|
+
case 2:
|
|
241
|
+
_a.sent();
|
|
242
|
+
return [2 /*return*/];
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}); };
|
|
246
|
+
runTests()
|
|
247
|
+
.then(function () {
|
|
248
|
+
console.log("✅ Beluga manual sync test suite completed successfully");
|
|
249
|
+
process.exit(0);
|
|
250
|
+
})
|
|
251
|
+
.catch(function (error) {
|
|
252
|
+
console.error("❌ Beluga manual sync test suite failed:", error);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=beluga_manual_sync.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beluga_manual_sync.test.js","sourceRoot":"","sources":["../../../../src/tests/api_tests/beluga_manual_sync.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,CAAC,oBAAoB,CAAC,CAAC,OAAO,EAAE,CAAC;AAExC,iCAAmC;AACnC,+CAG4B;AAC5B,kCAAsC;AACtC,mDAAoD;AAEpD,IAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,uBAAgC,CAAA;AAEpE,oDAAoD;AACpD,8DAA8D;AAC9D,mDAAmD;AACnD,EAAE;AACF,6FAA6F;AAC7F,iGAAiG;AACjG,kGAAkG;AAClG,uDAAuD;AAChD,IAAM,wBAAwB,GAAG,UAAO,EAA4D;QAA1D,GAAG,SAAA,EAAE,WAAW,iBAAA;;;;;;oBAC/D,IAAA,oBAAU,EAAC,wDAAwD,CAAC,CAAA;oBAE9D,YAAY,GAAG,UAAC,CAAM,YAAK,OAAA,CAAC,CAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,OAAO,MAAI,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,QAAQ,iDAAI,CAAA,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAW,CAAA,EAAA,CAAA;oBAKzF,OAAO,GAAa,EAAE,CAAA;;;;oBAIV,qBAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;4BAC/C,KAAK,EAAE,aAAa;4BACpB,KAAK,EAAE,6BAAsB,IAAI,CAAC,GAAG,EAAE,yBAAsB;yBAC9D,CAAC,EAAA;;oBAHI,YAAU,SAGd;oBACF,SAAS,GAAG,SAAO,CAAC,EAAE,CAAA;oBAGH,qBAAM,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,EAAA;;oBAAzG,UAAU,GAAG,SAA4F;oBAC/G,YAAY,GAAG,UAAU,CAAC,EAAE,CAAA;oBAEV,qBAAM,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAC,EAAA;;oBAAnF,SAAS,GAAG,SAAuE;oBACzF,WAAW,GAAG,SAAS,CAAC,EAAE,CAAA;oBAEP,qBAAM,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC;4BACrD,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;yBACnG,CAAC,EAAA;;oBAFI,eAAa,SAEjB;oBAEI,UAAU,GAAG,UAAO,MAAc;;;;wCACL,qBAAM,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,qBAAqB,CAAC,EAAE,SAAS,EAAE,SAAO,CAAC,EAAE,EAAE,MAAM,QAAA,EAAE,CAAC,EAAA;;oCAAhH,KAA2B,SAAqF,EAA9G,UAAU,gBAAA,EAAE,QAAQ,cAAA;oCAC5B,qBAAM,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,oBAAoB,CAAC;4CAChD,UAAU,YAAA;4CACV,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,YAAU,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC;yCACrG,CAAC,EAAA;;oCAHF,SAGE,CAAA;oCACF,sBAAO,QAAQ,CAAC,EAAE,EAAA;;;yBACnB,CAAA;oBAKK,gBAAgB,GAAG,UAAO,IAAY;;;;wCACzB,qBAAM,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC;wCACvD,IAAI,MAAA;wCAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,SAAO,CAAC,EAAE;qCACzD,CAAC,EAAA;;oCAFM,IAAI,GAAK,CAAA,SAEf,CAAA,KAFU;oCAGZ,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;oCACrB,sBAAO,IAAI,EAAA;;;yBACZ,CAAA;oBAO2B,qBAAM,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,qBAAqB,CAAC,EAAE,SAAS,EAAE,SAAO,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,EAAA;;oBAAxH,UAAoB,CAAA,SAAoG,CAAA,SAAzG;oBACvB,qBAAM,IAAA,oBAAU,EACd,iEAAiE,EACjE,cAAM,OAAA,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,OAAK,CAAC,EAAE,EAAE,MAAM,EAAE,wBAAY,EAAE,CAAC,EAA1E,CAA0E,EAChF,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,UAAC,CAAM,IAAK,OAAA,yBAAyB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAA/C,CAA+C,EAAE,CAC5F;wBAED,8EAA8E;sBAF7E;;oBAJD,SAIC,CAAA;oBAGuB,qBAAM,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,EAAA;;oBAAhD,oBAAkB,SAA8B;oBACtD,qBAAM,IAAA,oBAAU,EACd,qEAAqE,EACrE,cAAM,OAAA,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,iBAAe,EAAE,MAAM,EAAE,wBAAY,EAAE,CAAC,EAAjF,CAAiF,EACvF,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,UAAC,CAAM,IAAK,OAAA,4BAA4B,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAlD,CAAkD,EAAE,CAC/F;wBAED,6EAA6E;wBAC7E,kFAAkF;wBAClF,yFAAyF;wBACzF,wFAAwF;wBACxF,6EAA6E;sBAN5E;;oBAJD,SAIC,CAAA;oBAQG,0BAA0B,GAAG,KAAK,CAAA;;;;oBAEnB,qBAAM,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE,CAAC,EAAA;;oBAAvD,QAAQ,GAAG,SAA4C;oBAC7D,0BAA0B,GAAG,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,UAAC,CAAM,IAAK,OAAA,CAAC,CAAC,KAAK,KAAK,wBAAY,EAAxB,CAAwB,CAAC,CAAA;;;;;;yBAG7F,CAAC,0BAA0B,EAA3B,yBAA2B;;;;oBAEX,qBAAM,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC;4BACnD,KAAK,EAAE,wBAAY;4BACnB,cAAc,EAAE;gCACd,IAAI,EAAE,QAAQ;gCACd,IAAI,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,oBAAoB,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE;6BACrJ;yBACF,CAAC,EAAA;;oBANI,OAAO,GAAG,SAMd;oBACF,0BAA0B,GAAG,OAAO,CAAC,EAAE,CAAA;oBACvC,0BAA0B,GAAG,IAAI,CAAA;;;;oBAEjC,OAAO,CAAC,GAAG,CAAC,+EAA+E,EAAE,YAAY,CAAC,GAAC,CAAC,CAAC,CAAA;;;yBAI7G,0BAA0B,EAA1B,yBAA0B;oBAEP,qBAAM,gBAAgB,CAAC,qBAAqB,CAAC,EAAA;;oBAA5D,iBAAe,SAA6C;oBAClE,qBAAM,IAAA,oBAAU,EACd,gFAAgF,EAChF,cAAM,OAAA,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,cAAY,CAAC,EAAE,EAAE,WAAW,EAAE,wBAAY,EAAE,CAAC,EAAtE,CAAsE,EAC5E,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,UAAC,CAAM,IAAK,OAAA,sCAAsC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAA5D,CAA4D,EAAE,CACzG,EAAA;;oBAJD,SAIC,CAAA;;;oBAED,OAAO,CAAC,GAAG,CAAC,qFAAqF,CAAC,CAAA;;;;0BAG5E,EAAP,mBAAO;;;yBAAP,CAAA,qBAAO,CAAA;oBAAb,EAAE;oBACX,qBAAM,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAA;;oBAAtD,SAAsD,CAAA;;;oBADvC,IAAO,CAAA;;;yBAGpB,YAAY,EAAZ,yBAAY;oBAAE,qBAAM,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAA;;oBAAhE,SAAgE,CAAA;;;yBAC9E,WAAW,EAAX,yBAAW;oBAAE,qBAAM,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAA;;oBAA/D,SAA+D,CAAA;;;yBAC5E,SAAS,EAAT,yBAAS;oBAAE,qBAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAA;;oBAAhE,SAAgE,CAAA;;;yBAC3E,0BAA0B,EAA1B,yBAA0B;oBAAE,qBAAM,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAA;;oBAArF,SAAqF,CAAA;;;;;;;CAExH,CAAA;AArHY,QAAA,wBAAwB,4BAqHpC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE;IAC3B,OAAO,CAAC,GAAG,CAAC,yBAAkB,IAAI,CAAE,CAAC,CAAA;IACrC,IAAM,KAAG,GAAG,IAAI,aAAO,CAAC,EAAE,IAAI,MAAA,EAAE,CAAC,CAAA;IACjC,IAAM,aAAW,GAAG,IAAI,aAAO,CAAC,EAAE,IAAI,MAAA,EAAE,CAAC,CAAA;IAEzC,IAAM,QAAQ,GAAG;;;wBACf,qBAAM,IAAA,mBAAW,EAAC,KAAG,EAAE,aAAW,CAAC,EAAA;;oBAAnC,SAAmC,CAAA;oBACnC,qBAAM,IAAA,gCAAwB,EAAC,EAAE,GAAG,OAAA,EAAE,WAAW,eAAA,EAAE,CAAC,EAAA;;oBAApD,SAAoD,CAAA;;;;SACrD,CAAA;IAED,QAAQ,EAAE;SACP,IAAI,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAA;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAC;SACD,KAAK,CAAC,UAAC,KAAK;QACX,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAA;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAC,CAAA;CACL"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Session } from "../../sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Google Calendar sync retry — integration coverage.
|
|
4
|
+
*
|
|
5
|
+
* ┌─ ARCHITECTURE NOTE (why the full mock-Google scenarios are gated) ──────────┐
|
|
6
|
+
* │ SDK api_tests run in a SEPARATE process from the API server (they talk to │
|
|
7
|
+
* │ host = API_URL / http://localhost:8080). The retry scheduler, the Google │
|
|
8
|
+
* │ retryable-error predicates, and the google.calendar() client all live in the │
|
|
9
|
+
* │ API SERVER process. A stub installed here (in the SDK test process) cannot │
|
|
10
|
+
* │ replace the server's in-process google client, so we cannot deterministically│
|
|
11
|
+
* │ inject 429 / 500 / ECONNRESET responses from this test alone. │
|
|
12
|
+
* │ │
|
|
13
|
+
* │ Two ways to run the full fail-429-then-succeed / exhaustion / cap scenarios: │
|
|
14
|
+
* │ 1. Run the API server with NODE_ENV=test and RETRY_SCHEDULER_DELAYS_MS=10,20 │
|
|
15
|
+
* │ (already honored by the singleton constructor) plus a server-side │
|
|
16
|
+
* │ fault-injection hook on sdk.events.* that reads e.g. │
|
|
17
|
+
* │ process.env.GCAL_TEST_FORCE_ERROR — that hook does not exist yet. │
|
|
18
|
+
* │ 2. Drive the scheduler directly with the in-process unit tests, which DO │
|
|
19
|
+
* │ cover all retry mechanics deterministically: │
|
|
20
|
+
* │ packages/private/api/api/modules/retry_scheduler.test.ts │
|
|
21
|
+
* │ packages/private/api/api/integrations/google.test.ts │
|
|
22
|
+
* │ │
|
|
23
|
+
* │ The scenario matrix below is recorded for when a server-side hook is added. │
|
|
24
|
+
* └──────────────────────────────────────────────────────────────────────────────┘
|
|
25
|
+
*
|
|
26
|
+
* Scenario matrix (requires server-side Google fault injection — see note):
|
|
27
|
+
* 1. create retry: fail 429 once then succeed -> gcal reference written, NO background_errors
|
|
28
|
+
* 2. exhaustion: fail 429 on every call -> exactly one "Google Calendar Push Error" background_errors row
|
|
29
|
+
* 3. non-retryable: fail 403 -> background_errors written immediately, no retries
|
|
30
|
+
* 4. create idempotency: fail ECONNRESET (network) -> NON-retryable for create (duplicate risk),
|
|
31
|
+
* background_errors written, no retry, no duplicate insert
|
|
32
|
+
* 5. update + delete: same as (1) for events.patch and events.delete
|
|
33
|
+
* 6. cap exceeded: maxOpenRetries=2, 3 events all fail retryably -> 3rd -> background_errors immediately
|
|
34
|
+
*
|
|
35
|
+
* The runnable assertions below cover what IS observable end-to-end without a
|
|
36
|
+
* connected Google account: the refactored call sites must not regress the common
|
|
37
|
+
* "user has no Google integration" path (no sync attempt, no background_errors, no retry).
|
|
38
|
+
*/
|
|
39
|
+
export declare const gcal_sync_retry_tests: ({ sdk }: {
|
|
40
|
+
sdk: Session;
|
|
41
|
+
sdkNonAdmin: Session;
|
|
42
|
+
}) => Promise<void>;
|
|
43
|
+
//# sourceMappingURL=gcal_sync_retry.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcal_sync_retry.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/api_tests/gcal_sync_retry.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAUnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,qBAAqB;SAA2B,OAAO;iBAAe,OAAO;mBAwCzF,CAAA"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.gcal_sync_retry_tests = void 0;
|
|
40
|
+
require('source-map-support').install();
|
|
41
|
+
var sdk_1 = require("../../sdk");
|
|
42
|
+
var testing_1 = require("@tellescope/testing");
|
|
43
|
+
var setup_1 = require("../setup");
|
|
44
|
+
var host = process.env.API_URL || 'http://localhost:8080';
|
|
45
|
+
/**
|
|
46
|
+
* Google Calendar sync retry — integration coverage.
|
|
47
|
+
*
|
|
48
|
+
* ┌─ ARCHITECTURE NOTE (why the full mock-Google scenarios are gated) ──────────┐
|
|
49
|
+
* │ SDK api_tests run in a SEPARATE process from the API server (they talk to │
|
|
50
|
+
* │ host = API_URL / http://localhost:8080). The retry scheduler, the Google │
|
|
51
|
+
* │ retryable-error predicates, and the google.calendar() client all live in the │
|
|
52
|
+
* │ API SERVER process. A stub installed here (in the SDK test process) cannot │
|
|
53
|
+
* │ replace the server's in-process google client, so we cannot deterministically│
|
|
54
|
+
* │ inject 429 / 500 / ECONNRESET responses from this test alone. │
|
|
55
|
+
* │ │
|
|
56
|
+
* │ Two ways to run the full fail-429-then-succeed / exhaustion / cap scenarios: │
|
|
57
|
+
* │ 1. Run the API server with NODE_ENV=test and RETRY_SCHEDULER_DELAYS_MS=10,20 │
|
|
58
|
+
* │ (already honored by the singleton constructor) plus a server-side │
|
|
59
|
+
* │ fault-injection hook on sdk.events.* that reads e.g. │
|
|
60
|
+
* │ process.env.GCAL_TEST_FORCE_ERROR — that hook does not exist yet. │
|
|
61
|
+
* │ 2. Drive the scheduler directly with the in-process unit tests, which DO │
|
|
62
|
+
* │ cover all retry mechanics deterministically: │
|
|
63
|
+
* │ packages/private/api/api/modules/retry_scheduler.test.ts │
|
|
64
|
+
* │ packages/private/api/api/integrations/google.test.ts │
|
|
65
|
+
* │ │
|
|
66
|
+
* │ The scenario matrix below is recorded for when a server-side hook is added. │
|
|
67
|
+
* └──────────────────────────────────────────────────────────────────────────────┘
|
|
68
|
+
*
|
|
69
|
+
* Scenario matrix (requires server-side Google fault injection — see note):
|
|
70
|
+
* 1. create retry: fail 429 once then succeed -> gcal reference written, NO background_errors
|
|
71
|
+
* 2. exhaustion: fail 429 on every call -> exactly one "Google Calendar Push Error" background_errors row
|
|
72
|
+
* 3. non-retryable: fail 403 -> background_errors written immediately, no retries
|
|
73
|
+
* 4. create idempotency: fail ECONNRESET (network) -> NON-retryable for create (duplicate risk),
|
|
74
|
+
* background_errors written, no retry, no duplicate insert
|
|
75
|
+
* 5. update + delete: same as (1) for events.patch and events.delete
|
|
76
|
+
* 6. cap exceeded: maxOpenRetries=2, 3 events all fail retryably -> 3rd -> background_errors immediately
|
|
77
|
+
*
|
|
78
|
+
* The runnable assertions below cover what IS observable end-to-end without a
|
|
79
|
+
* connected Google account: the refactored call sites must not regress the common
|
|
80
|
+
* "user has no Google integration" path (no sync attempt, no background_errors, no retry).
|
|
81
|
+
*/
|
|
82
|
+
var gcal_sync_retry_tests = function (_a) {
|
|
83
|
+
var sdk = _a.sdk;
|
|
84
|
+
return __awaiter(void 0, void 0, void 0, function () {
|
|
85
|
+
var enduser;
|
|
86
|
+
return __generator(this, function (_b) {
|
|
87
|
+
switch (_b.label) {
|
|
88
|
+
case 0:
|
|
89
|
+
(0, testing_1.log_header)("Google Calendar Sync Retry");
|
|
90
|
+
if (process.env.GCAL_RETRY_INTEGRATION !== '1') {
|
|
91
|
+
console.log("ℹ️ Skipping mock-Google scenarios (set GCAL_RETRY_INTEGRATION=1 with a server-side "
|
|
92
|
+
+ "fault-injection hook to run scenarios 1-6). Running no-integration regression checks only.");
|
|
93
|
+
}
|
|
94
|
+
return [4 /*yield*/, sdk.api.endusers.createOne({ fname: 'GcalRetry', lname: 'Test' })];
|
|
95
|
+
case 1:
|
|
96
|
+
enduser = _b.sent();
|
|
97
|
+
return [4 /*yield*/, (0, testing_1.async_test)('create event for user without Google integration does not produce a background error', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
98
|
+
var event, errors;
|
|
99
|
+
return __generator(this, function (_a) {
|
|
100
|
+
switch (_a.label) {
|
|
101
|
+
case 0: return [4 /*yield*/, sdk.api.calendar_events.createOne({
|
|
102
|
+
title: 'Gcal Retry Regression',
|
|
103
|
+
startTimeInMS: Date.now() + 1000 * 60 * 60,
|
|
104
|
+
durationInMinutes: 30,
|
|
105
|
+
attendees: [{ type: 'user', id: sdk.userInfo.id }, { type: 'enduser', id: enduser.id }],
|
|
106
|
+
})
|
|
107
|
+
// give side-effect handlers a moment to run
|
|
108
|
+
];
|
|
109
|
+
case 1:
|
|
110
|
+
event = _a.sent();
|
|
111
|
+
// give side-effect handlers a moment to run
|
|
112
|
+
return [4 /*yield*/, (0, testing_1.wait)(undefined, 750)];
|
|
113
|
+
case 2:
|
|
114
|
+
// give side-effect handlers a moment to run
|
|
115
|
+
_a.sent();
|
|
116
|
+
return [4 /*yield*/, sdk.api.background_errors.getSome({}).catch(function () { return []; })
|
|
117
|
+
// clean up
|
|
118
|
+
];
|
|
119
|
+
case 3:
|
|
120
|
+
errors = _a.sent();
|
|
121
|
+
// clean up
|
|
122
|
+
return [4 /*yield*/, sdk.api.calendar_events.deleteOne(event.id).catch(function () { })
|
|
123
|
+
// No Google integration on the test user => no push attempt => no error row.
|
|
124
|
+
];
|
|
125
|
+
case 4:
|
|
126
|
+
// clean up
|
|
127
|
+
_a.sent();
|
|
128
|
+
// No Google integration on the test user => no push attempt => no error row.
|
|
129
|
+
return [2 /*return*/, errors.filter(function (e) { return (e.userId === sdk.userInfo.id && e.title === "Google Calendar Push Error"); }).length];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}); }, { onResult: function (count) { return count === 0; } })
|
|
133
|
+
// cleanup
|
|
134
|
+
];
|
|
135
|
+
case 2:
|
|
136
|
+
_b.sent();
|
|
137
|
+
// cleanup
|
|
138
|
+
return [4 /*yield*/, sdk.api.endusers.deleteOne(enduser.id).catch(function () { })];
|
|
139
|
+
case 3:
|
|
140
|
+
// cleanup
|
|
141
|
+
_b.sent();
|
|
142
|
+
return [2 /*return*/];
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
exports.gcal_sync_retry_tests = gcal_sync_retry_tests;
|
|
148
|
+
if (require.main === module) {
|
|
149
|
+
var sdk_2 = new sdk_1.Session({ host: host });
|
|
150
|
+
var sdkNonAdmin_1 = new sdk_1.Session({ host: host });
|
|
151
|
+
var runTests = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
152
|
+
return __generator(this, function (_a) {
|
|
153
|
+
switch (_a.label) {
|
|
154
|
+
case 0: return [4 /*yield*/, (0, setup_1.setup_tests)(sdk_2, sdkNonAdmin_1)];
|
|
155
|
+
case 1:
|
|
156
|
+
_a.sent();
|
|
157
|
+
return [4 /*yield*/, (0, exports.gcal_sync_retry_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
|
|
158
|
+
case 2:
|
|
159
|
+
_a.sent();
|
|
160
|
+
return [2 /*return*/];
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}); };
|
|
164
|
+
runTests()
|
|
165
|
+
.then(function () { console.log("✅ gcal sync retry test suite completed successfully"); process.exit(0); })
|
|
166
|
+
.catch(function (error) { console.error("❌ gcal sync retry test suite failed:", error); process.exit(1); });
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=gcal_sync_retry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcal_sync_retry.test.js","sourceRoot":"","sources":["../../../../src/tests/api_tests/gcal_sync_retry.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Session } from "../../../sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Regression test for F-0106 and F-0110
|
|
4
|
+
* (security-audit/findings/F-0106-enduser-self-update-admin-only-fields.md,
|
|
5
|
+
* security-audit/findings/F-0110-form-responses-enduser-update-admin-only-fields.md).
|
|
6
|
+
*
|
|
7
|
+
* Endusers could PATCH admin-only / access-bearing / attribution-bearing fields on
|
|
8
|
+
* their own endusers record (assignedTo, tags, references, ...) and their own
|
|
9
|
+
* form_responses (procedureCodes, submittedBy, markedAsSubmitted, ...). The fix adds
|
|
10
|
+
* the `enduserUpdatesDisabled` field option (schema.ts ModelFieldInfo), enforced for
|
|
11
|
+
* enduser sessions in the generic update handler (routing.ts createDefaultEndpoints).
|
|
12
|
+
*
|
|
13
|
+
* This test asserts, for every flagged field on both models:
|
|
14
|
+
* - an enduser session updating its OWN record gets a 400 "<field> cannot be updated by endusers"
|
|
15
|
+
* - nothing persists (spot-checked on assignedTo, the highest-impact field)
|
|
16
|
+
* - enduser self-updates of allowed fields still work (fname, hideFromEnduserPortal)
|
|
17
|
+
* - staff sessions can still update the restricted fields
|
|
18
|
+
*/
|
|
19
|
+
export declare const enduser_write_restrictions_tests: ({ sdk }: {
|
|
20
|
+
sdk: Session;
|
|
21
|
+
sdkNonAdmin: Session;
|
|
22
|
+
}) => Promise<void>;
|
|
23
|
+
//# sourceMappingURL=F-0106-F-0110-enduser-write-restrictions.test.d.ts.map
|
package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"F-0106-F-0110-enduser-write-restrictions.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAkB,MAAM,cAAc,CAAA;AA+DtD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gCAAgC;SAA2B,OAAO;iBAAe,OAAO;mBA6GpG,CAAA"}
|