Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Avatar for KuCalc : devops.
Download
50664 views
1
###
2
TESTING of patches table
3
4
COPYRIGHT : (c) 2017 SageMath, Inc.
5
LICENSE : AGPLv3
6
###
7
8
async = require('async')
9
expect = require('expect')
10
11
pgtest = require('./pgtest')
12
db = undefined
13
setup = (cb) -> (pgtest.setup (err) -> db=pgtest.db; cb(err))
14
teardown = pgtest.teardown
15
16
{create_accounts, create_projects, changefeed_series} = pgtest
17
misc = require('smc-util/misc')
18
19
describe 'basic use of patches table from user -- ', ->
20
before(setup)
21
after(teardown)
22
23
accounts = projects = string_id = undefined
24
path = 'a.txt'
25
it 'creates 2 accounts', (done) ->
26
create_accounts 2, (err, x) -> accounts=x; done(err)
27
it 'creates 2 projects', (done) ->
28
create_projects 2, accounts[0], (err, x) -> projects=x; done(err)
29
30
it 'creates a syncstring', (done) ->
31
string_id = db.sha1(projects[0], path)
32
db.user_query
33
account_id : accounts[0]
34
query : {syncstrings:{project_id:projects[0], path:path, users:accounts}}
35
cb : done
36
37
t0 = misc.minutes_ago(10)
38
patch0 = misc.to_json({a:'patch'})
39
it 'user creates a patch', (done) ->
40
db.user_query
41
account_id : accounts[0]
42
query : {patches:{string_id:string_id, time:t0, user_id:0, patch:patch0}}
43
cb : done
44
45
it 'reads the patch back', (done) ->
46
db.user_query
47
account_id : accounts[0]
48
query : {patches:{string_id:string_id, time:t0, user_id:null, patch:null}}
49
cb : (err, x) ->
50
expect(x).toEqual(patches:{string_id:string_id, time:t0, user_id:0, patch:patch0})
51
done(err)
52
53
t1 = misc.minutes_ago(11)
54
t2 = misc.minutes_ago(12)
55
t3 = misc.minutes_ago(20)
56
it 'user creates a patch with all fields', (done) ->
57
db.user_query
58
account_id : accounts[0]
59
query : {patches:{string_id:string_id, time:t3, user_id:1, patch:patch0, snapshot:'foo', prev:t1, sent:t2}}
60
cb : done
61
62
it 'reads the patch with all fields back', (done) ->
63
db.user_query
64
account_id : accounts[0]
65
query : {patches:{string_id:string_id, time:t3, user_id:1, patch:null, snapshot:null, prev:null, sent:null}}
66
cb : (err, x) ->
67
expect(x).toEqual(patches:{string_id:string_id, time:t3, user_id:1, patch:patch0, snapshot:'foo', prev:t1, sent:t2})
68
done(err)
69
70
it 'reads all patches so far', (done) ->
71
db.user_query
72
account_id : accounts[0]
73
query : {patches:[{string_id:string_id, time:null, user_id:null, patch:null}]}
74
cb : (err, x) ->
75
expect(x.patches.length).toEqual(2)
76
done(err)
77
78
it 'reads only the more recent patch', (done) ->
79
db.user_query
80
account_id : accounts[0]
81
query : {patches:[{string_id:string_id, time:{'>=':t0}, user_id:null, patch:null}]}
82
cb : (err, x) ->
83
expect(x.patches.length).toEqual(1)
84
expect(x.patches[0].time).toEqual(t0)
85
done(err)
86
87
it 'reads only the older patch', (done) ->
88
db.user_query
89
account_id : accounts[0]
90
query : {patches:[{string_id:string_id, time:{'<':t0}, user_id:null, patch:null}]}
91
cb : (err, x) ->
92
expect(x.patches.length).toEqual(1)
93
expect(x.patches[0].time).toEqual(t3)
94
done(err)
95
96
describe 'access control tests on patches table -- ', ->
97
before(setup)
98
after(teardown)
99
100
# SETUP
101
accounts = projects = string_id = undefined
102
path = 'a.txt'
103
it 'creates 3 accounts', (done) ->
104
create_accounts 3, (err, x) -> accounts=x; done(err)
105
it 'creates 2 projects', (done) ->
106
create_projects 2, accounts[0], (err, x) -> projects=x; done(err)
107
it 'creates a syncstring', (done) ->
108
string_id = db.sha1(projects[0], path)
109
db.user_query
110
account_id : accounts[0]
111
query : {syncstrings:{project_id:projects[0], path:path, users:accounts}}
112
cb : done
113
t0 = misc.minutes_ago(10)
114
patch0 = misc.to_json({a:'patch'})
115
it 'creates a patch', (done) ->
116
db.user_query
117
account_id : accounts[0]
118
query : {patches:{string_id:string_id, time:t0, user_id:0, patch:patch0}}
119
cb : done
120
121
it 'tries to read as anon to patches table and fails', (done) ->
122
db.user_query
123
query : {patches:{string_id:null, time:null, user_id:null, patch:null}}
124
cb : (err) ->
125
expect(err).toEqual("anonymous get queries not allowed for table 'patches'")
126
done()
127
128
it 'tries to write as anon to patches table and fails', (done) ->
129
db.user_query
130
query : {patches:{string_id:string_id, time:new Date(), user_id:0, patch:patch0}}
131
cb : (err) ->
132
expect(err).toEqual("no anonymous set queries")
133
done()
134
135
it 'tries to write as user not on the project and fails', (done) ->
136
db.user_query
137
account_id : accounts[1]
138
query : {patches:{string_id:string_id, time:new Date(), user_id:0, patch:patch0}}
139
cb : (err) ->
140
expect(err).toEqual("user must be an admin")
141
done()
142
143
it 'tries to write as different project and fails', (done) ->
144
db.user_query
145
project_id : projects[1]
146
query : {patches:{string_id:string_id, time:new Date(), user_id:0, patch:patch0}}
147
cb : (err) ->
148
expect(err).toEqual("project not allowed to write to syncstring in different project")
149
done()
150
151
it 'makes account1 an admin', (done) ->
152
db.make_user_admin(account_id:accounts[1], cb:done)
153
154
it 'tries to write as admin and succeeds', (done) ->
155
db.user_query
156
account_id : accounts[1]
157
query : {patches:{string_id:string_id, time:misc.minutes_ago(2), user_id:0, patch:patch0}}
158
cb : done
159
160
it 'makes account2 a collab', (done) ->
161
db.add_user_to_project(project_id:projects[0], account_id:accounts[2], cb:done)
162
163
it 'tries to write as collab and succeeds', (done) ->
164
db.user_query
165
account_id : accounts[2]
166
query : {patches:{string_id:string_id, time:misc.minutes_ago(3), user_id:0, patch:patch0}}
167
cb : done
168
169
it 'tries to write as same project and succeeds', (done) ->
170
db.user_query
171
project_id : projects[0]
172
query : {patches:{string_id:string_id, time:misc.minutes_ago(1), user_id:0, patch:patch0}}
173
cb : (err) ->
174
done(err)
175
176
###
177
# NOTE: I removed this constraint, since code handles the undefined case fine,
178
# and it was causing problems. We should revisit this later.
179
it 'tries to write negative user number and fails', (done) ->
180
db.user_query
181
project_id : projects[0]
182
query : {patches:{string_id:string_id, time:misc.minutes_ago(4), user_id:-1, patch:patch0}}
183
cb : (err) ->
184
expect(err).toContain('new row for relation "patches" violates check constraint')
185
done()
186
187
it 'tries to write without including user field at all (and fails)', (done) ->
188
db.user_query
189
account_id : accounts[1]
190
query : {patches:{string_id:string_id, time:t0, patch:patch0}}
191
cb : (err) ->
192
expect(err).toContain('null value in column "user_id" violates not-null constraint')
193
done()
194
195
###
196
197
it 'tries to write invalid string_id and fails', (done) ->
198
db.user_query
199
project_id : projects[0]
200
query : {patches:{string_id:'sage', time:misc.minutes_ago(4), user_id:0, patch:patch0}}
201
cb : (err) ->
202
expect(err).toEqual("string_id (='sage') must be a string of length 40")
203
done()
204
205
it 'tries to write invalid time and fails', (done) ->
206
db.user_query
207
project_id : projects[0]
208
query : {patches:{string_id:string_id, time:'sage', user_id:0, patch:patch0}}
209
cb : (err) ->
210
expect(err).toContain('invalid input syntax for type timestamp')
211
done()
212
213
it 'tries to write invalid sent type and fails', (done) ->
214
db.user_query
215
project_id : projects[0]
216
query : {patches:{string_id:string_id, time:misc.minutes_ago(4), user_id:0, sent:'sage', patch:patch0}}
217
cb : (err) ->
218
expect(err).toContain('invalid input syntax for type timestamp')
219
done()
220
221
it 'tries to write invalid prev type and fails', (done) ->
222
db.user_query
223
project_id : projects[0]
224
query : {patches:{string_id:string_id, time:misc.minutes_ago(4), user_id:0, prev:'sage', patch:patch0}}
225
cb : (err) ->
226
expect(err).toContain('invalid input syntax for type timestamp')
227
done()
228
229
it 'tries to change past author and fails', (done) ->
230
db.user_query
231
account_id : accounts[1]
232
query : {patches:{string_id:string_id, time:t0, user_id:1, patch:patch0}}
233
cb : (err) ->
234
expect(err).toEqual('you may not change the author of a patch from 0 to 1')
235
done()
236
237
it 'tries to write without including time field at all (and fails)', (done) ->
238
db.user_query
239
account_id : accounts[1]
240
query : {patches:{string_id:string_id, user_id:1, patch:patch0}}
241
cb : (err) ->
242
expect("#{err}").toEqual("query must specify (primary) key 'time'")
243
done()
244
245
it 'tries to write without including string field at all (and fails)', (done) ->
246
db.user_query
247
account_id : accounts[1]
248
query : {patches:{time:t0, user_id:1, patch:patch0}}
249
cb : (err) ->
250
expect(err).toEqual("string_id (='undefined') must be a string of length 40")
251
done()
252
253
254
describe 'changefeed tests on patches table', ->
255
before(setup)
256
after(teardown)
257
258
accounts = projects = string_id = undefined
259
path = 'a.txt'
260
t = (misc.minutes_ago(10-i) for i in [0...10])
261
patch0 = misc.to_json({a:'patch'})
262
it 'creates 2 accounts', (done) ->
263
create_accounts 2, (err, x) -> accounts=x; done(err)
264
it 'creates 1 projects', (done) ->
265
create_projects 1, accounts[0], (err, x) -> projects=x; done(err)
266
it 'creates a syncstring', (done) ->
267
string_id = db.sha1(projects[0], path)
268
db.user_query
269
account_id : accounts[0]
270
query : {syncstrings:{project_id:projects[0], path:path, users:accounts}}
271
cb : done
272
273
it 'creates a changefeed as user', (done) ->
274
changefeed_id = misc.uuid()
275
db.user_query
276
account_id : accounts[0]
277
query : {patches:[{string_id:string_id, time:null, user_id:null, patch:null}]}
278
changes : changefeed_id
279
cb : changefeed_series([
280
(x, cb) ->
281
expect(x?.patches?.length).toEqual(0)
282
283
# insert a new patch
284
db.user_query
285
account_id : accounts[0]
286
query : {patches:{string_id:string_id, time:t[0], user_id:0, patch:patch0}}
287
cb : cb
288
(x, cb) ->
289
expect(x).toEqual({action:'insert', new_val:{string_id:string_id, time:t[0], user_id:0, patch:patch0}})
290
291
# modify the just-inserted patch -- should not fire anything off since sent isn't a field we're watching
292
db.user_query
293
account_id : accounts[0]
294
query : {patches:{string_id:string_id, time:t[0], user_id:0, patch:patch0, sent:t[1]}}
295
cb : (err) ->
296
if err
297
cb(err)
298
else
299
# insert new patch
300
db.user_query
301
account_id : accounts[0]
302
query : {patches:{string_id:string_id, time:t[2], user_id:0, patch:'foo'}}
303
cb : cb
304
(x, cb) ->
305
expect(x).toEqual({action:'insert', new_val:{string_id:string_id, time:t[2], user_id:0, patch:'foo'}})
306
307
db.user_query_cancel_changefeed(id:changefeed_id, cb:cb)
308
(x, cb) ->
309
expect(x).toEqual({action:'close'})
310
cb()
311
], done)
312
313
it 'creates a changefeed as project', (done) ->
314
changefeed_id = misc.uuid()
315
db.user_query
316
project_id : projects[0]
317
query : {patches:[{string_id:string_id, time:{'>=':t[2]}, user_id:null, patch:null, sent:null}]}
318
changes : changefeed_id
319
cb : changefeed_series([
320
(x, cb) ->
321
expect(x?.patches?.length).toEqual(1)
322
323
# insert a new enough patch to notice
324
db.user_query
325
account_id : accounts[0]
326
query : {patches:{string_id:string_id, time:t[3], user_id:1, patch:patch0}}
327
cb : cb
328
(x, cb) ->
329
expect(x).toEqual({action:'insert', new_val:{string_id:string_id, time:t[3], user_id:1, patch:patch0}})
330
331
# modify the just-inserted patch -- should fire since we *are* watching sent column
332
db.user_query
333
account_id : accounts[0]
334
query : {patches:{string_id:string_id, time:t[3], user_id:1, sent:t[1]}}
335
cb : cb
336
(x, cb) ->
337
expect(x).toEqual({action:'update', new_val:{string_id:string_id, time:t[3], user_id:1, patch:patch0, sent:t[1]}})
338
339
# deletes an older patch -- shouldn't fire changefeed
340
db._query
341
query : "DELETE FROM patches"
342
where : {string_id:string_id, time:t[0]}
343
cb : (err) ->
344
if err
345
cb(err)
346
else
347
# delete newer patch -- should fire changefeed
348
db._query
349
query : "DELETE FROM patches"
350
where : {string_id:string_id, time:t[3]}
351
cb : cb
352
(x, cb) ->
353
expect(x).toEqual({action:'delete', old_val:{string_id:string_id, time:t[3]}})
354
355
db.user_query_cancel_changefeed(id:changefeed_id, cb:cb)
356
(x, cb) ->
357
expect(x).toEqual({action:'close'})
358
cb()
359
], done)
360
361
362
363
364