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_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 test_del_meta(self): Database.connected = False Database.connect_to_database() Database.set_meta('random_key', 4242) self.assertTrue(Database.del_meta('random_key')) self.assertIsNone(Database.get_meta('random_key'))
def test_get_meta_default_not_used(self): Database.connected = False Database.connect_to_database() Database.set_meta("this_key_doesnt_exist", "cool_value") meta = Database.get_meta("this_key_doesnt_exist", "default_value_is_not_cool") self.assertEqual("cool_value", meta)
def test_set_meta_overwrite(self): Database.connected = False Database.connect_to_database() Database.set_meta("random_key", 4242) Database.set_meta("random_key", 42) value = Database.get_meta("random_key", type=int) self.assertEqual(42, value)
def test_get_meta_type_bool(self): Database.connected = False Database.connect_to_database() Database.set_meta('boooool', True) self.assertTrue(Database.get_meta('boooool', type=bool)) Database.set_meta('boooool2', False) self.assertFalse(Database.get_meta('boooool2', type=bool))
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_get_meta_default_not_used(self): Database.connected = False Database.connect_to_database() Database.set_meta('this_key_doesnt_exist', 'cool_value') meta = Database.get_meta('this_key_doesnt_exist', 'default_value_is_not_cool') self.assertEqual('cool_value', meta)
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_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_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_transaction_rollback(self): Database.connected = False Database.connect_to_database() Database.begin() Database.set_meta('random_foobar', 123, autocommit=False) Database.rollback() self.assertEqual(42, Database.get_meta('random_foobar', default=42, type=int))
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 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 set_extra_time(self, extra_time: int, user): """ POST /admin/set_extra_time """ if user is None: Database.set_meta("extra_time", extra_time) Logger.info("ADMIN", "Global extra time set to %d" % extra_time) else: Logger.info( "ADMIN", "Extra time for user %s set to %d" % (user["token"], extra_time)) Database.set_extra_time(user["token"], extra_time) return {}
def start(self): """ POST /admin/start """ if Database.get_meta("start_time", default=None, type=int) is not None: BaseHandler.raise_exc(Forbidden, "FORBIDDEN", "Contest has already been started!") start_time = int(time.time()) Database.set_meta("start_time", start_time) Logger.info("CONTEST", "Contest started") return BaseHandler.format_dates({"start_time": start_time}, fields=["start_time"])
def test_window_end_time(self): Database.set_meta("start_time", 1000) Database.set_meta("contest_duration", 150) Database.set_meta("window_duration", 100) Database.set_meta("extra_time", 20) self.assertEqual(BaseHandler.get_window_end_time(10, 20), 1130) self.assertEqual(BaseHandler.get_window_end_time(0, 0), 1100)
def test_end_time(self): Database.set_meta("start_time", 1000) Database.set_meta("contest_duration", 150) Database.set_meta("extra_time", 20) self.assertEqual(BaseHandler.get_end_time(20), 1190) self.assertEqual(BaseHandler.get_end_time(0), 1170)
def test_window_end_time_no_window(self): Database.set_meta("start_time", 1000) Database.set_meta("contest_duration", 150) # Database.set_meta("window_duration", nope) Database.set_meta("extra_time", 20) self.assertEqual(BaseHandler.get_window_end_time(20, 42), None)
def start(self, start_time: str): """ POST /admin/start """ previous_start = Database.get_meta("start_time", type=int) now = int(time.time()) if previous_start and now > previous_start: BaseHandler.raise_exc(Forbidden, "FORBIDDEN", "Contest has already been started!") actual_start = None if start_time == "reset": Database.del_meta("start_time") return {"start_time": None} elif start_time == "now": actual_start = now else: actual_start = dateutil.parser.parse(start_time).timestamp() Database.set_meta("start_time", int(actual_start)) Logger.info("CONTEST", "Contest starts at " + str(actual_start)) return BaseHandler.format_dates({"start_time": actual_start}, fields=["start_time"])
def test_get_user_windowed_partial_window(self): now = int(datetime.utcnow().timestamp()) Database.set_meta("start_time", now) Database.set_meta("contest_duration", 1000) Database.set_meta("window_duration", 100) Database.add_user("token", "", "") Database.set_start_delay("token", 990) Database.add_task("poldo", "", "", 42, 1) Database.add_user_task("token", "poldo") Database.add_input("inputid", "token", "poldo", 1, "/path", 42) Database.set_user_attempt("token", "poldo", 1) res = self.handler.get_user(token="token", _ip="1.1.1.1") end_time = datetime.fromtimestamp(now + 1000, timezone.utc).isoformat() self.assertEqual(end_time, res["end_time"])
def test_get_user_windowed_almost_finished(self): now = int(datetime.datetime.now().timestamp()) Database.set_meta("start_time", now - 90) Database.set_meta("contest_duration", 1000) Database.set_meta("window_duration", 100) Database.add_user("token", "", "") Database.set_start_delay("token", 10) Database.add_task("poldo", "", "", 42, 1) Database.add_user_task("token", "poldo") Database.add_input("inputid", "token", "poldo", 1, "/path", 42) Database.set_user_attempt("token", "poldo", 1) res = self.handler.get_user(token="token", _ip="1.1.1.1") end_time = datetime.datetime.fromtimestamp(now + 20).strftime( '%Y-%m-%dT%H:%M:%S') self.assertEqual(end_time, res["end_time"])
def test_get_user(self): now = int(datetime.utcnow().timestamp()) Database.set_meta("start_time", now) Database.set_meta("contest_duration", 1000) Database.set_meta("extra_time", 50) Database.add_user("token", "", "") Database.set_extra_time("token", 30) Database.add_task("poldo", "", "", 42, 1) Database.add_user_task("token", "poldo") Database.add_input("inputid", "token", "poldo", 1, "/path", 42) Database.set_user_attempt("token", "poldo", 1) res = self.handler.get_user(token="token", _ip="1.1.1.1") end_time = datetime.fromtimestamp(now + 1080, timezone.utc).isoformat() self.assertEqual(end_time, res["end_time"]) self.assertEqual("poldo", res["tasks"]["poldo"]["name"]) self.assertEqual("inputid", res["tasks"]["poldo"]["current_input"]["id"])
def read_from_disk(remove_enc=True): """ Load a task from the disk and load the data into the database """ try: contest = ContestManager.import_contest(Config.contest_path) except FileNotFoundError as ex: error = ( "Contest not found, you probably need to unzip it. Missing file %s" % ex.filename) Logger.warning("CONTEST", error) shutil.rmtree(Config.statementdir, ignore_errors=True) shutil.rmtree(Config.web_statementdir, ignore_errors=True) shutil.rmtree(Config.contest_path, ignore_errors=True) if remove_enc: with suppress(Exception): os.remove(Config.encrypted_file) with suppress(Exception): os.remove(Config.decrypted_file) Database.del_meta("admin_token") BaseHandler.raise_exc(UnprocessableEntity, "CONTEST", error) if not Database.get_meta("contest_imported", default=False, type=bool): Database.begin() try: Database.set_meta("contest_duration", contest["duration"], autocommit=False) Database.set_meta("contest_name", contest.get("name", "Contest"), autocommit=False) Database.set_meta( "contest_description", contest.get("description", ""), autocommit=False, ) Database.set_meta( "window_duration", # if None the contest is not USACO-style contest.get("window_duration"), autocommit=False, ) count = 0 for task in contest["tasks"]: Database.add_task( task["name"], task["description"], task["statement_path"], task["max_score"], count, autocommit=False, ) count += 1 for user in contest["users"]: Database.add_user(user["token"], user["name"], user["surname"], autocommit=False) for user in Database.get_users(): for task in Database.get_tasks(): Database.add_user_task(user["token"], task["name"], autocommit=False) Database.set_meta("contest_imported", True, autocommit=False) Database.commit() except: Database.rollback() raise else: # TODO: check that the contest is still the same pass # store the task in the ContestManager singleton ContestManager.tasks = dict( (task["name"], task) for task in contest["tasks"]) ContestManager.has_contest = True # create the queues for the task inputs for task in ContestManager.tasks: ContestManager.input_queue[task] = gevent.queue.Queue( Config.queue_size) gevent.spawn(ContestManager.worker, task)
def test_drop_contest_loaded_wrong_token(self): Utils.setup_encrypted_file() Database.set_meta("admin_token", "UHUHU-HUHU") with self.assertRaises(Forbidden): self.admin_handler.drop_contest("LALLA-BALALLA")
def start_contest(since=5, duration=100): Database.set_meta("start_time", int(datetime.datetime.now().timestamp()) - since) Database.set_meta("contest_duration", duration)