CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/database/postgres/site-license/hook.test.ts
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/**
7
* This tests the core of ./hook.ts
8
* It's not using it directly, though, because of the complex dependency of the database.
9
* The main purpose of this test is to simulate what happens, if first a partial set of licenses,
10
* and then one more license is fed through the quota function.
11
* There was a bug, where licenses were modified in place, and the second call to the quota function
12
* used the modified license, which led to very subtle but severe problems.
13
*
14
* The quota function uses a deep copy operation on all its arguments to avoid this.
15
*/
16
17
// see packages/database/pool/pool.ts for where this name is also hard coded:
18
process.env.PGDATABASE = "smc_ephemeral_testing_database";
19
20
import { isEqual } from "lodash";
21
22
import getPool, { initEphemeralDatabase } from "@cocalc/database/pool";
23
import { quota_with_reasons, SiteLicenses } from "@cocalc/util/upgrades/quota";
24
25
beforeAll(async () => {
26
await initEphemeralDatabase({});
27
}, 15000);
28
29
afterAll(async () => {
30
await getPool().end();
31
});
32
33
test("allow for much larger max_upgrades", () => {
34
const site_settings = {
35
default_quotas: {
36
internet: true,
37
idle_timeout: 1800,
38
mem: 2000,
39
cpu: 1,
40
cpu_oc: 20,
41
mem_oc: 10,
42
},
43
max_upgrades: {
44
disk_quota: 20000,
45
memory: 50000,
46
memory_request: 1000,
47
cores: 16,
48
network: 1,
49
cpu_shares: 1024,
50
mintime: 7776000,
51
member_host: 1,
52
ephemeral_state: 1,
53
ephemeral_disk: 1,
54
always_running: 1,
55
},
56
kucalc: "onprem",
57
datastore: true,
58
};
59
60
const site_licenses: SiteLicenses = {
61
a: {
62
quota: { cpu: 2, ram: 13 },
63
},
64
b: {
65
quota: { cpu: 3, ram: 32 },
66
},
67
};
68
69
const q1 = quota_with_reasons(
70
{},
71
{ userX: {} },
72
{ a: site_licenses.a },
73
site_settings,
74
);
75
expect(q1).toEqual({
76
quota: {
77
network: true,
78
member_host: false,
79
privileged: false,
80
gpu: false,
81
memory_request: 1000,
82
cpu_request: 0.1,
83
disk_quota: 3000,
84
memory_limit: 13000,
85
cpu_limit: 2,
86
idle_timeout: 1800,
87
always_running: false,
88
dedicated_vm: false,
89
dedicated_disks: [],
90
},
91
reasons: {},
92
});
93
94
const q2 = quota_with_reasons(
95
{},
96
{ userX: {} },
97
site_licenses,
98
site_settings,
99
);
100
expect(q2).toEqual({
101
quota: {
102
always_running: false,
103
cpu_limit: 5,
104
cpu_request: 0.25,
105
dedicated_disks: [],
106
dedicated_vm: false,
107
disk_quota: 3000,
108
idle_timeout: 1800,
109
member_host: false,
110
memory_limit: 45000,
111
memory_request: 1000,
112
network: true,
113
privileged: false,
114
gpu: false,
115
},
116
reasons: {},
117
});
118
});
119
120
test("two licenses", () => {
121
const site_settings = {
122
default_quotas: {
123
internet: true,
124
idle_timeout: 1800,
125
mem: 2000,
126
cpu: 1,
127
cpu_oc: 20,
128
mem_oc: 10,
129
},
130
max_upgrades: {
131
disk_quota: 20000,
132
memory: 50000,
133
memory_request: 1000,
134
cores: 16,
135
network: 1,
136
cpu_shares: 1024,
137
mintime: 7776000,
138
member_host: 1,
139
ephemeral_state: 1,
140
ephemeral_disk: 1,
141
always_running: 1,
142
},
143
kucalc: "onprem",
144
datastore: true,
145
};
146
147
const site_licenses = {
148
a: {
149
quota: { cpu: 1, ram: 13 },
150
},
151
b: {
152
quota: { cpu: 3, ram: 32 },
153
},
154
};
155
156
const q1 = quota_with_reasons(
157
{},
158
{ userX: {} },
159
{ a: site_licenses.a },
160
site_settings,
161
);
162
expect(q1).toEqual({
163
quota: {
164
network: true,
165
member_host: false,
166
privileged: false,
167
gpu: false,
168
memory_request: 1000,
169
cpu_request: 0.05,
170
disk_quota: 3000,
171
memory_limit: 13000,
172
cpu_limit: 1,
173
idle_timeout: 1800,
174
always_running: false,
175
dedicated_vm: false,
176
dedicated_disks: [],
177
},
178
reasons: {},
179
});
180
181
const q2 = quota_with_reasons(
182
{},
183
{ userX: {} },
184
site_licenses,
185
site_settings,
186
);
187
expect(q1).toEqual({
188
quota: {
189
network: true,
190
member_host: false,
191
privileged: false,
192
gpu: false,
193
memory_request: 1000,
194
cpu_request: 0.05,
195
disk_quota: 3000,
196
memory_limit: 13000,
197
cpu_limit: 1,
198
idle_timeout: 1800,
199
always_running: false,
200
dedicated_vm: false,
201
dedicated_disks: [],
202
},
203
reasons: {},
204
});
205
206
expect(q2).toEqual({
207
quota: {
208
always_running: false,
209
cpu_limit: 4,
210
cpu_request: 0.2,
211
dedicated_disks: [],
212
dedicated_vm: false,
213
disk_quota: 3000,
214
idle_timeout: 1800,
215
member_host: false,
216
memory_limit: 45000,
217
memory_request: 1000,
218
network: true,
219
privileged: false,
220
gpu: false,
221
},
222
reasons: {},
223
});
224
225
// in particular, this implies that the second license indeed HAS an effect and hence will be used.
226
expect(isEqual(q1, q2)).toBe(false);
227
});
228
229
// TODO the test below would be very important to get to work, but the call to the site_license_hook has no effect at all
230
231
// describe("site_license_hook", () => {
232
// const pool = getPool();
233
// const account_id = uuid();
234
// const license_id_1 = uuid();
235
// const license_id_2 = uuid();
236
237
// let project_id;
238
// test("creates a project", async () => {
239
// project_id = await createProject({
240
// account_id,
241
// title: "Test Project",
242
// });
243
// });
244
245
// test("setup project license", async () => {
246
// const site_licenses_data: SiteLicenses = {
247
// [license_id_1]: {
248
// quota: {
249
// dedicated_disk: { speed: "standard", size_gb: 128, name: "bar" },
250
// },
251
// },
252
// [license_id_2]: {
253
// quota: {
254
// ram: 2,
255
// cpu: 1,
256
// disk: 3,
257
// always_running: true,
258
// member: true,
259
// user: "academic",
260
// },
261
// },
262
// };
263
264
// await pool.query(
265
// "UPDATE projects SET site_license=$1 WHERE project_id=$2",
266
// [site_licenses_data, project_id]
267
// );
268
// });
269
270
// test("PAYGO mixes with dedicated disk", async () => {
271
// // run the hook -- "true" means there are PAYGO upgrades, different mode of how the license hook operates
272
// await site_license_hook(db(), project_id, true);
273
274
// const { rows } = await pool.query(
275
// "SELECT * FROM projects WHERE project_id=$1",
276
// [project_id]
277
// );
278
// expect(rows.length).toBe(1);
279
// const site_licenses = rows[0].site_license;
280
// expect(rows[0].site_license).toEqual({
281
// [license_id_1]: {
282
// quota: {
283
// dedicated_disk: { name: "bar", size_gb: 128, speed: "standard" },
284
// },
285
// },
286
// [license_id_2]: {
287
// quota: {
288
// always_running: true,
289
// cpu: 1,
290
// disk: 3,
291
// member: true,
292
// ram: 2,
293
// user: "academic",
294
// },
295
// },
296
// });
297
298
// const q = quota_with_reasons({}, { [account_id]: {} }, site_licenses);
299
// // projects on dedicated VMs get this quota
300
// expect(q).toEqual({
301
// quota: {
302
// always_running: false,
303
// cpu_limit: 1,
304
// cpu_request: 0.02,
305
// dedicated_disks: [
306
// {
307
// name: "bar",
308
// size_gb: 128,
309
// speed: "standard",
310
// },
311
// ],
312
// dedicated_vm: false,
313
// disk_quota: 3000,
314
// idle_timeout: 1800,
315
// member_host: false,
316
// memory_limit: 1000,
317
// memory_request: 200,
318
// network: false,
319
// privileged: false,gpu:false,
320
// },
321
// reasons: {},
322
// });
323
// });
324
// });
325
326