@datalayer/core 0.0.10 → 0.0.11

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.
Files changed (195) hide show
  1. package/lib/__tests__/shared/cleanup-shared.d.ts +4 -0
  2. package/lib/__tests__/shared/cleanup-shared.js +228 -0
  3. package/lib/__tests__/shared/test-config.d.ts +51 -0
  4. package/lib/__tests__/shared/test-config.js +110 -0
  5. package/lib/__tests__/shared/test-constants.d.ts +66 -0
  6. package/lib/__tests__/shared/test-constants.js +79 -0
  7. package/lib/api/DatalayerApi.d.ts +1 -1
  8. package/lib/api/DatalayerApi.js +73 -42
  9. package/lib/api/__tests__/iam.authentication.integration.test.d.ts +1 -0
  10. package/lib/api/__tests__/iam.authentication.integration.test.js +247 -0
  11. package/lib/api/__tests__/iam.healthz.integration.test.d.ts +1 -0
  12. package/lib/api/__tests__/iam.healthz.integration.test.js +63 -0
  13. package/lib/api/__tests__/iam.profile.integration.test.d.ts +1 -0
  14. package/lib/api/__tests__/iam.profile.integration.test.js +252 -0
  15. package/lib/api/__tests__/runtimes.environments.integration.test.d.ts +1 -0
  16. package/lib/api/__tests__/runtimes.environments.integration.test.js +122 -0
  17. package/lib/api/__tests__/runtimes.healthz.integration.test.d.ts +1 -0
  18. package/lib/api/__tests__/runtimes.healthz.integration.test.js +50 -0
  19. package/lib/api/__tests__/runtimes.integration.test.d.ts +1 -0
  20. package/lib/api/__tests__/runtimes.integration.test.js +369 -0
  21. package/lib/api/__tests__/spacer.healthz.integration.test.d.ts +1 -0
  22. package/lib/api/__tests__/spacer.healthz.integration.test.js +50 -0
  23. package/lib/api/__tests__/spacer.integration.test.d.ts +1 -0
  24. package/lib/api/__tests__/spacer.integration.test.js +519 -0
  25. package/lib/api/constants.d.ts +19 -0
  26. package/lib/api/constants.js +23 -0
  27. package/lib/api/iam/__tests__/authentication.unit.test.d.ts +1 -0
  28. package/lib/api/iam/__tests__/authentication.unit.test.js +63 -0
  29. package/lib/api/iam/__tests__/healthz.unit.test.d.ts +1 -0
  30. package/lib/api/iam/__tests__/healthz.unit.test.js +60 -0
  31. package/lib/api/iam/__tests__/profile.unit.test.d.ts +1 -0
  32. package/lib/api/iam/__tests__/profile.unit.test.js +57 -0
  33. package/lib/api/iam/authentication.d.ts +40 -0
  34. package/lib/api/iam/authentication.js +128 -0
  35. package/lib/api/iam/healthz.d.ts +15 -0
  36. package/lib/api/iam/healthz.js +43 -0
  37. package/lib/api/iam/index.d.ts +12 -0
  38. package/lib/api/iam/index.js +17 -0
  39. package/lib/api/iam/profile.d.ts +15 -0
  40. package/lib/api/iam/profile.js +41 -0
  41. package/lib/api/index.d.ts +20 -3
  42. package/lib/api/index.js +22 -3
  43. package/lib/api/runtimes/__tests__/environments.unit.test.d.ts +1 -0
  44. package/lib/api/runtimes/__tests__/environments.unit.test.js +77 -0
  45. package/lib/api/runtimes/__tests__/healthz.unit.test.d.ts +1 -0
  46. package/lib/api/runtimes/__tests__/healthz.unit.test.js +57 -0
  47. package/lib/api/runtimes/__tests__/runtimes.unit.test.d.ts +1 -0
  48. package/lib/api/runtimes/__tests__/runtimes.unit.test.js +139 -0
  49. package/lib/api/runtimes/__tests__/snapshots.unit.test.d.ts +1 -0
  50. package/lib/api/runtimes/__tests__/snapshots.unit.test.js +96 -0
  51. package/lib/api/runtimes/environments.d.ts +9 -0
  52. package/lib/api/runtimes/environments.js +28 -0
  53. package/lib/api/runtimes/healthz.d.ts +25 -0
  54. package/lib/api/runtimes/healthz.js +43 -0
  55. package/lib/api/runtimes/index.d.ts +10 -5
  56. package/lib/api/runtimes/index.js +10 -5
  57. package/lib/api/runtimes/runtimes.d.ts +54 -0
  58. package/lib/api/runtimes/runtimes.js +169 -0
  59. package/lib/api/runtimes/snapshots.d.ts +34 -21
  60. package/lib/api/runtimes/snapshots.js +69 -138
  61. package/lib/api/spacer/__tests__/healthz.unit.test.d.ts +1 -0
  62. package/lib/api/spacer/__tests__/healthz.unit.test.js +57 -0
  63. package/lib/api/spacer/__tests__/items.unit.test.d.ts +1 -0
  64. package/lib/api/spacer/__tests__/items.unit.test.js +165 -0
  65. package/lib/api/spacer/__tests__/lexicals.unit.test.d.ts +1 -0
  66. package/lib/api/spacer/__tests__/lexicals.unit.test.js +323 -0
  67. package/lib/api/spacer/__tests__/notebooks.unit.test.d.ts +1 -0
  68. package/lib/api/spacer/__tests__/notebooks.unit.test.js +224 -0
  69. package/lib/api/spacer/__tests__/users.unit.test.d.ts +1 -0
  70. package/lib/api/spacer/__tests__/users.unit.test.js +132 -0
  71. package/lib/api/spacer/healthz.d.ts +25 -0
  72. package/lib/api/spacer/healthz.js +43 -0
  73. package/lib/api/spacer/index.d.ts +13 -0
  74. package/lib/api/spacer/index.js +17 -0
  75. package/lib/api/spacer/items.d.ts +17 -0
  76. package/lib/api/spacer/items.js +40 -0
  77. package/lib/api/spacer/lexicals.d.ts +26 -0
  78. package/lib/api/spacer/lexicals.js +74 -0
  79. package/lib/api/spacer/notebooks.d.ts +26 -0
  80. package/lib/api/spacer/notebooks.js +74 -0
  81. package/lib/api/spacer/spaces.d.ts +9 -0
  82. package/lib/api/spacer/spaces.js +29 -0
  83. package/lib/api/spacer/users.d.ts +9 -0
  84. package/lib/api/spacer/users.js +28 -0
  85. package/lib/api/types/iam.d.ts +180 -0
  86. package/lib/api/types/index.d.ts +32 -0
  87. package/lib/api/types/index.js +36 -0
  88. package/lib/api/types/runtimes.d.ts +235 -0
  89. package/lib/api/types/runtimes.js +5 -0
  90. package/lib/api/types/spacer.d.ts +271 -0
  91. package/lib/api/types/spacer.js +5 -0
  92. package/lib/api/utils/__tests__/validation.test.d.ts +1 -0
  93. package/lib/api/utils/__tests__/validation.test.js +109 -0
  94. package/lib/api/utils/validation.d.ts +24 -0
  95. package/lib/api/utils/validation.js +133 -0
  96. package/lib/components/progress/CreditsIndicator.d.ts +1 -1
  97. package/lib/components/runtimes/RuntimeCellVariablesDialog.js +1 -1
  98. package/lib/components/runtimes/RuntimeLauncherDialog.d.ts +1 -1
  99. package/lib/components/runtimes/RuntimeLauncherDialog.js +2 -1
  100. package/lib/components/runtimes/RuntimePickerBase.d.ts +1 -1
  101. package/lib/components/runtimes/RuntimePickerBase.js +1 -1
  102. package/lib/components/runtimes/RuntimePickerCell.js +2 -1
  103. package/lib/components/runtimes/RuntimePickerNotebook.d.ts +1 -1
  104. package/lib/components/runtimes/RuntimePickerNotebook.js +1 -1
  105. package/lib/components/runtimes/RuntimeSimplePicker.js +2 -1
  106. package/lib/components/runtimes/RuntimeTransfer.d.ts +1 -1
  107. package/lib/components/runtimes/RuntimeUtils.d.ts +1 -1
  108. package/lib/components/snapshots/RuntimeSnapshotMenu.d.ts +1 -1
  109. package/lib/components/snapshots/RuntimeSnapshotMenu.js +1 -1
  110. package/lib/hooks/useDatalayer.d.ts +1 -1
  111. package/lib/hooks/useDatalayer.js +1 -1
  112. package/lib/hooks/useIAM.js +1 -1
  113. package/lib/hooks/useRuntimes.js +1 -1
  114. package/lib/index.d.ts +9 -0
  115. package/lib/index.js +10 -0
  116. package/lib/sdk/client/__tests__/sdk.health.integration.test.d.ts +1 -0
  117. package/lib/sdk/client/__tests__/sdk.health.integration.test.js +110 -0
  118. package/lib/sdk/client/__tests__/sdk.iam.integration.test.d.ts +1 -0
  119. package/lib/sdk/client/__tests__/sdk.iam.integration.test.js +179 -0
  120. package/lib/sdk/client/__tests__/sdk.models.integration.test.d.ts +1 -0
  121. package/lib/sdk/client/__tests__/sdk.models.integration.test.js +376 -0
  122. package/lib/sdk/client/__tests__/sdk.runtimes.integration.test.d.ts +1 -0
  123. package/lib/sdk/client/__tests__/sdk.runtimes.integration.test.js +276 -0
  124. package/lib/sdk/client/__tests__/sdk.spacer.integration.test.d.ts +1 -0
  125. package/lib/sdk/client/__tests__/sdk.spacer.integration.test.js +361 -0
  126. package/lib/sdk/client/base.d.ts +88 -0
  127. package/lib/sdk/client/base.js +112 -0
  128. package/lib/sdk/client/index.d.ts +192 -0
  129. package/lib/sdk/client/index.js +128 -0
  130. package/lib/sdk/client/mixins/HealthMixin.d.ts +100 -0
  131. package/lib/sdk/client/mixins/HealthMixin.js +133 -0
  132. package/lib/sdk/client/mixins/IAMMixin.d.ts +59 -0
  133. package/lib/sdk/client/mixins/IAMMixin.js +83 -0
  134. package/lib/sdk/client/mixins/RuntimesMixin.d.ts +134 -0
  135. package/lib/sdk/client/mixins/RuntimesMixin.js +221 -0
  136. package/lib/sdk/client/mixins/SpacerMixin.d.ts +184 -0
  137. package/lib/sdk/client/mixins/SpacerMixin.js +278 -0
  138. package/lib/sdk/client/models/Lexical.d.ts +156 -0
  139. package/lib/sdk/client/models/Lexical.js +275 -0
  140. package/lib/sdk/client/models/Notebook.d.ts +174 -0
  141. package/lib/sdk/client/models/Notebook.js +311 -0
  142. package/lib/sdk/client/models/Runtime.d.ts +221 -0
  143. package/lib/sdk/client/models/Runtime.js +341 -0
  144. package/lib/sdk/client/models/Snapshot.d.ts +156 -0
  145. package/lib/sdk/client/models/Snapshot.js +244 -0
  146. package/lib/sdk/client/models/Space.d.ts +182 -0
  147. package/lib/sdk/client/models/Space.js +276 -0
  148. package/lib/sdk/client/models/__tests__/Lexical.test.d.ts +1 -0
  149. package/lib/sdk/client/models/__tests__/Lexical.test.js +288 -0
  150. package/lib/sdk/client/models/__tests__/Notebook.test.d.ts +1 -0
  151. package/lib/sdk/client/models/__tests__/Notebook.test.js +206 -0
  152. package/lib/sdk/client/models/__tests__/Runtime.test.d.ts +1 -0
  153. package/lib/sdk/client/models/__tests__/Runtime.test.js +133 -0
  154. package/lib/sdk/client/models/__tests__/Snapshot.test.d.ts +1 -0
  155. package/lib/sdk/client/models/__tests__/Snapshot.test.js +244 -0
  156. package/lib/sdk/client/models/__tests__/Space.test.d.ts +1 -0
  157. package/lib/sdk/client/models/__tests__/Space.test.js +334 -0
  158. package/lib/sdk/client/models/index.d.ts +30 -0
  159. package/lib/sdk/client/models/index.js +30 -0
  160. package/lib/sdk/client/utils/mixins.d.ts +42 -0
  161. package/lib/sdk/client/utils/mixins.js +47 -0
  162. package/lib/sdk/index.d.ts +26 -0
  163. package/lib/sdk/index.js +32 -0
  164. package/lib/sdk/stateful/index.d.ts +3 -0
  165. package/lib/sdk/stateful/index.js +7 -0
  166. package/lib/{api → sdk/stateful}/runtimes/actions.d.ts +1 -1
  167. package/lib/{api → sdk/stateful}/runtimes/actions.js +3 -3
  168. package/lib/{api → sdk/stateful}/runtimes/apis.d.ts +1 -1
  169. package/lib/sdk/stateful/runtimes/apis.js +5 -0
  170. package/lib/sdk/stateful/runtimes/index.d.ts +5 -0
  171. package/lib/sdk/stateful/runtimes/index.js +9 -0
  172. package/lib/sdk/stateful/runtimes/snapshots.d.ts +25 -0
  173. package/lib/sdk/stateful/runtimes/snapshots.js +150 -0
  174. package/lib/services/DatalayerServiceManager.js +1 -1
  175. package/lib/state/substates/IAMState.js +1 -1
  176. package/lib/state/substates/RuntimesState.d.ts +1 -1
  177. package/lib/state/substates/RuntimesState.js +1 -1
  178. package/lib/state/substates/SurveysState.js +1 -1
  179. package/lib/test-setup.js +1 -0
  180. package/package.json +19 -9
  181. /package/lib/api/{runtimes/apis.js → types/iam.js} +0 -0
  182. /package/lib/{api → sdk/stateful}/jupyter/exec/Python.d.ts +0 -0
  183. /package/lib/{api → sdk/stateful}/jupyter/exec/Python.js +0 -0
  184. /package/lib/{api → sdk/stateful}/jupyter/exec/Snippets.d.ts +0 -0
  185. /package/lib/{api → sdk/stateful}/jupyter/exec/Snippets.js +0 -0
  186. /package/lib/{api → sdk/stateful}/jupyter/exec/index.d.ts +0 -0
  187. /package/lib/{api → sdk/stateful}/jupyter/exec/index.js +0 -0
  188. /package/lib/{api → sdk/stateful}/jupyter/index.d.ts +0 -0
  189. /package/lib/{api → sdk/stateful}/jupyter/index.js +0 -0
  190. /package/lib/{api → sdk/stateful}/jupyter/kernelsHandler.d.ts +0 -0
  191. /package/lib/{api → sdk/stateful}/jupyter/kernelsHandler.js +0 -0
  192. /package/lib/{api → sdk/stateful}/runtimes/settings.d.ts +0 -0
  193. /package/lib/{api → sdk/stateful}/runtimes/settings.js +0 -0
  194. /package/lib/{api → sdk/stateful}/runtimes/utils.d.ts +0 -0
  195. /package/lib/{api → sdk/stateful}/runtimes/utils.js +0 -0
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Shared cleanup logic for both setup and teardown
3
+ */
4
+ export declare function performCleanup(phase: 'setup' | 'teardown'): Promise<void>;
@@ -0,0 +1,228 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { snapshots, runtimes } from '../../api/runtimes';
6
+ import { users, items } from '../../api/spacer';
7
+ import { testConfig } from './test-config';
8
+ /**
9
+ * Shared cleanup logic for both setup and teardown
10
+ */
11
+ export async function performCleanup(phase) {
12
+ const phaseLabel = phase === 'setup' ? 'PRE-TEST' : 'POST-TEST';
13
+ console.log('='.repeat(60));
14
+ console.log(`${phaseLabel} CLEANUP: Starting ${phase === 'setup' ? 'pre' : 'post'}-test cleanup...`);
15
+ console.log('='.repeat(60));
16
+ // Check if we have a token
17
+ if (!testConfig.hasToken()) {
18
+ console.log('WARNING: No Datalayer API token configured - skipping cleanup');
19
+ return;
20
+ }
21
+ const DATALAYER_TOKEN = testConfig.getToken();
22
+ const RUNTIMES_BASE_URL = testConfig.getBaseUrl('RUNTIMES');
23
+ const SPACER_BASE_URL = testConfig.getBaseUrl('SPACER');
24
+ // Clean up runtimes
25
+ await cleanupRuntimes(DATALAYER_TOKEN, RUNTIMES_BASE_URL, phaseLabel);
26
+ // Clean up test snapshots
27
+ await cleanupTestSnapshots(DATALAYER_TOKEN, RUNTIMES_BASE_URL, phaseLabel);
28
+ // Clean up ALL spacer items (notebooks, lexicals, etc.)
29
+ await cleanupSpacerItems(DATALAYER_TOKEN, SPACER_BASE_URL, phaseLabel);
30
+ // Final verification (only for teardown)
31
+ if (phase === 'teardown') {
32
+ await verifyFinalState(DATALAYER_TOKEN, RUNTIMES_BASE_URL, SPACER_BASE_URL);
33
+ }
34
+ console.log('='.repeat(60));
35
+ console.log(`${phaseLabel} CLEANUP: ${phase === 'setup' ? 'Pre' : 'Post'}-test cleanup completed`);
36
+ console.log('='.repeat(60));
37
+ }
38
+ async function cleanupRuntimes(token, baseUrl, phaseLabel) {
39
+ try {
40
+ console.log(`Cleaning up ${phaseLabel === 'PRE-TEST' ? 'existing' : 'test'} runtimes...`);
41
+ const runtimesResponse = await runtimes.listRuntimes(token, baseUrl);
42
+ if (!runtimesResponse.runtimes || runtimesResponse.runtimes.length === 0) {
43
+ console.log('✓ No runtimes to clean up');
44
+ return;
45
+ }
46
+ console.log(`Found ${runtimesResponse.runtimes.length} runtime(s) to clean up`);
47
+ let removedCount = 0;
48
+ let failedCount = 0;
49
+ for (const runtime of runtimesResponse.runtimes) {
50
+ try {
51
+ await runtimes.deleteRuntime(token, runtime.pod_name, baseUrl);
52
+ console.log(` ✓ Removed runtime: ${runtime.pod_name}`);
53
+ removedCount++;
54
+ }
55
+ catch (error) {
56
+ console.log(` ✗ Failed to remove runtime ${runtime.pod_name}: ${error.message}`);
57
+ failedCount++;
58
+ }
59
+ }
60
+ if (removedCount > 0 || failedCount > 0) {
61
+ console.log(`Runtime cleanup summary: ${removedCount} removed, ${failedCount} failed`);
62
+ }
63
+ }
64
+ catch (error) {
65
+ console.error('Error cleaning up runtimes:', error.message);
66
+ }
67
+ }
68
+ async function cleanupTestSnapshots(token, baseUrl, phaseLabel) {
69
+ try {
70
+ console.log(`Cleaning up ALL snapshots${phaseLabel === 'POST-TEST' ? ' created during tests' : ''}...`);
71
+ const snapshotsResponse = await snapshots.listSnapshots(token, baseUrl);
72
+ if (!snapshotsResponse.snapshots ||
73
+ snapshotsResponse.snapshots.length === 0) {
74
+ console.log('✓ No snapshots found');
75
+ return;
76
+ }
77
+ // Filter out already deleted snapshots
78
+ const allSnapshots = snapshotsResponse.snapshots.filter(s => s.status !== 'deleted');
79
+ if (allSnapshots.length === 0) {
80
+ const deletedCount = snapshotsResponse.snapshots.filter(s => s.status === 'deleted').length;
81
+ if (deletedCount > 0) {
82
+ console.log(`Found ${deletedCount} already deleted snapshot(s), skipping`);
83
+ }
84
+ console.log('✓ No active snapshots to clean up');
85
+ return;
86
+ }
87
+ console.log(`Found ${allSnapshots.length} active snapshot(s) to clean up`);
88
+ let removedCount = 0;
89
+ let skippedCount = 0;
90
+ let failedCount = 0;
91
+ for (const snapshot of allSnapshots) {
92
+ try {
93
+ console.log(` Attempting to delete: ${snapshot.name} (uid: ${snapshot.uid}, status: ${snapshot.status})`);
94
+ await snapshots.deleteSnapshot(token, snapshot.uid, baseUrl);
95
+ console.log(` ✓ Removed snapshot: ${snapshot.name}`);
96
+ removedCount++;
97
+ }
98
+ catch (error) {
99
+ if (error.message?.includes('404') ||
100
+ error.message?.includes('not found')) {
101
+ console.log(` - Already removed: ${snapshot.name}`);
102
+ skippedCount++;
103
+ }
104
+ else {
105
+ console.log(` ✗ Failed to remove snapshot ${snapshot.name}: ${error.message}`);
106
+ failedCount++;
107
+ }
108
+ }
109
+ }
110
+ if (removedCount > 0 || skippedCount > 0 || failedCount > 0) {
111
+ console.log(`Snapshot cleanup summary: ${removedCount} removed, ${skippedCount} skipped, ${failedCount} failed`);
112
+ // Verify snapshots are actually deleted
113
+ console.log('Verifying snapshot deletion...');
114
+ const verifyResponse = await snapshots.listSnapshots(token, baseUrl);
115
+ const remainingCount = verifyResponse.snapshots?.length || 0;
116
+ console.log(` Remaining snapshots after cleanup: ${remainingCount}`);
117
+ if (remainingCount > 0 && verifyResponse.snapshots) {
118
+ console.log(' Still present:');
119
+ for (const snap of verifyResponse.snapshots.slice(0, 5)) {
120
+ console.log(` - ${snap.name} (uid: ${snap.uid}, status: ${snap.status})`);
121
+ }
122
+ if (verifyResponse.snapshots.length > 5) {
123
+ console.log(` ... and ${verifyResponse.snapshots.length - 5} more`);
124
+ }
125
+ }
126
+ }
127
+ }
128
+ catch (error) {
129
+ console.error('Error cleaning up snapshots:', error.message);
130
+ }
131
+ }
132
+ async function cleanupSpacerItems(token, baseUrl, phaseLabel) {
133
+ try {
134
+ console.log(`Cleaning up ALL spacer items${phaseLabel === 'POST-TEST' ? ' (complete cleanup)' : ''}...`);
135
+ // Get user spaces
136
+ const spacesResponse = await users.getMySpaces(token, baseUrl);
137
+ if (!spacesResponse.spaces || spacesResponse.spaces.length === 0) {
138
+ console.log('✓ No spaces found');
139
+ return;
140
+ }
141
+ console.log(`Found ${spacesResponse.spaces.length} space(s)`);
142
+ let totalRemovedCount = 0;
143
+ let totalFailedCount = 0;
144
+ // Go through each space and clean up test items
145
+ for (const space of spacesResponse.spaces) {
146
+ try {
147
+ const itemsResponse = await items.getSpaceItems(token, space.uid, baseUrl);
148
+ if (!itemsResponse.items || itemsResponse.items.length === 0) {
149
+ continue;
150
+ }
151
+ const spaceName = space.name || space.name_t || 'Unknown Space';
152
+ console.log(` Space "${spaceName}": Found ${itemsResponse.items.length} item(s) to clean up`);
153
+ for (const item of itemsResponse.items) {
154
+ try {
155
+ // API returns uid field but TypeScript interface doesn't include it
156
+ await items.deleteItem(token, item.uid, baseUrl);
157
+ console.log(` ✓ Removed item: ${item.name || item.name_t}`);
158
+ totalRemovedCount++;
159
+ }
160
+ catch (error) {
161
+ console.log(` ✗ Failed to remove item ${item.name || item.name_t}: ${error.message}`);
162
+ totalFailedCount++;
163
+ }
164
+ }
165
+ }
166
+ catch (error) {
167
+ const spaceName = space.name || space.name_t || 'Unknown Space';
168
+ console.log(` Error processing space ${spaceName}: ${error.message}`);
169
+ }
170
+ }
171
+ if (totalRemovedCount > 0 || totalFailedCount > 0) {
172
+ console.log(`Spacer items cleanup summary: ${totalRemovedCount} removed, ${totalFailedCount} failed`);
173
+ }
174
+ else {
175
+ console.log('✓ No spacer items to clean up');
176
+ }
177
+ }
178
+ catch (error) {
179
+ console.error('Error cleaning up spacer items:', error.message);
180
+ }
181
+ }
182
+ async function verifyFinalState(token, runtimesBaseUrl, spacerBaseUrl) {
183
+ try {
184
+ const finalRuntimes = await runtimes.listRuntimes(token, runtimesBaseUrl);
185
+ const finalSnapshots = await snapshots.listSnapshots(token, runtimesBaseUrl);
186
+ const remainingRuntimes = finalRuntimes.runtimes?.length || 0;
187
+ const remainingSnapshots = (finalSnapshots.snapshots || []).filter(s => s.status !== 'deleted').length;
188
+ // Count spacer test items
189
+ let remainingTestItems = 0;
190
+ try {
191
+ const spacesResponse = await users.getMySpaces(token, spacerBaseUrl);
192
+ if (spacesResponse.spaces) {
193
+ for (const space of spacesResponse.spaces) {
194
+ try {
195
+ const itemsResponse = await items.getSpaceItems(token, space.uid, spacerBaseUrl);
196
+ if (itemsResponse.items) {
197
+ remainingTestItems += itemsResponse.items.length;
198
+ }
199
+ }
200
+ catch (error) {
201
+ // Ignore errors for individual spaces
202
+ }
203
+ }
204
+ }
205
+ }
206
+ catch (error) {
207
+ // Ignore errors
208
+ }
209
+ console.log('-'.repeat(60));
210
+ console.log('Final state after all tests:');
211
+ console.log(` - Remaining runtimes: ${remainingRuntimes}`);
212
+ console.log(` - Remaining active snapshots: ${remainingSnapshots}`);
213
+ console.log(` - Total snapshots: ${finalSnapshots.snapshots?.length || 0}`);
214
+ console.log(` - Remaining spacer items: ${remainingTestItems}`);
215
+ if (remainingRuntimes > 0) {
216
+ console.log(`\nNOTE: ${remainingRuntimes} runtime(s) still active. These may require manual cleanup.`);
217
+ }
218
+ if (remainingSnapshots > 0) {
219
+ console.log(`\nNOTE: ${remainingSnapshots} snapshot(s) still active. These may require manual cleanup.`);
220
+ }
221
+ if (remainingTestItems > 0) {
222
+ console.log(`\nNOTE: ${remainingTestItems} spacer item(s) still active. These may require manual cleanup.`);
223
+ }
224
+ }
225
+ catch (error) {
226
+ console.error('Error during final verification:', error.message);
227
+ }
228
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Test configuration object with proper fallbacks
3
+ */
4
+ export declare const testConfig: {
5
+ /**
6
+ * Check if we have a token available
7
+ */
8
+ hasToken(): boolean;
9
+ /**
10
+ * Get the Datalayer API token for testing
11
+ * Priority order:
12
+ * 1. DATALAYER_TEST_TOKEN environment variable
13
+ * 2. DATALAYER_API_TOKEN environment variable
14
+ * 3. VITE_DATALAYER_API_TOKEN environment variable
15
+ * 4. Throw error if not found
16
+ */
17
+ getToken(): string;
18
+ /**
19
+ * Get the base URL for testing
20
+ * Uses DEFAULT_SERVICE_URLS or can be overridden via environment
21
+ */
22
+ getBaseUrl(service?: "IAM" | "RUNTIMES" | "SPACER"): string;
23
+ /**
24
+ * Check if expensive tests should be skipped
25
+ * Default is false (run expensive tests) unless explicitly set to 'true'
26
+ */
27
+ shouldSkipExpensive(): boolean;
28
+ /**
29
+ * Get test environment names for runtime creation
30
+ */
31
+ getTestEnvironments(): {
32
+ python: string;
33
+ ai: string;
34
+ };
35
+ /**
36
+ * Check if debug output is enabled
37
+ */
38
+ isDebugEnabled(): boolean;
39
+ /**
40
+ * Get custom timeout for API calls (in milliseconds)
41
+ */
42
+ getTimeout(): number;
43
+ };
44
+ /**
45
+ * Helper function to skip tests if no token is available
46
+ */
47
+ export declare const skipIfNoToken: () => boolean;
48
+ /**
49
+ * Log debug information if debug is enabled
50
+ */
51
+ export declare const debugLog: (...args: any[]) => void;
@@ -0,0 +1,110 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import * as dotenv from 'dotenv';
6
+ import * as path from 'path';
7
+ import { DEFAULT_SERVICE_URLS } from '../../api/constants';
8
+ /**
9
+ * Load test environment configuration
10
+ * Loads from .env.test file and falls back to environment variables
11
+ */
12
+ const loadTestConfig = () => {
13
+ // Load .env.test file from project root
14
+ const testEnvPath = path.resolve(process.cwd(), '.env.test');
15
+ dotenv.config({ path: testEnvPath });
16
+ // Also load regular .env as fallback
17
+ dotenv.config();
18
+ };
19
+ // Load config immediately when module is imported
20
+ loadTestConfig();
21
+ /**
22
+ * Test configuration object with proper fallbacks
23
+ */
24
+ export const testConfig = {
25
+ /**
26
+ * Check if we have a token available
27
+ */
28
+ hasToken() {
29
+ return !!(process.env.DATALAYER_TEST_TOKEN ||
30
+ process.env.DATALAYER_API_TOKEN ||
31
+ process.env.VITE_DATALAYER_API_TOKEN);
32
+ },
33
+ /**
34
+ * Get the Datalayer API token for testing
35
+ * Priority order:
36
+ * 1. DATALAYER_TEST_TOKEN environment variable
37
+ * 2. DATALAYER_API_TOKEN environment variable
38
+ * 3. VITE_DATALAYER_API_TOKEN environment variable
39
+ * 4. Throw error if not found
40
+ */
41
+ getToken() {
42
+ const token = process.env.DATALAYER_TEST_TOKEN ||
43
+ process.env.DATALAYER_API_TOKEN ||
44
+ process.env.VITE_DATALAYER_API_TOKEN;
45
+ if (!token) {
46
+ throw new Error('No Datalayer API token found. Please set DATALAYER_TEST_TOKEN, DATALAYER_API_TOKEN, or VITE_DATALAYER_API_TOKEN environment variable');
47
+ }
48
+ return token;
49
+ },
50
+ /**
51
+ * Get the base URL for testing
52
+ * Uses DEFAULT_SERVICE_URLS or can be overridden via environment
53
+ */
54
+ getBaseUrl(service = 'IAM') {
55
+ const envBaseUrl = process.env.DATALAYER_TEST_BASE_URL;
56
+ if (envBaseUrl) {
57
+ return envBaseUrl;
58
+ }
59
+ return DEFAULT_SERVICE_URLS[service];
60
+ },
61
+ /**
62
+ * Check if expensive tests should be skipped
63
+ * Default is false (run expensive tests) unless explicitly set to 'true'
64
+ */
65
+ shouldSkipExpensive() {
66
+ return process.env.DATALAYER_TEST_SKIP_EXPENSIVE === 'true';
67
+ },
68
+ /**
69
+ * Get test environment names for runtime creation
70
+ */
71
+ getTestEnvironments() {
72
+ return {
73
+ python: process.env.DATALAYER_TEST_PYTHON_ENV || 'python-cpu-env',
74
+ ai: process.env.DATALAYER_TEST_AI_ENV || 'ai-env',
75
+ };
76
+ },
77
+ /**
78
+ * Check if debug output is enabled
79
+ */
80
+ isDebugEnabled() {
81
+ return process.env.DATALAYER_TEST_DEBUG === 'true';
82
+ },
83
+ /**
84
+ * Get custom timeout for API calls (in milliseconds)
85
+ */
86
+ getTimeout() {
87
+ const timeout = process.env.DATALAYER_TEST_TIMEOUT;
88
+ return timeout ? parseInt(timeout, 10) : 60000; // Default 60 seconds
89
+ },
90
+ };
91
+ /**
92
+ * Helper function to skip tests if no token is available
93
+ */
94
+ export const skipIfNoToken = () => {
95
+ try {
96
+ testConfig.getToken();
97
+ return false;
98
+ }
99
+ catch {
100
+ return true;
101
+ }
102
+ };
103
+ /**
104
+ * Log debug information if debug is enabled
105
+ */
106
+ export const debugLog = (...args) => {
107
+ if (testConfig.isDebugEnabled()) {
108
+ console.log('[DEBUG]', ...args);
109
+ }
110
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Test constants for API unit tests
3
+ */
4
+ /**
5
+ * A valid mock JWT token for testing
6
+ * This token has the correct JWT structure (header.payload.signature) but is not cryptographically valid
7
+ *
8
+ * Decoded header: {"alg":"HS256","typ":"JWT"}
9
+ * Decoded payload: {"sub":"test-user","iss":"test-issuer","iat":1700000000,"exp":9999999999,"aud":"test-audience"}
10
+ *
11
+ * The token is constructed to:
12
+ * - Have three parts separated by dots
13
+ * - Have valid base64url encoded parts
14
+ * - Have proper JWT header with alg and typ
15
+ * - Have common JWT claims in payload
16
+ * - Have an expiration far in the future to avoid expiration errors
17
+ * - Be long enough to pass length validation (>100 chars)
18
+ */
19
+ export declare const MOCK_JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0LXVzZXIiLCJpc3MiOiJ0ZXN0LWlzc3VlciIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjo5OTk5OTk5OTk5LCJhdWQiOiJ0ZXN0LWF1ZGllbmNlIn0.abcdefghijklmnopqrstuvwxyz012345678901234567890";
20
+ /**
21
+ * An invalid token (not JWT format) for negative testing
22
+ */
23
+ export declare const INVALID_TOKEN = "invalid-token";
24
+ /**
25
+ * A malformed JWT token (only two parts instead of three)
26
+ */
27
+ export declare const MALFORMED_JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ";
28
+ /**
29
+ * A JWT token with an expired timestamp
30
+ * Decoded payload: {"sub":"test-user","exp":1000000000}
31
+ */
32
+ export declare const EXPIRED_JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0LXVzZXIiLCJleHAiOjEwMDAwMDAwMDB9.abcdefghijklmnopqrstuvwxyz012345678901234567890";
33
+ /**
34
+ * Mock API responses
35
+ */
36
+ export declare const MOCK_ENVIRONMENTS_RESPONSE: {
37
+ success: boolean;
38
+ message: string;
39
+ environments: {
40
+ title: string;
41
+ description: string;
42
+ dockerImage: string;
43
+ language: string;
44
+ burning_rate: number;
45
+ }[];
46
+ };
47
+ export declare const MOCK_RUNTIME_RESPONSE: {
48
+ success: boolean;
49
+ message: string;
50
+ runtime: {
51
+ pod_name: string;
52
+ status: string;
53
+ environment: string;
54
+ created_at: string;
55
+ };
56
+ };
57
+ export declare const MOCK_SNAPSHOT_RESPONSE: {
58
+ success: boolean;
59
+ message: string;
60
+ snapshot: {
61
+ id: string;
62
+ name: string;
63
+ created_at: string;
64
+ size: number;
65
+ };
66
+ };
@@ -0,0 +1,79 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Test constants for API unit tests
7
+ */
8
+ /**
9
+ * A valid mock JWT token for testing
10
+ * This token has the correct JWT structure (header.payload.signature) but is not cryptographically valid
11
+ *
12
+ * Decoded header: {"alg":"HS256","typ":"JWT"}
13
+ * Decoded payload: {"sub":"test-user","iss":"test-issuer","iat":1700000000,"exp":9999999999,"aud":"test-audience"}
14
+ *
15
+ * The token is constructed to:
16
+ * - Have three parts separated by dots
17
+ * - Have valid base64url encoded parts
18
+ * - Have proper JWT header with alg and typ
19
+ * - Have common JWT claims in payload
20
+ * - Have an expiration far in the future to avoid expiration errors
21
+ * - Be long enough to pass length validation (>100 chars)
22
+ */
23
+ export const MOCK_JWT_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0LXVzZXIiLCJpc3MiOiJ0ZXN0LWlzc3VlciIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjo5OTk5OTk5OTk5LCJhdWQiOiJ0ZXN0LWF1ZGllbmNlIn0.abcdefghijklmnopqrstuvwxyz012345678901234567890';
24
+ /**
25
+ * An invalid token (not JWT format) for negative testing
26
+ */
27
+ export const INVALID_TOKEN = 'invalid-token';
28
+ /**
29
+ * A malformed JWT token (only two parts instead of three)
30
+ */
31
+ export const MALFORMED_JWT_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ';
32
+ /**
33
+ * A JWT token with an expired timestamp
34
+ * Decoded payload: {"sub":"test-user","exp":1000000000}
35
+ */
36
+ export const EXPIRED_JWT_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0LXVzZXIiLCJleHAiOjEwMDAwMDAwMDB9.abcdefghijklmnopqrstuvwxyz012345678901234567890';
37
+ /**
38
+ * Mock API responses
39
+ */
40
+ export const MOCK_ENVIRONMENTS_RESPONSE = {
41
+ success: true,
42
+ message: 'Environments retrieved successfully',
43
+ environments: [
44
+ {
45
+ title: 'Python Base',
46
+ description: 'Basic Python environment',
47
+ dockerImage: 'python:3.9',
48
+ language: 'python',
49
+ burning_rate: 1,
50
+ },
51
+ {
52
+ title: 'R Statistical',
53
+ description: 'R environment for statistical computing',
54
+ dockerImage: 'r-base:4.3',
55
+ language: 'r',
56
+ burning_rate: 2,
57
+ },
58
+ ],
59
+ };
60
+ export const MOCK_RUNTIME_RESPONSE = {
61
+ success: true,
62
+ message: 'Runtime retrieved successfully',
63
+ runtime: {
64
+ pod_name: 'test-runtime-pod',
65
+ status: 'running',
66
+ environment: 'python-base',
67
+ created_at: '2024-01-01T00:00:00Z',
68
+ },
69
+ };
70
+ export const MOCK_SNAPSHOT_RESPONSE = {
71
+ success: true,
72
+ message: 'Snapshot retrieved successfully',
73
+ snapshot: {
74
+ id: 'test-snapshot-123',
75
+ name: 'Test Snapshot',
76
+ created_at: '2024-01-01T00:00:00Z',
77
+ size: 1024000,
78
+ },
79
+ };
@@ -56,7 +56,7 @@ export interface IRequestDatalayerAPIOptions {
56
56
  */
57
57
  method?: string;
58
58
  /**
59
- * JSON-serializable object
59
+ * JSON-serializable object or FormData
60
60
  */
61
61
  body?: any;
62
62
  /**