2020-07-27 18:57:36 +00:00
|
|
|
"""
|
|
|
|
This module defines what sandbox functions are made available to the Node controller,
|
|
|
|
and starts the grist sandbox. See engine.py for the API documentation.
|
|
|
|
"""
|
(core) get all tests working under python3/gvisor
Summary:
This verifies that all existing tests are capable of running under python3/gvisor, and fixes the small issues that came up. It does not yet activate python3 tests on all diffs, only diffs that specifically request them.
* Adds a suffix in test names and output directories for tests run with PYTHON_VERSION=3, so that results of the same test run with and without the flag can be aggregated cleanly.
* Adds support for checkpointing to the gvisor sandbox adapter.
* Prepares a checkpoint made after grist python code has loaded in the gvisor sandbox.
* Changes how `DOC_URL` is passed to the sandbox, since it can no longer be passed in as an environment variable when using checkpoints.
* Uses the checkpoint to speed up tests using the gvisor sandbox, otherwise a lot of tests need more time (especially on mac under docker).
* Directs jenkins to run all tests with python2 and python3 when a new file `buildtools/changelogs/python.txt` is touched (this diff counts as touching that file).
* Tweaks miscellaneous tests
- some needed fixes exposed by slightly different timing
- a small number actually give different results in py3 (removal of `u` prefixes).
- some needed a little more time
The DOC_URL change is not the ultimate solution we want for DOC_URL. Eventually it should be a variable that gets updated, like the date perhaps. This is just a small pragmatic change to preserve existing behavior.
Tests are run mindlessly as py3, and for some tests it won't change anything (e.g. if they do not use NSandbox). Tests are not run in parallel, doubling overall test time.
Checkpoints could be useful in deployment, though this diff doesn't use them there.
The application of checkpoints doesn't check for other configuration like 3-versus-5-pipe that we don't actually use.
Python2 tests run using pynbox as always for now.
The diff got sufficiently bulky that I didn't tackle running py3 on "regular" diffs in it. My preference, given that most tests don't appear to stress the python side of things, would be to make a selection of the tests that do and a few wild cards, and run those tests on both pythons rather then all of them. For diffs making a significant python change, I'd propose touching buildtools/changelogs/python.txt for full tests. But this is a conversation in progress.
A total of 6886 tests ran on this diff.
Test Plan: this is a step in preparing tests for py3 transition
Reviewers: dsagal
Reviewed By: dsagal
Subscribers: dsagal
Differential Revision: https://phab.getgrist.com/D3066
2021-10-18 17:37:51 +00:00
|
|
|
import os
|
2020-07-27 18:57:36 +00:00
|
|
|
import sys
|
|
|
|
sys.path.append('thirdparty')
|
|
|
|
# pylint: disable=wrong-import-position
|
|
|
|
|
2022-04-26 05:50:57 +00:00
|
|
|
import logging
|
2020-07-27 18:57:36 +00:00
|
|
|
import marshal
|
|
|
|
import functools
|
|
|
|
|
2021-06-22 15:12:25 +00:00
|
|
|
import six
|
|
|
|
|
2020-07-27 18:57:36 +00:00
|
|
|
import actions
|
|
|
|
import engine
|
|
|
|
import migrations
|
|
|
|
import schema
|
|
|
|
import useractions
|
|
|
|
import objtypes
|
2021-08-09 14:51:43 +00:00
|
|
|
from acl_formula import parse_acl_formula
|
|
|
|
from sandbox import get_default_sandbox
|
|
|
|
from imports.register import register_import_parsers
|
2020-07-27 18:57:36 +00:00
|
|
|
|
|
|
|
import logger
|
|
|
|
log = logger.Logger(__name__, logger.INFO)
|
|
|
|
|
2022-04-26 05:50:57 +00:00
|
|
|
# Configure logging module to behave similarly to logger. (It may be OK to get rid of logger.)
|
|
|
|
logging.basicConfig(format="[%(levelname)s] [%(name)s] %(message)s")
|
|
|
|
|
2020-07-27 18:57:36 +00:00
|
|
|
def table_data_from_db(table_name, table_data_repr):
|
|
|
|
if table_data_repr is None:
|
|
|
|
return actions.TableData(table_name, [], {})
|
|
|
|
table_data_parsed = marshal.loads(table_data_repr)
|
2021-06-24 12:23:33 +00:00
|
|
|
table_data_parsed = {key.decode("utf8"): value for key, value in table_data_parsed.items()}
|
2020-07-27 18:57:36 +00:00
|
|
|
id_col = table_data_parsed.pop("id")
|
|
|
|
return actions.TableData(table_name, id_col,
|
|
|
|
actions.decode_bulk_values(table_data_parsed, _decode_db_value))
|
|
|
|
|
|
|
|
def _decode_db_value(value):
|
|
|
|
# Decode database values received from SQLite's allMarshal() call. These are encoded by
|
|
|
|
# marshalling certain types and storing as BLOBs (received in Python as binary strings, as
|
|
|
|
# opposed to text which is received as unicode). See also encodeValue() in DocStorage.js
|
|
|
|
t = type(value)
|
2021-06-24 12:23:33 +00:00
|
|
|
if t == six.binary_type:
|
2020-07-27 18:57:36 +00:00
|
|
|
return objtypes.decode_object(marshal.loads(value))
|
|
|
|
else:
|
|
|
|
return value
|
|
|
|
|
2021-06-30 13:35:05 +00:00
|
|
|
def run(sandbox):
|
2020-07-27 18:57:36 +00:00
|
|
|
eng = engine.Engine()
|
|
|
|
|
2021-06-30 13:35:05 +00:00
|
|
|
def export(method):
|
|
|
|
# Wrap each method so that it logs a message that it's being called.
|
|
|
|
@functools.wraps(method)
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
log.debug("calling %s" % method.__name__)
|
|
|
|
return method(*args, **kwargs)
|
|
|
|
|
|
|
|
sandbox.register(method.__name__, wrapper)
|
|
|
|
|
(core) Log statistics about table sizes
Summary:
Record numbers of rows, columns, cells, and bytes of marshalled data for most calls to table_data_from_db
Export new function get_table_stats in the sandbox, which gives the raw numbers and totals.
Get and log these stats in ActiveDoc right after loading tables, before Calculate, so they are logged even in case of errors.
Tweak logging about number of tables, especially number of on-demand tables, to not only show in debug logging.
Test Plan: Updated doc regression tests, that shows what the data looks like nicely.
Reviewers: dsagal, paulfitz
Reviewed By: dsagal
Differential Revision: https://phab.getgrist.com/D3081
2021-10-21 13:03:37 +00:00
|
|
|
def load_and_record_table_data(table_name, table_data_repr):
|
|
|
|
result = table_data_from_db(table_name, table_data_repr)
|
|
|
|
eng.record_table_stats(result, table_data_repr)
|
|
|
|
return result
|
|
|
|
|
2020-07-27 18:57:36 +00:00
|
|
|
@export
|
2021-07-15 00:45:53 +00:00
|
|
|
def apply_user_actions(action_reprs, user=None):
|
|
|
|
action_group = eng.apply_user_actions([useractions.from_repr(u) for u in action_reprs], user)
|
2022-06-17 18:49:18 +00:00
|
|
|
result = dict(
|
2022-02-21 14:19:11 +00:00
|
|
|
rowCount=eng.count_rows(),
|
|
|
|
**eng.acl_split(action_group).to_json_obj()
|
|
|
|
)
|
2022-06-17 18:49:18 +00:00
|
|
|
if action_group.requests:
|
|
|
|
result["requests"] = action_group.requests
|
|
|
|
return result
|
2020-07-27 18:57:36 +00:00
|
|
|
|
|
|
|
@export
|
|
|
|
def fetch_table(table_id, formulas=True, query=None):
|
|
|
|
return actions.get_action_repr(eng.fetch_table(table_id, formulas=formulas, query=query))
|
|
|
|
|
|
|
|
@export
|
|
|
|
def fetch_table_schema():
|
|
|
|
return eng.fetch_table_schema()
|
|
|
|
|
|
|
|
@export
|
2021-07-15 00:45:53 +00:00
|
|
|
def autocomplete(txt, table_id, column_id, user):
|
|
|
|
return eng.autocomplete(txt, table_id, column_id, user)
|
2020-07-27 18:57:36 +00:00
|
|
|
|
|
|
|
@export
|
|
|
|
def find_col_from_values(values, n, opt_table_id):
|
|
|
|
return eng.find_col_from_values(values, n, opt_table_id)
|
|
|
|
|
|
|
|
@export
|
|
|
|
def fetch_meta_tables(formulas=True):
|
|
|
|
return {table_id: actions.get_action_repr(table_data)
|
2021-06-22 15:12:25 +00:00
|
|
|
for (table_id, table_data) in six.iteritems(eng.fetch_meta_tables(formulas))}
|
2020-07-27 18:57:36 +00:00
|
|
|
|
|
|
|
@export
|
|
|
|
def load_meta_tables(meta_tables, meta_columns):
|
(core) Log statistics about table sizes
Summary:
Record numbers of rows, columns, cells, and bytes of marshalled data for most calls to table_data_from_db
Export new function get_table_stats in the sandbox, which gives the raw numbers and totals.
Get and log these stats in ActiveDoc right after loading tables, before Calculate, so they are logged even in case of errors.
Tweak logging about number of tables, especially number of on-demand tables, to not only show in debug logging.
Test Plan: Updated doc regression tests, that shows what the data looks like nicely.
Reviewers: dsagal, paulfitz
Reviewed By: dsagal
Differential Revision: https://phab.getgrist.com/D3081
2021-10-21 13:03:37 +00:00
|
|
|
return eng.load_meta_tables(load_and_record_table_data("_grist_Tables", meta_tables),
|
|
|
|
load_and_record_table_data("_grist_Tables_column", meta_columns))
|
2020-07-27 18:57:36 +00:00
|
|
|
|
|
|
|
@export
|
|
|
|
def load_table(table_name, table_data):
|
(core) Log statistics about table sizes
Summary:
Record numbers of rows, columns, cells, and bytes of marshalled data for most calls to table_data_from_db
Export new function get_table_stats in the sandbox, which gives the raw numbers and totals.
Get and log these stats in ActiveDoc right after loading tables, before Calculate, so they are logged even in case of errors.
Tweak logging about number of tables, especially number of on-demand tables, to not only show in debug logging.
Test Plan: Updated doc regression tests, that shows what the data looks like nicely.
Reviewers: dsagal, paulfitz
Reviewed By: dsagal
Differential Revision: https://phab.getgrist.com/D3081
2021-10-21 13:03:37 +00:00
|
|
|
return eng.load_table(load_and_record_table_data(table_name, table_data))
|
|
|
|
|
|
|
|
@export
|
|
|
|
def get_table_stats():
|
|
|
|
return eng.get_table_stats()
|
2020-07-27 18:57:36 +00:00
|
|
|
|
|
|
|
@export
|
2020-11-11 21:29:11 +00:00
|
|
|
def create_migrations(all_tables, metadata_only=False):
|
2020-07-27 18:57:36 +00:00
|
|
|
doc_actions = migrations.create_migrations(
|
2021-06-22 15:12:25 +00:00
|
|
|
{t: table_data_from_db(t, data) for t, data in six.iteritems(all_tables)}, metadata_only)
|
|
|
|
return [actions.get_action_repr(action) for action in doc_actions]
|
2020-07-27 18:57:36 +00:00
|
|
|
|
|
|
|
@export
|
|
|
|
def get_version():
|
|
|
|
return schema.SCHEMA_VERSION
|
|
|
|
|
(core) get all tests working under python3/gvisor
Summary:
This verifies that all existing tests are capable of running under python3/gvisor, and fixes the small issues that came up. It does not yet activate python3 tests on all diffs, only diffs that specifically request them.
* Adds a suffix in test names and output directories for tests run with PYTHON_VERSION=3, so that results of the same test run with and without the flag can be aggregated cleanly.
* Adds support for checkpointing to the gvisor sandbox adapter.
* Prepares a checkpoint made after grist python code has loaded in the gvisor sandbox.
* Changes how `DOC_URL` is passed to the sandbox, since it can no longer be passed in as an environment variable when using checkpoints.
* Uses the checkpoint to speed up tests using the gvisor sandbox, otherwise a lot of tests need more time (especially on mac under docker).
* Directs jenkins to run all tests with python2 and python3 when a new file `buildtools/changelogs/python.txt` is touched (this diff counts as touching that file).
* Tweaks miscellaneous tests
- some needed fixes exposed by slightly different timing
- a small number actually give different results in py3 (removal of `u` prefixes).
- some needed a little more time
The DOC_URL change is not the ultimate solution we want for DOC_URL. Eventually it should be a variable that gets updated, like the date perhaps. This is just a small pragmatic change to preserve existing behavior.
Tests are run mindlessly as py3, and for some tests it won't change anything (e.g. if they do not use NSandbox). Tests are not run in parallel, doubling overall test time.
Checkpoints could be useful in deployment, though this diff doesn't use them there.
The application of checkpoints doesn't check for other configuration like 3-versus-5-pipe that we don't actually use.
Python2 tests run using pynbox as always for now.
The diff got sufficiently bulky that I didn't tackle running py3 on "regular" diffs in it. My preference, given that most tests don't appear to stress the python side of things, would be to make a selection of the tests that do and a few wild cards, and run those tests on both pythons rather then all of them. For diffs making a significant python change, I'd propose touching buildtools/changelogs/python.txt for full tests. But this is a conversation in progress.
A total of 6886 tests ran on this diff.
Test Plan: this is a step in preparing tests for py3 transition
Reviewers: dsagal
Reviewed By: dsagal
Subscribers: dsagal
Differential Revision: https://phab.getgrist.com/D3066
2021-10-18 17:37:51 +00:00
|
|
|
@export
|
|
|
|
def set_doc_url(doc_url):
|
|
|
|
os.environ['DOC_URL'] = doc_url
|
|
|
|
|
2020-07-27 18:57:36 +00:00
|
|
|
@export
|
|
|
|
def get_formula_error(table_id, col_id, row_id):
|
|
|
|
return objtypes.encode_object(eng.get_formula_error(table_id, col_id, row_id))
|
|
|
|
|
2020-12-15 04:19:38 +00:00
|
|
|
export(parse_acl_formula)
|
2020-07-27 18:57:36 +00:00
|
|
|
export(eng.load_empty)
|
|
|
|
export(eng.load_done)
|
|
|
|
|
2021-08-09 14:51:43 +00:00
|
|
|
register_import_parsers(sandbox)
|
|
|
|
|
(core) get all tests working under python3/gvisor
Summary:
This verifies that all existing tests are capable of running under python3/gvisor, and fixes the small issues that came up. It does not yet activate python3 tests on all diffs, only diffs that specifically request them.
* Adds a suffix in test names and output directories for tests run with PYTHON_VERSION=3, so that results of the same test run with and without the flag can be aggregated cleanly.
* Adds support for checkpointing to the gvisor sandbox adapter.
* Prepares a checkpoint made after grist python code has loaded in the gvisor sandbox.
* Changes how `DOC_URL` is passed to the sandbox, since it can no longer be passed in as an environment variable when using checkpoints.
* Uses the checkpoint to speed up tests using the gvisor sandbox, otherwise a lot of tests need more time (especially on mac under docker).
* Directs jenkins to run all tests with python2 and python3 when a new file `buildtools/changelogs/python.txt` is touched (this diff counts as touching that file).
* Tweaks miscellaneous tests
- some needed fixes exposed by slightly different timing
- a small number actually give different results in py3 (removal of `u` prefixes).
- some needed a little more time
The DOC_URL change is not the ultimate solution we want for DOC_URL. Eventually it should be a variable that gets updated, like the date perhaps. This is just a small pragmatic change to preserve existing behavior.
Tests are run mindlessly as py3, and for some tests it won't change anything (e.g. if they do not use NSandbox). Tests are not run in parallel, doubling overall test time.
Checkpoints could be useful in deployment, though this diff doesn't use them there.
The application of checkpoints doesn't check for other configuration like 3-versus-5-pipe that we don't actually use.
Python2 tests run using pynbox as always for now.
The diff got sufficiently bulky that I didn't tackle running py3 on "regular" diffs in it. My preference, given that most tests don't appear to stress the python side of things, would be to make a selection of the tests that do and a few wild cards, and run those tests on both pythons rather then all of them. For diffs making a significant python change, I'd propose touching buildtools/changelogs/python.txt for full tests. But this is a conversation in progress.
A total of 6886 tests ran on this diff.
Test Plan: this is a step in preparing tests for py3 transition
Reviewers: dsagal
Reviewed By: dsagal
Subscribers: dsagal
Differential Revision: https://phab.getgrist.com/D3066
2021-10-18 17:37:51 +00:00
|
|
|
log.info("Ready") # This log message is significant for checkpointing.
|
2020-07-27 18:57:36 +00:00
|
|
|
sandbox.run()
|
|
|
|
|
2021-06-30 13:35:05 +00:00
|
|
|
def main():
|
2021-07-08 21:52:00 +00:00
|
|
|
run(get_default_sandbox())
|
2021-06-30 13:35:05 +00:00
|
|
|
|
2020-07-27 18:57:36 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|