UNPKG

smc-hub

Version:

CoCalc: Backend webserver component

959 lines (945 loc) 26.2 kB
// Generated by CoffeeScript 2.5.1 (function() { //######################################################################## // This file is part of CoCalc: Copyright © 2020 Sagemath, Inc. // License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details //######################################################################## /* TESTING of syncstring related eval user query functionality COPYRIGHT : (c) 2017 SageMath, Inc. LICENSE : AGPLv3 */ var async, changefeed_series, create_accounts, create_projects, db, expect, misc, pgtest, setup, teardown; async = require('async'); expect = require('expect'); pgtest = require('./pgtest'); db = void 0; setup = function(cb) { return pgtest.setup(function(err) { db = pgtest.db; return cb(err); }); }; teardown = pgtest.teardown; ({create_accounts, create_projects, changefeed_series} = pgtest); misc = require('smc-util/misc'); describe('use of eval_inputs table --', function() { var accounts, input, path, projects, string_id, t0, t1, test_write_and_read; this.timeout(10000); before(setup); after(teardown); accounts = projects = string_id = void 0; path = 'a.txt'; it('creates 3 accounts', function(done) { return create_accounts(3, function(err, x) { accounts = x; return done(err); }); }); it('creates 2 projects', function(done) { return create_projects(2, accounts[0], function(err, x) { projects = x; return done(err); }); }); t0 = new Date(); input = { program: 'sage', input: { code: '2^a', data: { a: 3 }, preparse: true, event: 'execute_code', output_uuid: misc.uuid(), id: misc.uuid() } }; it('creates a valid syncstring', function(done) { return db.user_query({ account_id: accounts[0], query: { syncstrings: { project_id: projects[0], path: 'a.sagews', users: accounts } }, cb: done }); }); it('gets the string_id', function(done) { return db.user_query({ account_id: accounts[0], query: { syncstrings: { project_id: projects[0], path: 'a.sagews', string_id: null } }, cb: function(err, result) { string_id = result != null ? result.syncstrings.string_id : void 0; return done(err); } }); }); it('verifies anonymous set queries are not allowed', function(done) { return db.user_query({ query: { eval_inputs: { string_id: string_id, time: t0, user_id: 0, input: input } }, cb: function(err) { expect(err).toEqual("FATAL: no anonymous set queries"); return done(); } }); }); it('verifies anonymous get queries are not allowed', function(done) { return db.user_query({ query: { eval_inputs: [ { string_id: string_id, time: null, user_id: null, input: null } ] }, cb: function(err) { expect(err).toEqual("FATAL: anonymous get queries not allowed for table 'eval_inputs'"); return done(); } }); }); it('verifies set query by user not on syncstring is not allowed', function(done) { return db.user_query({ account_id: accounts[2], query: { eval_inputs: { string_id: string_id, time: t0, user_id: 0, input: input } }, cb: function(err) { expect(err).toEqual("FATAL: user must be an admin"); return done(); } }); }); it('verifies get query by user not on project not allowed', function(done) { return db.user_query({ account_id: accounts[2], query: { eval_inputs: [ { string_id: string_id, time: null, user_id: null, input: null } ] }, cb: function(err) { expect(err).toEqual("FATAL: user must be an admin"); return done(); } }); }); it('make that user an admin', function(done) { return db.make_user_admin({ account_id: accounts[2], cb: done }); }); test_write_and_read = function(account_id, project_id, cb) { db.clear_cache(); return async.series([ function(cb) { // deletes records return db._query({ query: "DELETE FROM eval_inputs", safety_check: false, cb: cb }); }, function(cb) { return db.user_query({ account_id: account_id, project_id: project_id, query: { eval_inputs: { string_id: string_id, time: t0, user_id: 0, input: input } }, cb: cb }); }, function(cb) { return db.user_query({ account_id: account_id, project_id: project_id, query: { eval_inputs: [ { string_id: string_id, time: null, user_id: null, input: null } ] }, cb: function(err, x) { expect(x).toEqual({ eval_inputs: [ { input: input, string_id: string_id, time: t0, user_id: 0 } ] }); return cb(err); } }); } ], cb); }; it('verifies set/get by admin user', function(done) { return test_write_and_read(accounts[2], void 0, done); }); it('verifies set/get FAILS by user who is listed on syncstring, but is actually not on project', function(done) { return test_write_and_read(accounts[1], void 0, function(err) { expect(err).toEqual('FATAL: user must be an admin'); return done(); }); }); it('adds other user to project', function(done) { return db.add_user_to_project({ account_id: accounts[1], project_id: projects[0], cb: done }); }); it('verifies set/get succeeds by other user who is listed on syncstring and is now on project', function(done) { return test_write_and_read(accounts[1], void 0, done); }); it('verifies set/get by other project fails', function(done) { return test_write_and_read(void 0, projects[1], function(err) { expect(err).toEqual('FATAL: project not allowed to write to syncstring in different project'); return done(); }); }); // one that succeeds should be done last, since this is used below. it('verifies set/get by user of syncstring', function(done) { return test_write_and_read(accounts[0], void 0, done); }); t1 = misc.hours_ago(5); it('writes an old eval_inputs', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_inputs: { string_id: string_id, time: t1, user_id: 0, input: input } }, cb: done }); }); it('queries for eval_inputs newer than some time', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_inputs: [ { string_id: string_id, time: { '>=': misc.hours_ago(4) }, user_id: null, input: null } ] }, cb: function(err, x) { expect(x).toEqual({ eval_inputs: [ { input: input, string_id: string_id, time: t0, user_id: 0 } ] }); return done(err); } }); }); it('queries for eval_inputs older than some time', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_inputs: [ { string_id: string_id, time: { '<=': misc.hours_ago(4) }, user_id: null, input: null } ] }, cb: function(err, x) { expect(x).toEqual({ eval_inputs: [ { input: input, string_id: string_id, time: t1, user_id: 0 } ] }); return done(err); } }); }); it('checks that string_id must be given', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_inputs: [ { string_id: null, time: null, user_id: null, input: null } ] }, cb: function(err, x) { expect(err).toEqual("FATAL: string_id (='null') must be a string of length 40"); return done(); } }); }); it('verifies that user_id must be nonnegative', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_inputs: { string_id: string_id, time: t1, user_id: -1, input: input } }, cb: function(err) { expect(err).toContain('new row for relation "eval_inputs" violates check constraint'); return done(); } }); }); it('inserts an ugly-formatted date, which works', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_inputs: { string_id: string_id, time: 'Wed Feb 01 2017 19:04:10 GMT-0600 (Central Standard Time)1', user_id: 0, input: input } }, cb: done }); }); it('inserts an horribly-formatted non-date, which does NOT work', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_inputs: { string_id: string_id, time: 'laksdjfasdf', user_id: 0, input: input } }, cb: function(err) { expect(err).toContain('invalid input syntax for type timestamp'); return done(); } }); }); return it('tests uses of eval_inputs changefeed', function(done) { var changefeed_id, t2; changefeed_id = misc.uuid(); t2 = new Date(); return db.user_query({ project_id: projects[0], query: { eval_inputs: [ { string_id: string_id, time: { '>=': misc.hours_ago(4) }, user_id: null, input: null } ] }, changes: changefeed_id, cb: changefeed_series([ function(x, cb) { expect(x.eval_inputs.length).toEqual(1); // write old input -- no update return db.user_query({ account_id: accounts[0], query: { eval_inputs: { string_id: string_id, time: misc.hours_ago(10), user_id: 0, input: input } }, cb: function(err) { if (err) { cb(err); return; } // write new input, which triggers a response return db.user_query({ account_id: accounts[0], query: { eval_inputs: { string_id: string_id, time: t2, user_id: 0, input: input } }, cb: cb }); } }); }, function(x, cb) { expect(x).toEqual({ action: 'insert', new_val: { string_id: string_id, time: t2, user_id: 0, input: input } }); // modify existing input return db.user_query({ account_id: accounts[0], query: { eval_inputs: { string_id: string_id, time: t2, user_id: 0, input: { foo: 'bar' } } }, cb: cb }); }, function(x, cb) { expect(x).toEqual({ action: 'update', new_val: { string_id: string_id, time: t2, user_id: 0, input: misc.merge({ foo: 'bar' }, input) } }); return db.user_query_cancel_changefeed({ id: changefeed_id, cb: cb }); }, function(x, cb) { expect(x).toEqual({ action: 'close' }); return cb(); } ], done) }); }); }); // NOTE: this is very similar to eval_inputs above. describe('use of eval_outputs table --', function() { var accounts, output, path, projects, string_id, t0, t1, test_write_and_read; before(setup); after(teardown); accounts = projects = string_id = void 0; path = 'a.txt'; it('creates 3 accounts', function(done) { return create_accounts(3, function(err, x) { accounts = x; return done(err); }); }); it('creates 2 projects', function(done) { return create_projects(2, accounts[0], function(err, x) { projects = x; return done(err); }); }); t0 = new Date(); output = { stdout: "hello world", done: true }; it('creates a valid syncstring', function(done) { return db.user_query({ account_id: accounts[0], query: { syncstrings: { project_id: projects[0], path: 'a.sagews', users: accounts } }, cb: done }); }); it('gets the string_id', function(done) { return db.user_query({ account_id: accounts[0], query: { syncstrings: { project_id: projects[0], path: 'a.sagews', string_id: null } }, cb: function(err, result) { string_id = result != null ? result.syncstrings.string_id : void 0; return done(err); } }); }); it('verifies anonymous set queries are not allowed', function(done) { return db.user_query({ query: { eval_outputs: { string_id: string_id, time: t0, number: 0, output: output } }, cb: function(err) { expect(err).toEqual("FATAL: no anonymous set queries"); return done(); } }); }); it('verifies anonymous get queries are not allowed', function(done) { return db.user_query({ query: { eval_outputs: [ { string_id: string_id, time: null, number: null, output: null } ] }, cb: function(err) { expect(err).toEqual("FATAL: anonymous get queries not allowed for table 'eval_outputs'"); return done(); } }); }); it('verifies set query by user not on syncstring is not allowed', function(done) { return db.user_query({ account_id: accounts[2], query: { eval_outputs: { string_id: string_id, time: t0, number: 0, output: output } }, cb: function(err) { expect(err).toEqual("FATAL: user must be an admin"); return done(); } }); }); it('verifies get query by user not on project not allowed', function(done) { return db.user_query({ account_id: accounts[2], query: { eval_outputs: [ { string_id: string_id, time: null, number: null, output: null } ] }, cb: function(err) { expect(err).toEqual("FATAL: user must be an admin"); return done(); } }); }); it('make that user an admin', function(done) { return db.make_user_admin({ account_id: accounts[2], cb: done }); }); test_write_and_read = function(account_id, project_id, cb) { db.clear_cache(); return async.series([ function(cb) { // deletes records return db._query({ query: "DELETE FROM eval_outputs", safety_check: false, cb: cb }); }, function(cb) { return db.user_query({ account_id: account_id, project_id: project_id, query: { eval_outputs: { string_id: string_id, time: t0, number: 0, output: output } }, cb: cb }); }, function(cb) { return db.user_query({ account_id: account_id, project_id: project_id, query: { eval_outputs: [ { string_id: string_id, time: null, number: null, output: null } ] }, cb: function(err, x) { expect(x).toEqual({ eval_outputs: [ { output: output, string_id: string_id, time: t0, number: 0 } ] }); return cb(err); } }); } ], cb); }; it('verifies set/get by admin user', function(done) { return test_write_and_read(accounts[2], void 0, done); }); it('verifies set/get FAILS by user who is listed on syncstring, but is actually not on project', function(done) { return test_write_and_read(accounts[1], void 0, function(err) { expect(err).toEqual('FATAL: user must be an admin'); return done(); }); }); it('adds other user to project', function(done) { return db.add_user_to_project({ account_id: accounts[1], project_id: projects[0], cb: done }); }); it('verifies set/get succeeds by other user who is listed on syncstring and is now on project', function(done) { return test_write_and_read(accounts[1], void 0, done); }); it('verifies set/get by other project fails', function(done) { return test_write_and_read(void 0, projects[1], function(err) { expect(err).toEqual('FATAL: project not allowed to write to syncstring in different project'); return done(); }); }); // one that succeeds should be done last, since this is used below. it('verifies set/get by user of syncstring', function(done) { return test_write_and_read(accounts[0], void 0, done); }); t1 = misc.hours_ago(5); it('writes an old eval_outputs', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_outputs: { string_id: string_id, time: t1, number: 0, output: output } }, cb: done }); }); it('queries for eval_outputs newer than some time', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_outputs: [ { string_id: string_id, time: { '>=': misc.hours_ago(4) }, number: null, output: null } ] }, cb: function(err, x) { expect(x).toEqual({ eval_outputs: [ { output: output, string_id: string_id, time: t0, number: 0 } ] }); return done(err); } }); }); it('queries for eval_outputs older than some time', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_outputs: [ { string_id: string_id, time: { '<=': misc.hours_ago(4) }, number: null, output: null } ] }, cb: function(err, x) { expect(x).toEqual({ eval_outputs: [ { output: output, string_id: string_id, time: t1, number: 0 } ] }); return done(err); } }); }); it('checks that string_id must be given', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_outputs: [ { string_id: null, time: null, number: null, output: null } ] }, cb: function(err, x) { expect(err).toEqual("FATAL: string_id (='null') must be a string of length 40"); return done(); } }); }); it('verifies that number must be nonnegative', function(done) { return db.user_query({ account_id: accounts[0], query: { eval_outputs: { string_id: string_id, time: t1, number: -1, output: output } }, cb: function(err) { expect(err).toContain('new row for relation "eval_outputs" violates check constraint'); return done(); } }); }); return it('tests uses of eval_outputs changefeed', function(done) { var changefeed_id, t2; changefeed_id = misc.uuid(); t2 = new Date(); return db.user_query({ account_id: accounts[0], query: { eval_outputs: [ { string_id: string_id, time: { '>=': misc.hours_ago(4) }, number: null, output: null } ] }, changes: changefeed_id, cb: changefeed_series([ function(x, cb) { expect(x.eval_outputs.length).toEqual(1); // write old output -- no update return db.user_query({ project_id: projects[0], query: { eval_outputs: { string_id: string_id, time: misc.hours_ago(10), number: 0, output: output } }, cb: function(err) { if (err) { cb(err); return; } // write new output, which triggers a response return db.user_query({ project_id: projects[0], query: { eval_outputs: { string_id: string_id, time: t2, number: 0, output: output } }, cb: cb }); } }); }, function(x, cb) { expect(x).toEqual({ action: 'insert', new_val: { string_id: string_id, time: t2, number: 0, output: output } }); // modify existing output return db.user_query({ project_id: projects[0], query: { eval_outputs: { string_id: string_id, time: t2, number: 0, output: { foo: 'bar' } } }, cb: cb }); }, function(x, cb) { expect(x).toEqual({ action: 'update', new_val: { string_id: string_id, time: t2, number: 0, output: misc.merge({ foo: 'bar' }, output) } }); return db.user_query_cancel_changefeed({ id: changefeed_id, cb: cb }); }, function(x, cb) { expect(x).toEqual({ action: 'close' }); return cb(); } ], done) }); }); }); }).call(this); //# sourceMappingURL=postgres-user-queries-syncstring-eval.js.map