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))
Exemple #2
0
    def test_patch_submission(self, mock):
        Utils.start_contest()
        submission = {
            "id": "subid",
            "nested_item": 42,
            "output_result": b'{"feedback":123}'
        }

        res = InfoHandler.patch_submission(submission)
        self.assertEqual("subid", res["id"])
        self.assertEqual(42, res["nested"]["item"])
        self.assertEqual(123, res["feedback"])
        self.assertEqual("outputid", res["output"]["id"])
Exemple #3
0
    def submit(self, output, source):
        """
        POST /submit
        """
        input = Database.get_input(output["input"])
        if input is None:
            Logger.warning("DB_CONSISTENCY_ERROR",
                           "Input %s not found in the db" % output["input"])
            self.raise_exc(BadRequest, "WRONG_INPUT",
                           "The provided input in invalid")
        if output["input"] != source["input"]:
            Logger.warning("POSSIBLE_CHEAT",
                           "Trying to submit wrong pair source-output")
            self.raise_exc(Forbidden, "WRONG_OUTPUT_SOURCE",
                           "The provided pair of source-output is invalid")

        score = ContestHandler.compute_score(input["task"], output["result"])
        Database.begin()
        try:
            submission_id = Database.gen_id()
            if not Database.add_submission(submission_id,
                                           input["id"],
                                           output["id"],
                                           source["id"],
                                           score,
                                           autocommit=False):
                self.raise_exc(BadRequest, "INTERNAL_ERROR",
                               "Error inserting the submission")
            ContestHandler.update_user_score(input["token"], input["task"],
                                             score)
            Database.set_user_attempt(input["token"],
                                      input["task"],
                                      None,
                                      autocommit=False)
            Database.commit()
        except sqlite3.IntegrityError as ex:
            Database.rollback()
            # provide a better error message if the input has already been
            # submitted
            if "UNIQUE constraint failed: submissions.input" in str(ex):
                self.raise_exc(Forbidden, "ALREADY_SUBMITTED",
                               "This input has already been submitted")
            raise
        except:
            Database.rollback()
            raise
        Logger.info(
            "CONTEST", "User %s has submitted %s on %s" %
            (input["token"], submission_id, input["task"]))
        return InfoHandler.patch_submission(
            Database.get_submission(submission_id))
Exemple #4
0
    def test_patch_output(self):
        Utils.start_contest()
        output = {
            "id": "outputid",
            "date": 1234,
            "path": "/path",
            "size": 42,
            "result": b'{"validation":42}'
        }

        res = InfoHandler.patch_output(output)
        self.assertEqual("outputid", res["id"]),
        self.assertEqual(
            datetime.datetime.fromtimestamp(1234).isoformat(), res["date"])
        self.assertEqual("/path", res["path"])
        self.assertEqual(42, res["validation"])
        self.assertEqual(42, res["size"])
Exemple #5
0
    def __init__(self):
        self.handlers = {
            "contest": ContestHandler(),
            "info": InfoHandler(),
            "upload": UploadHandler(),
            "admin": AdminHandler(),
        }

        # The router tries to match the rules, the endpoint MUST be a string
        # with this format
        #     CONTROLLER#ACTION
        # Where CONTROLLER is an handler registered in self.handlers and
        # ACTION is a valid
        # method of that handler
        self.router = Map([
            Rule("/contest", methods=["GET"], endpoint="info#get_contest"),
            Rule("/input/<input_id>",
                 methods=["GET"],
                 endpoint="info#get_input"),
            Rule("/output/<output_id>",
                 methods=["GET"],
                 endpoint="info#get_output"),
            Rule("/source/<source_id>",
                 methods=["GET"],
                 endpoint="info#get_source"),
            Rule(
                "/submission/<submission_id>",
                methods=["GET"],
                endpoint="info#get_submission",
            ),
            Rule("/user/<token>", methods=["GET"], endpoint="info#get_user"),
            Rule(
                "/user/<token>/submissions/<task>",
                methods=["GET"],
                endpoint="info#get_submissions",
            ),
            Rule(
                "/generate_input",
                methods=["POST"],
                endpoint="contest#generate_input",
            ),
            Rule("/submit", methods=["POST"], endpoint="contest#submit"),
            Rule(
                "/internet_detected",
                methods=["POST"],
                endpoint="contest#internet_detected",
            ),
            Rule("/upload_source",
                 methods=["POST"],
                 endpoint="upload#upload_source"),
            Rule("/upload_output",
                 methods=["POST"],
                 endpoint="upload#upload_output"),
            Rule("/admin/upload_pack",
                 methods=["POST"],
                 endpoint="admin#upload_pack"),
            Rule(
                "/admin/download_results",
                methods=["POST"],
                endpoint="admin#download_results",
            ),
            Rule("/admin/login", methods=["POST"], endpoint="admin#login"),
            Rule("/admin/log", methods=["POST"], endpoint="admin#log"),
            Rule("/admin/append_log",
                 methods=["POST"],
                 endpoint="admin#append_log"),
            Rule("/admin/start", methods=["POST"], endpoint="admin#start"),
            Rule(
                "/admin/set_extra_time",
                methods=["POST"],
                endpoint="admin#set_extra_time",
            ),
            Rule("/admin/status", methods=["POST"], endpoint="admin#status"),
            Rule("/admin/pack_status",
                 methods=["GET"],
                 endpoint="admin#pack_status"),
            Rule("/admin/user_list",
                 methods=["POST"],
                 endpoint="admin#user_list"),
            Rule(
                "/admin/drop_contest",
                methods=["POST"],
                endpoint="admin#drop_contest",
            ),
        ])
Exemple #6
0
    def setUp(self):
        Utils.prepare_test()
        self.handler = InfoHandler()

        self.log_backup = Logger.LOG_LEVEL
        Logger.LOG_LEVEL = 9001  # disable the logs
Exemple #7
0
class TestInfoHandler(unittest.TestCase):
    def setUp(self):
        Utils.prepare_test()
        self.handler = InfoHandler()

        self.log_backup = Logger.LOG_LEVEL
        Logger.LOG_LEVEL = 9001  # disable the logs

    def tearDown(self):
        Logger.LOG_LEVEL = self.log_backup

    def test_get_contest_not_started(self):
        res = self.handler.get_contest()

        self.assertFalse(res["has_started"])

    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_get_input(self):
        Database.add_user("token", "", "")
        Database.add_task("poldo", "", "", 42, 1)
        Database.add_input("inputid", "token", "poldo", 1, "/path", 42)
        Utils.start_contest()

        res = self.handler.get_input(input_id="inputid", _ip="1.1.1.1")
        self.assertEqual("inputid", res["id"])
        self.assertEqual("token", res["token"])
        self.assertEqual("poldo", res["task"])

    def test_get_input_invalid_id(self):
        Utils.start_contest()
        with self.assertRaises(Forbidden) as ex:
            self.handler.get_input(input_id="invalid input", _ip="1.1.1.1")

        response = ex.exception.response.data.decode()
        self.assertIn("No such input", response)

    def test_get_output(self):
        Database.add_user("token", "", "")
        Database.add_task("poldo", "", "", 42, 1)
        Database.add_input("inputid", "token", "poldo", 1, "/path", 42)
        Database.add_output("outputid", "inputid", "/path", 42,
                            b'{"validation":42}')
        Utils.start_contest()

        res = self.handler.get_output(output_id="outputid", _ip="1.1.1.1")
        self.assertEqual("outputid", res["id"])
        self.assertEqual(42, res["validation"])

    def test_get_output_invalid_id(self):
        Utils.start_contest()
        with self.assertRaises(Forbidden) as ex:
            self.handler.get_output(output_id="invalid output", _ip="1.1.1.1")

        response = ex.exception.response.data.decode()
        self.assertIn("No such output", response)

    def test_get_source(self):
        Utils.start_contest()
        Database.add_user("token", "", "")
        Database.add_task("poldo", "", "", 42, 1)
        Database.add_input("inputid", "token", "poldo", 1, "/path", 42)
        Database.add_source("sourceid", "inputid", "/path", 42)

        res = self.handler.get_source(source_id="sourceid", _ip="1.1.1.1")
        self.assertEqual("sourceid", res["id"])

    def test_get_source_invalid_id(self):
        Utils.start_contest()
        with self.assertRaises(Forbidden) as ex:
            self.handler.get_source(source_id="invalid source", _ip="1.1.1.1")

        response = ex.exception.response.data.decode()
        self.assertIn("No such source", response)

    def test_get_submission(self):
        Utils.start_contest()
        Database.add_user("token", "", "")
        Database.add_task("poldo", "", "", 42, 1)
        Database.add_input("inputid", "token", "poldo", 1, "/path", 42)
        Database.add_output("outputid", "inputid", "/path", 42,
                            b'{"validation":42,"feedback":42}')
        Database.add_source("sourceid", "inputid", "/path", 42)
        Database.add_submission("subid", "inputid", "outputid", "sourceid", 42)

        res = self.handler.get_submission(submission_id="subid", _ip="1.1.1.1")
        self.assertEqual("subid", res["id"])
        self.assertEqual("inputid", res["input"]["id"])
        self.assertEqual("outputid", res["output"]["id"])
        self.assertEqual("sourceid", res["source"]["id"])
        self.assertEqual(42, res["feedback"])

    def test_get_submission_invalid_id(self):
        Utils.start_contest()
        with self.assertRaises(Forbidden) as ex:
            self.handler.get_submission(submission_id="invalid submission",
                                        _ip="1.1.1.1")

        response = ex.exception.response.data.decode()
        self.assertIn("No such submission", response)

    def test_get_user_invalid_token(self):
        Utils.start_contest()
        with self.assertRaises(Forbidden) as ex:
            self.handler.get_user(token="invalid token", _ip="1.1.1.1")

        response = ex.exception.response.data.decode()
        self.assertIn("No such user", response)

    def test_get_user(self):
        now = int(datetime.datetime.now().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.datetime.fromtimestamp(now + 1080).strftime(
            '%Y-%m-%dT%H:%M:%S')
        self.assertEqual(end_time, res["end_time"])
        self.assertEqual("poldo", res["tasks"]["poldo"]["name"])
        self.assertEqual("inputid",
                         res["tasks"]["poldo"]["current_input"]["id"])

    def test_get_user_windowed(self):
        now = int(datetime.datetime.now().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", 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 + 110).strftime(
            '%Y-%m-%dT%H:%M:%S')
        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_windowed_partial_window(self):
        now = int(datetime.datetime.now().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.datetime.fromtimestamp(now + 1000).strftime(
            '%Y-%m-%dT%H:%M:%S')
        self.assertEqual(end_time, res["end_time"])

    def test_get_user_no_current_attempt(self):
        Utils.start_contest(since=100, duration=200)
        Database.add_user("token", "", "")
        Database.add_task("poldo", "", "", 42, 1)
        Database.add_user_task("token", "poldo")

        res = self.handler.get_user(token="token", _ip="1.1.1.1")
        self.assertEqual(None, res["tasks"]["poldo"]["current_input"])

    def test_get_submissions(self):
        Utils.start_contest()
        Database.add_user("token", "", "")
        Database.add_task("poldo", "", "", 42, 1)
        Database.add_input("inputid", "token", "poldo", 1, "/path", 42)
        Database.add_output("outputid", "inputid", "/path", 42,
                            b'{"validation":42,"feedback":42}')
        Database.add_source("sourceid", "inputid", "/path", 42)
        Database.add_submission("subid", "inputid", "outputid", "sourceid", 42)

        res = self.handler.get_submissions(token="token",
                                           task="poldo",
                                           _ip="1.1.1.1")
        self.assertEqual(1, len(res["items"]))
        self.assertEqual("subid", res["items"][0]["id"])

    def test_get_submissions_invalid_token(self):
        Utils.start_contest()
        with self.assertRaises(Forbidden) as ex:
            self.handler.get_submissions(token="invalid token",
                                         task="poldo",
                                         _ip="1.1.1.1")

        response = ex.exception.response.data.decode()
        self.assertIn("No such user", response)

    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)

    @patch("terry.handlers.info_handler.InfoHandler.patch_output",
           return_value={"id": "outputid"})
    def test_patch_submission(self, mock):
        Utils.start_contest()
        submission = {
            "id": "subid",
            "nested_item": 42,
            "output_result": b'{"feedback":123}'
        }

        res = InfoHandler.patch_submission(submission)
        self.assertEqual("subid", res["id"])
        self.assertEqual(42, res["nested"]["item"])
        self.assertEqual(123, res["feedback"])
        self.assertEqual("outputid", res["output"]["id"])

    def test_patch_output(self):
        Utils.start_contest()
        output = {
            "id": "outputid",
            "date": 1234,
            "path": "/path",
            "size": 42,
            "result": b'{"validation":42}'
        }

        res = InfoHandler.patch_output(output)
        self.assertEqual("outputid", res["id"]),
        self.assertEqual(
            datetime.datetime.fromtimestamp(1234).isoformat(), res["date"])
        self.assertEqual("/path", res["path"])
        self.assertEqual(42, res["validation"])
        self.assertEqual(42, res["size"])