smc-hub
Version:
CoCalc: Backend webserver component
959 lines (945 loc) • 26.2 kB
JavaScript
// 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