def test_register_ip_submission(self): self._insert_data() Database.add_submission("submissionid", "inputid", "outputid", "sourceid", 42) self.register_ip(submission_id="submissionid", _ip="1.1.1.1") users = Database.get_users() self.assertEqual("1.1.1.1", users[0]["ip"][0]["ip"])
def test_submit(self, g_f_s_mock, g_i_mock): Utils.start_contest() self._insert_data() self.handler.generate_input(token='token', task='poldo', _ip='1.1.1.1') Database.c.execute( "INSERT INTO outputs (id, input, path, size, result) " "VALUES ('outputid', 'inputid', '/output', 42," ":result)", { "result": b'{\"score\":0.5,\"feedback\":{\"a\":1},' b'\"validation\":{\"b\":2}}' }) Database.c.execute("INSERT INTO sources (id, input, path, size) " "VALUES ('sourceid', 'inputid', '/source', 42)") response = self.handler.submit(output_id='outputid', source_id='sourceid', _ip='1.1.1.1') self.assertEqual("token", response["token"]) self.assertEqual("poldo", response["task"]) self.assertEqual(21, response["score"]) self.assertEqual("inputid", response["input"]["id"]) self.assertEqual("sourceid", response["source"]["id"]) self.assertEqual("outputid", response["output"]["id"]) self.assertEqual(1, response["feedback"]["a"]) self.assertEqual(2, response["output"]["validation"]["b"]) user_task = Database.get_user_task("token", "poldo") self.assertEqual(21, user_task["score"]) self.assertEqual(response["id"], Database.get_submission(response["id"])["id"])
def analyze_pack(pack, workdir, token, all, source_only, no_group_venue, outdir): packname = os.path.basename(pack)[:4] if packname[3] == "0": packname = packname[:3] with common.extract_and_connect(pack, workdir): users = Database.get_users() if token: users = list(filter(lambda u: u["token"] in token, users)) if not users: return False for user in users: token = user["token"] print("Found user %s %s" % (user["name"], user["surname"])) tasks = common.get_tasks() num_submissions = 0 for task in tasks: submissions = Database.get_submissions(token, task) num_submissions += len(submissions) if no_group_venue: taskdir = os.path.join(outdir, task, token) else: taskdir = os.path.join(outdir, packname, task, token) os.makedirs(taskdir, exist_ok=True) if not all: best = max(submissions, key=lambda x: x["score"], default=None) if best: submissions = [best] for submission in submissions: store_submission(submission, taskdir, workdir, source_only) print(" > %d submissions" % num_submissions, file=sys.stderr) return len(token) == 1 and num_submissions > 0
def test_get_meta_default(self): Database.connected = False Database.connect_to_database() meta = Database.get_meta("this_key_doesnt_exist", "default_value_is_cool") self.assertEqual("default_value_is_cool", meta)
def _ensure_contest_running(token=None): """ Makes sure that the contest is running for the user, if any. If the user has a time window it is also checked. :param token: The optional token of the user. """ extra_time = None start_delay = None if token: Validators._ensure_window_start(token) user = Database.get_user(token) if user: extra_time = user["extra_time"] start_delay = user["contest_start_delay"] if Database.get_meta("start_time") is None: BaseHandler.raise_exc(Forbidden, "FORBIDDEN", "The contest has not started yet") contest_end = BaseHandler.get_end_time(extra_time) window_end = BaseHandler.get_window_end_time(extra_time, start_delay) now = time.time() # check the contest is not finished if contest_end < now: BaseHandler.raise_exc(Forbidden, "FORBIDDEN", "The contest has ended") # if a window is present check it's not finished if window_end and window_end < now: BaseHandler.raise_exc(Forbidden, "FORBIDDEN", "Your window has ended")
def prepare_test(load_config=True, connect_database=True, connect_logger=True): config_file_name = Utils.new_tmp_file() log_file_name = Utils.new_tmp_file() db_file_name = Utils.new_tmp_file() contest_dir = Utils.new_tmp_dir("contest", create=False) with open(config_file_name, 'w') as file: file.write("logfile: %s\n" "db: %s\n" "storedir: %s\n" "contest_path: %s\n" % (log_file_name, db_file_name, Utils.new_tmp_dir(), contest_dir)) if load_config: Config.loaded = False Config.set_config_file(config_file_name) if connect_logger: Logger.connected = False Logger.connect_to_database() Logger.set_log_level("WARNING") if connect_database: Database.connected = False Database.connect_to_database()
def upload_output(self, input, file): """ POST /upload_output """ output_id = Database.gen_id() try: path = StorageManager.new_output_file(output_id, file["name"]) except ValueError: BaseHandler.raise_exc(BadRequest, "INVALID_FILENAME", "The provided file has an invalid name") StorageManager.save_file(path, file["content"]) file_size = StorageManager.get_file_size(path) try: result = ContestManager.evaluate_output(input["task"], input["path"], path) except: BaseHandler.raise_exc(InternalServerError, "INTERNAL_ERROR", "Failed to evaluate the output") Database.add_output(output_id, input["id"], path, file_size, result) Logger.info( "UPLOAD", "User %s has uploaded the output %s" % (input["token"], output_id)) return InfoHandler.patch_output(Database.get_output(output_id))
def test_set_meta(self): Database.connected = False Database.connect_to_database() Database.set_meta('random_key', 42) value = Database.get_meta('random_key', type=int) self.assertEqual(42, value)
def upload_source(self, input, file): """ POST /upload_source """ alerts = [] if get_exeflags(file["content"]): alerts.append({ "severity": "warning", "message": "You have submitted an executable! Please send the " "source code." }) Logger.info("UPLOAD", "User %s has uploaded an executable" % input["token"]) if not alerts: alerts.append({ "severity": "success", "message": "Source file uploaded correctly." }) source_id = Database.gen_id() try: path = StorageManager.new_source_file(source_id, file["name"]) except ValueError: BaseHandler.raise_exc(BadRequest, "INVALID_FILENAME", "The provided file has an invalid name") StorageManager.save_file(path, file["content"]) file_size = StorageManager.get_file_size(path) Database.add_source(source_id, input["id"], path, file_size) Logger.info("UPLOAD", "User %s has uploaded the source %s" % ( input["token"], source_id)) output = BaseHandler.format_dates(Database.get_source(source_id)) output["validation"] = {"alerts": alerts} return output
def download_results(self): """ POST /admin/download_pack """ Logger.info("ADMIN", "Creating zip file") zip_directory = os.path.join(Config.storedir, "zips", Database.gen_id()) os.makedirs(zip_directory, exist_ok=True) zipf_name = ("results-" + Database.get_meta("admin_token").split("-", 1)[0] + "-" + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + ".zip") zipf_name = os.path.join(zip_directory, zipf_name) command = ("zip -r '" + zipf_name + "' db.sqlite3* log.sqlite3* " "files/input files/output " "files/source /version* " "/proc/cpuinfo* " "/var/log/nginx") try: gevent.subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: Logger.error("ADMIN", "Zip error: %s" % e.output) raise e return { "path": os.path.relpath(zipf_name, Config.storedir) } # pragma: nocover
def test_upload_pack_already_extracted(self): Database.set_meta("admin_token", "totally the real token") with self.assertRaises(Forbidden): self.admin_handler.upload_pack(file={ "content": "foobar".encode(), "name": "pack.zip.enc" })
def test_drop_contest_not_deletable(self): Utils.setup_encrypted_file() Database.del_meta("admin_token") with open(Config.encrypted_file, "wb") as f: f.write(Utils.build_pack(ruamel.yaml.dump({"deletable": False}))) with self.assertRaises(Forbidden): self.admin_handler.drop_contest(Utils.ZIP_TOKEN)
def test_get_meta_default(self): Database.connected = False Database.connect_to_database() meta = Database.get_meta('this_key_doesnt_exist', 'default_value_is_cool') self.assertEqual('default_value_is_cool', meta)
def setUp(self): Utils.prepare_test() self.admin_handler = AdminHandler() Database.set_meta("admin_token", "ADMIN-TOKEN") self.log_backup = Logger.LOG_LEVEL Logger.LOG_LEVEL = 9001 # disable the logs
def test_start_already_started(self): Database.set_meta('start_time', 12345) with self.assertRaises(Forbidden) as ex: self.admin_handler.start(admin_token='ADMIN-TOKEN', _ip='1.2.3.4') self.assertIn("Contest has already been started", ex.exception.response.data.decode())
def test_input_invalid_params(self): Database.connected = False Database.connect_to_database() with self.assertRaises(ValueError) as ex: Database.get_input() self.assertEqual("Invalid parameters to get_input", ex.exception.args[0])
def handle(*args, **kwargs): token = Validators._guess_token(**kwargs) ip = kwargs["_ip"] if token is not None and Database.get_user(token) is not None: if Database.register_ip(token, ip): Logger.info( "LOGIN", "User %s logged in from %s for the first " "time" % (token, ip)) del kwargs["_ip"] return handler(*args, **kwargs)
def test_dictify(self): Database.connected = False Database.connect_to_database() Database.set_meta('random_key', 'random_value') Database.c.execute("SELECT * FROM metadata WHERE key = 'random_key'") dct = Database.dictify(all=False) self.assertDictEqual({'key': 'random_key', 'value': 'random_value'}, dct)
def test_get_submissions_invalid_task(self): Utils.start_contest() Database.add_user("token", "", "") with self.assertRaises(Forbidden) as ex: self.handler.get_submissions(token="token", task="invalid task", _ip="1.1.1.1") response = ex.exception.response.data.decode() self.assertIn("No such task", response)
def test_get_meta_none(self): Database.connected = False Database.connect_to_database() Database.set_meta("test", None) Database.set_meta("test2", "None") self.assertEqual(Database.get_meta("test"), None) self.assertEqual(Database.get_meta("test", type=int), None) self.assertEqual(Database.get_meta("test", None, type=int), None) self.assertEqual(Database.get_meta("test2", None), "None")
def test_upload_pack_already_uploaded(self): path = os.path.join(Utils.new_tmp_dir(), "pack.zip.enc") with open(path, "wb") as f: f.write(b"hola!") Config.encrypted_file = path Database.del_meta("admin_token") with self.assertRaises(Forbidden): self.admin_handler.upload_pack(file={ "content": "foobar".encode(), "name": "pack.zip.enc" })
def test_upload_invalid_pack(self): enc_path = os.path.join(Utils.new_tmp_dir(), "pack.zip.enc") Config.encrypted_file = enc_path Database.del_meta("admin_token") with self.assertRaises(Forbidden): self.admin_handler.upload_pack(file={ "content": b"totally not a pack", "name": "pack.zip.enc" }) self.assertFalse(os.path.exists(enc_path))
def test_contest_started(self): Database.add_task("poldo", "", "", 42, 1) Database.set_meta("start_time", 1234) res = self.handler.get_contest() self.assertTrue(res["has_started"]) self.assertEqual( datetime.datetime.fromtimestamp(1234).isoformat(), res["start_time"]) self.assertEqual(1, len(res["tasks"])) self.assertEqual("poldo", res["tasks"][0]["name"])
def test_status(self): Database.set_meta("start_time", 1234) res = self.admin_handler.status(admin_token="ADMIN-TOKEN", _ip="1.2.3.4") start_time = dateutil.parser.parse(res["start_time"]) start_time_db = datetime.fromtimestamp( Database.get_meta("start_time", type=int), timezone.utc) self.assertEqual(start_time, start_time_db) self.assertEqual(0, Database.get_meta("extra_time", default=0))
def test_status(self): Database.set_meta('start_time', 1234) res = self.admin_handler.status(admin_token='ADMIN-TOKEN', _ip='1.2.3.4') start_time = int( datetime.datetime.strptime(res["start_time"], "%Y-%m-%dT%H:%M:%S").timestamp()) self.assertEqual(start_time, Database.get_meta('start_time', type=int)) self.assertEqual(0, Database.get_meta('extra_time', default=0))
def test_dictify(self): Database.connected = False Database.connect_to_database() Database.set_meta("random_key", "random_value") Database.c.execute("SELECT * FROM metadata WHERE key = 'random_key'") dct = Database.dictify(all=False) self.assertDictEqual({ "key": "random_key", "value": "random_value" }, dct)
def test_drop_contest(self): Utils.setup_encrypted_file() Database.del_meta("admin_token") with open(Config.encrypted_file, "wb") as f: f.write(Utils.build_pack(ruamel.yaml.dump({"deletable": True}))) self.admin_handler.drop_contest(Utils.ZIP_TOKEN) self.assertFalse(os.path.exists(Config.storedir)) self.assertFalse(os.path.exists(Config.statementdir)) self.assertFalse(os.path.exists(Config.contest_path)) self.assertFalse(os.path.exists(Config.encrypted_file)) self.assertFalse(os.path.exists(Config.decrypted_file)) self.assertTrue(os.path.exists(Config.db))
def extract_contest(token): """ Decrypt and extract the contest and store the used admin token in the database """ if "-" not in token: BaseHandler.raise_exc(Forbidden, "WRONG_PASSWORD", "The provided password is malformed") try: username, password = token.split("-", 1) secret, scrambled_password = decode_data(password, SECRET_LEN) file_password = recover_file_password(username, secret, scrambled_password) except ValueError: BaseHandler.raise_exc(Forbidden, "WRONG_PASSWORD", "The provided password is malformed") try: with open(Config.encrypted_file, "rb") as encrypted_file: encrypted_data = encrypted_file.read() decrypted_data = decode(file_password, encrypted_data) with open(Config.decrypted_file, "wb") as decrypted_file: decrypted_file.write(decrypted_data) except FileNotFoundError: BaseHandler.raise_exc(NotFound, "NOT_FOUND", "The contest pack was not uploaded yet") except nacl.exceptions.CryptoError: BaseHandler.raise_exc(Forbidden, "WRONG_PASSWORD", "The provided password is wrong") except OSError as ex: BaseHandler.raise_exc(InternalServerError, "FAILED", str(ex)) zip_abs_path = os.path.realpath(Config.decrypted_file) wd = os.getcwd() try: os.makedirs(Config.contest_path, exist_ok=True) os.chdir(Config.contest_path) with zipfile.ZipFile(zip_abs_path) as f: f.extractall() real_yaml = os.path.join("__users__", username + ".yaml") if not os.path.exists(real_yaml): BaseHandler.raise_exc(Forbidden, "WRONG_PASSWORD", "Invalid username for the given pack") os.symlink(real_yaml, "contest.yaml") Logger.info("CONTEST", "Contest extracted") except zipfile.BadZipFile as ex: BaseHandler.raise_exc(Forbidden, "FAILED", str(ex)) finally: os.chdir(wd) Database.set_meta("admin_token", token)
def test_transaction_commit(self): Database.connected = False Database.connect_to_database() Database.begin() Database.set_meta('random_foobar', 123, autocommit=False) Database.commit() self.assertEqual(123, Database.get_meta('random_foobar', type=int))
def test_do_write_rollback(self): Database.connected = False Database.connect_to_database() with patch("terry.database.Database.commit", side_effect=ValueError("Ops...")): with self.assertRaises(ValueError): Database.do_write(True, """ INSERT INTO metadata (key, value) VALUES (:key, :value) """, {"key": "ciao", "value": "mondo"}) self.assertIsNone(Database.get_meta("ciao"))