def test_new_input_file(self):
     input_id = 'input_id'
     task = 'simple_task'
     attempt = 42
     path = StorageManager.new_input_file(input_id, task, attempt)
     self.assertIn("input", path)
     self.assertTrue(path.find(input_id) >= 0)
     self.assertTrue(path.find(task) >= 0)
     self.assertTrue(path.find(str(attempt)) >= 0)
    def get_input(task_name, attempt):
        """
        Fetch an input from the queue and properly rename it
        :param task_name: Name of the task
        :param attempt: Number of the attempt for the user
        :return: A pair, the first element is the id of the input file,
        the second the path
        """
        if ContestManager.input_queue[task_name].empty():
            Logger.warning("TASK", "Empty queue for task %s!" % task_name)

        input = ContestManager.input_queue[task_name].get()
        path = StorageManager.new_input_file(input["id"], task_name, attempt)
        StorageManager.rename_file(input["path"], path)

        return input["id"], path
    def worker(task_name):
        """ Method that stays in the background and generates inputs """
        task = ContestManager.tasks[task_name]
        queue = ContestManager.input_queue[task_name]

        while True:
            try:
                id = Database.gen_id()
                path = StorageManager.new_input_file(id, task_name, "invalid")
                seed = int(sha256(id.encode()).hexdigest(), 16) % (2**31)

                stdout = os.open(
                    StorageManager.get_absolute_path(path),
                    os.O_WRONLY | os.O_CREAT,
                    0o644,
                )

                try:
                    start_time = time.monotonic()
                    # generate the input and store the stdout into a file
                    retcode = gevent.subprocess.call(
                        [task["generator"], str(seed), "0"], stdout=stdout)
                    if time.monotonic() > start_time + 1:
                        Logger.warning(
                            "TASK",
                            "Generation of input %s for task %s took %f seconds"
                            % (seed, task_name, time.monotonic() - start_time),
                        )
                finally:
                    os.close(stdout)

                if retcode != 0:
                    Logger.error(
                        "TASK",
                        "Error %d generating input %s (%d) for task %s" %
                        (retcode, id, seed, task_name),
                    )
                    # skip the input
                    continue

                # if there is a validator in the task use it to check if the
                # generated input is valid
                if "validator" in task:
                    stdin = os.open(StorageManager.get_absolute_path(path),
                                    os.O_RDONLY)
                    try:
                        start_time = time.monotonic()
                        # execute the validator piping the input file to stdin
                        retcode = gevent.subprocess.call(
                            [task["validator"], "0"], stdin=stdin)
                        if time.monotonic() > start_time + 1:
                            Logger.warning(
                                "TASK",
                                "Validation of input %s for task %s took %f "
                                "seconds" % (seed, task_name,
                                             time.monotonic() - start_time),
                            )
                    finally:
                        os.close(stdin)

                    if retcode != 0:
                        Logger.error(
                            "TASK",
                            "Error %d validating input %s (%d) for task %s" %
                            (retcode, id, seed, task_name),
                        )
                        # skip the input
                        continue

                Logger.debug(
                    "TASK",
                    "Generated input %s (%d) for task %s" %
                    (id, seed, task_name),
                )
                # this method is blocking if the queue is full
                queue.put({"id": id, "path": path})
            except:
                Logger.error(
                    "TASK",
                    "Exception while creating an input file: " +
                    traceback.format_exc(),
                )