Пример #1
0
    def test_simple(self):
        run = Run(user=self.users[0],
                  problem=self.problems[0],
                  statement=self.statements[0],
                  score=123,
                  create_time=datetime.datetime(2018, 3, 24, 10, 49, 0),
                  ejudge_score=456,
                  ejudge_status=7,
                  ejudge_language_id=27,
                  ejudge_create_time=datetime.datetime(2010, 1, 1, 1, 1, 1))
        db.session.add(run)
        db.session.flush()

        assert_that(
            run.serialize(),
            equal_to({
                'id': 1,
                'create_time': '2018-03-24 10:49:00',
                'ejudge_contest_id': None,
                'ejudge_run_id': None,
                'problem_id': self.problems[0].id,
                'statement_id': self.statements[0].id,
                'score': 123,
                'status': 7,
                'language_id': 27,
                'user': {
                    'id': 1,
                    'ejudge_id': 179,
                    'firstname': 'Maxim',
                    'lastname': 'Grishkin',
                }
            }))
Пример #2
0
    def test_handles_submit_exception(self):
        # В случае, если функция submit бросила исключение
        run = Run(
            user_id=self.users[0].id,
            problem_id=self.ejudge_problems[0].id,
            statement_id=self.statements[0].id,
            create_time=datetime.datetime(2018, 3, 30, 16, 59, 0),
            ejudge_contest_id=self.ejudge_problems[0].ejudge_contest_id,
            ejudge_language_id=27,
            ejudge_status=EjudgeStatuses.COMPILING.value,
        )
        db.session.add(run)
        db.session.flush()
        db.session.refresh(run)

        file = self.file_mock

        text = file.read()
        run.update_source(text)

        submit = Submit(
            id=1,
            run_id=run.id,
            ejudge_url='ejudge_url',
        )

        ejudge_submit_mock.side_effect = lambda *args, **kwargs: 1 / 0
        assert_that(
            calling(submit.send),
            is_not(raises(anything())),
        )

        ejudge_submit_mock.side_effect = None
Пример #3
0
    def post(self, problem_id: int):
        args = parser.parse(self.post_args)

        language_id = args['lang_id']
        statement_id = args.get('statement_id')
        user_id = args.get('user_id')
        file = parser.parse_files(request, 'file', 'file')

        # Здесь НЕЛЬЗЯ использовать .get(problem_id), см EjudgeProblem.__doc__
        problem = db.session.query(EjudgeProblem) \
            .filter_by(id=problem_id) \
            .one_or_none()

        if not problem:
            raise NotFound('Problem with this id is not found')

        try:
            text = self.check_file_restriction(file)
        except ValueError as e:
            raise BadRequest(e.args[0])
        source_hash = Run.generate_source_hash(text)

        duplicate = db.session.query(Run).filter(Run.user_id == user_id) \
            .filter(Run.problem_id == problem_id) \
            .order_by(Run.id.desc()).first()
        if duplicate is not None and duplicate.source_hash == source_hash:
            raise BadRequest('Source file is duplicate of your previous submission')

        # TODO: разобраться, есть ли там constraint на statement_id
        run = Run(
            user_id=user_id,
            problem_id=problem_id,
            statement_id=statement_id,
            ejudge_contest_id=problem.ejudge_contest_id,
            ejudge_language_id=language_id,
            ejudge_status=377,  # In queue
            source_hash=source_hash,
        )

        db.session.add(run)
        db.session.flush()

        run.update_source(text)

        run_id = run.id
        ejudge_url = current_app.config['EJUDGE_NEW_CLIENT_URL']

        # Коммит должен быть до отправки в очередь иначе это гонка
        db.session.commit()

        queue_submit(run_id, ejudge_url)
        return jsonify({
            'run_id': run_id
        })
Пример #4
0
    def send(self):
        try:
            ejudge_response = submit(run_file=self.file,
                                     contest_id=self.problem.ejudge_contest_id,
                                     prob_id=self.problem.problem_id,
                                     lang_id=self.language_id,
                                     login=self.user.login,
                                     password=self.user.password,
                                     filename=self.file.filename,
                                     url=self.ejudge_url,
                                     user_id=self.user.id)
        except Exception:
            log.exception('Unknown Ejudge submit error')
            notify_user(self.user.id, SUBMIT_ERROR,
                        ejudge_error_notification())
            return

        try:
            if ejudge_response['code'] != 0:
                notify_user(self.user.id, SUBMIT_ERROR,
                            ejudge_error_notification(ejudge_response))
                return

            run_id = ejudge_response['run_id']
        except Exception:
            log.exception('ejudge_proxy.submit returned bad value')
            notify_user(self.user.id,
                        SUBMIT_ERROR,
                        message=ejudge_error_notification())
            return

        run = Run(
            user_id=self.user.id,
            problem=self.problem,
            statement_id=self.statement_id,
            create_time=self.create_time,
            ejudge_run_id=run_id,
            ejudge_contest_id=self.problem.ejudge_contest_id,
            ejudge_language_id=self.language_id,
            ejudge_status=98,  # compiling
        )
        db.session.add(run)
        db.session.commit()

        db.session.refresh(run)
        run.update_source(text=self.source)
        g.user = self.user
        notify_user(self.user.id, SUBMIT_SUCCESS, {
            'run': run.serialize(),
            'submit_id': self.id,
        })
Пример #5
0
    def test_simple(self):
        run = Run(
            user_id=self.users[0].id,
            problem_id=self.ejudge_problems[0].id,
            statement_id=self.statements[0].id,
            create_time=datetime.datetime(2018, 3, 30, 16, 59, 0),
            ejudge_contest_id=self.ejudge_problems[0].ejudge_contest_id,
            ejudge_language_id=27,
            ejudge_status=EjudgeStatuses.COMPILING.value,
        )
        db.session.add(run)
        db.session.flush()
        db.session.refresh(run)

        file = self.file_mock

        text = file.read()
        run.update_source(text)

        submit = Submit(
            id=1,
            run_id=run.id,
            ejudge_url='ejudge_url',
        )

        ejudge_submit_mock.return_value = {
            'code': 0,
            'run_id': self.run.run_id,
        }

        submit.send()

        from flask import current_app

        ejudge_submit_mock.assert_called_once_with(
            run_file=b'source',
            contest_id=1,
            prob_id=1,
            lang_id=27,
            login=current_app.config['EJUDGE_USER'],
            password=current_app.config['EJUDGE_PASSWORD'],
            filename='common_filename',
            url='ejudge_url',
        )

        run = db.session.query(Run).one()
        assert_that(run.ejudge_run_id, equal_to(self.run.run_id))
        assert_that(run.ejudge_contest_id,
                    equal_to(self.ejudge_problems[0].ejudge_contest_id))
        assert_that(run.user.id, equal_to(self.users[0].id))
        assert_that(run.problem.id, equal_to(self.ejudge_problems[0].id))
Пример #6
0
def notification_update_run():
    contest_id = int(request.args['contest_id'])
    run_id = int(request.args['run_id'])

    try:
        run = db.session.query(EjudgeRun) \
            .filter_by(contest_id=contest_id) \
            .filter_by(run_id=run_id) \
            .one()
    except Exception:
        raise RunNotFound

    run = Run.sync(
        ejudge_run_id=run_id,
        ejudge_contest_id=contest_id
    )
    db.session.commit()
    db.session.refresh(run)

    g.user = run.user
    notify_user(
        run.user_id,
        RUNS_FETCH,
        {
            'runs': [run.serialize()],
        }
    )

    return jsonify({})
Пример #7
0
    def setUp(self):
        super().setUp()

        self.create_ejudge_problems()
        self.create_problems()
        self.create_statements()
        self.create_statement_problems()
        self.create_course_module_statement()

        self.user1 = SimpleUser(firstname='user1', lastname='user1')
        self.user2 = SimpleUser(firstname='user2', lastname='user2')

        db.session.add_all([self.user1, self.user2])

        db.session.flush()

        self.run1 = Run(user_id=self.user1.id,
                        problem_id=self.problems[1].id,
                        ejudge_status=0,
                        ejudge_language_id=1)
        self.run2 = Run(user_id=self.user1.id,
                        problem_id=self.problems[2].id,
                        ejudge_status=0,
                        ejudge_language_id=1)
        self.run3 = Run(user_id=self.user2.id,
                        problem_id=self.problems[1].id,
                        ejudge_status=2,
                        ejudge_language_id=2)
        self.run4 = Run(user_id=self.user2.id,
                        problem_id=self.problems[2].id,
                        ejudge_status=2,
                        ejudge_language_id=2)

        self.run4.create_time = datetime.utcnow() - timedelta(days=1)

        db.session.add_all([self.run1, self.run2, self.run3, self.run4])

        self.group = Group()
        db.session.add(self.group)
        db.session.flush()

        user_group = UserGroup(user_id=self.user1.id, group_id=self.group.id)
        db.session.add(user_group)

        db.session.commit()
Пример #8
0
 def test_create(self):
     run = Run.sync(
         ejudge_run_id=self.ejudge_run.run_id,
         ejudge_contest_id=self.ejudge_run.contest_id,
     )
     db.session.flush()
     assert_that(run.user_id, equal_to(self.users[1].id))
     assert_that(run.problem_id, equal_to(self.problems[1].id))
     assert_that(run.score, equal_to(self.ejudge_run.score))
Пример #9
0
 def send_problem_run_updates(self, problem_id: int, run: Run):
     current_app.logger.debug(
         f'CentrifugoClient: send update for problem {problem_id}')
     channel = f'problem.{problem_id}'
     try:
         self.client.publish(channel, {'run': run.serialize()})
     except AttributeError:
         current_app.logger.exception(
             f'CentrifugoClient: client is not initialized')
     except CentException:
         current_app.logger.exception(
             f'CentrifugoClient: can\'t send message to centrifugo')
Пример #10
0
    def test_handles_submit_error(self):
        # В случае, если ejudge вернул не 0 код

        run = Run(
            user_id=self.users[0].id,
            problem_id=self.ejudge_problems[0].id,
            statement_id=self.statements[0].id,
            create_time=datetime.datetime(2018, 3, 30, 17, 10, 11),
            ejudge_contest_id=self.ejudge_problems[0].ejudge_contest_id,
            ejudge_language_id=27,
            ejudge_status=EjudgeStatuses.COMPILING.value,
        )
        db.session.add(run)
        db.session.flush()
        db.session.refresh(run)

        file = self.file_mock

        text = file.read()
        run.update_source(text)

        submit = Submit(
            id=1,
            run_id=run.id,
            ejudge_url='ejudge_url',
        )

        ejudge_submit_mock.return_value = {
            'code': 123,
            'message': 'some message',
            'other': 'secrets'
        }
        assert_that(
            calling(submit.send),
            is_not(raises(anything())),
        )

        ejudge_submit_mock.side_effect = None
Пример #11
0
    def test_simple(self):
        ejudge_run = EjudgeRun(
            run_id=2,
            user=self.users[0],
            problem=self.problems[0],
            run_uuid='some string',
            score=10,
            status=7,
            lang_id=27,
            test_num=3,
            create_time=datetime.datetime(2018, 3, 24, 9, 51, 30),
            last_change_time=datetime.datetime(2018, 3, 24, 9, 51, 31),
        )
        db.session.add(ejudge_run)
        db.session.flush()

        run = Run.from_ejudge_run(ejudge_run)
        db.session.add(run)
        db.session.flush()

        assert_that(
            attrs_to_dict(
                run,
                'user_id',
                'problem_id',
                'statement_id',
                'score',
                'ejudge_run_id',
                'ejudge_contest_id',
                'ejudge_score',
                'ejudge_status',
                'ejudge_language_id',
                'ejudge_test_num',
                'ejudge_create_time',
                'ejudge_last_change_time',
            ),
            has_entries({
                'user_id': self.users[0].id,
                'problem_id': self.problems[0].id,
                'score': ejudge_run.score,
                'ejudge_run_id': ejudge_run.run_id,
                'ejudge_contest_id': ejudge_run.contest_id,
                'ejudge_score': ejudge_run.score,
                'ejudge_status': ejudge_run.status,
                'ejudge_language_id': ejudge_run.lang_id,
                'ejudge_test_num': ejudge_run.test_num,
                'ejudge_create_time': ejudge_run.create_time,
                'ejudge_last_change_time': ejudge_run.last_change_time,
            }))
Пример #12
0
    def test_update(self):
        run = Run.sync(
            ejudge_run_id=self.ejudge_run.run_id,
            ejudge_contest_id=self.ejudge_run.contest_id,
        )
        run.statement = self.statements[0]
        self.ejudge_run.score = 179
        db.session.flush()

        assert_that(run.score, equal_to(456))
        assert_that(run.ejudge_score, equal_to(456))
        assert_that(run.statement_id, equal_to(self.statements[0].id))
        assert_that(self.ejudge_run.score, equal_to(179))

        run = Run.sync(
            ejudge_run_id=self.ejudge_run.run_id,
            ejudge_contest_id=self.ejudge_run.contest_id,
        )
        db.session.flush()
        assert_that(run.score, equal_to(179))
        assert_that(run.ejudge_score, equal_to(179))
        assert_that(run.statement_id, equal_to(self.statements[0].id))

        assert_that(db.session.query(Run).count(), equal_to(1))
Пример #13
0
    def setUp(self):
        super(TestView__problem_runs, self).setUp()

        self.create_problems()
        self.create_statements()
        self.create_users()

        self.user1 = self.users[0]
        self.user2 = self.users[1]
        self.problem = self.problems[0]

        self.runs = [[Run(problem=self.problem, user=user) for i in range(3)]
                     for user in [self.user1, self.user2]]
        db.session.add_all(self.runs[0])  # user1 runs
        db.session.add_all(self.runs[1])  # user2 runs
        db.session.flush()
Пример #14
0
    def setUp(self):
        super(TestAPI__notification_update_run, self).setUp()

        self.create_problems()
        self.create_users()

        self.ej_run = EjudgeRun(
            run_id=123,
            user=self.users[0],
            problem=self.problems[0],
        )
        db.session.add(self.ej_run)
        db.session.flush()

        self.run = Run.from_ejudge_run(self.ej_run)
        db.session.add(self.run)
        db.session.flush()
Пример #15
0
    def post(self, problem_id: int):
        args = parser.parse(self.post_args)

        language_id = args['lang_id']
        statement_id = args.get('statement_id')
        user_id = args.get('user_id')
        file = parser.parse_files(request, 'file', 'file')

        # If context parameters are unavialable,
        # consider it as Moodle submission and set defaults
        context_id = args.get('context_id')
        context_source = args.get('context_source',
                                  DEFAULT_MOODLE_CONTEXT_SOURCE)
        is_visible = args.get('is_visible', True)

        # Здесь НЕЛЬЗЯ использовать .get(problem_id), см EjudgeProblem.__doc__
        problem = db.session.query(EjudgeProblem) \
            .filter_by(id=problem_id) \
            .one_or_none()

        if not problem:
            raise NotFound('Problem with this id is not found')

        if int(user_id) <= 0:
            raise BadRequest('Wrong user status')

        try:
            limit = 64
            if problem.output_only:
                limit = 1024 * 16
            text = self.check_file_restriction(file, limit)
        except ValueError as e:
            raise BadRequest(e.args[0])
        source_hash = Run.generate_source_hash(text)

        duplicate: Run = db.session.query(Run).filter(Run.user_id == user_id) \
            .filter(Run.problem_id == problem_id) \
            .order_by(Run.id.desc()).first()

        if duplicate is not None and \
                duplicate.source_hash == source_hash and \
                duplicate.ejudge_language_id == language_id:
            raise BadRequest(
                'Source file is duplicate of your previous submission')

        # There is not constraint on statement_id
        run = Run(
            user_id=user_id,
            problem_id=problem_id,
            statement_id=statement_id,
            ejudge_contest_id=problem.ejudge_contest_id,
            ejudge_language_id=language_id,
            ejudge_status=377,  # In queue
            source_hash=source_hash,

            # Context related properties
            context_source=context_source,
            is_visible=is_visible,
        )
        # If it's context aware submission,
        # overwrite statement_id with context
        if context_id:
            run.statement_id = context_id

        db.session.add(run)
        db.session.flush()

        run.update_source(text)

        run_id = run.id
        ejudge_url = current_app.config['EJUDGE_NEW_CLIENT_URL']

        # Коммит должен быть до отправки в очередь иначе это гонка
        db.session.commit()

        queue_submit(run_id, ejudge_url)
        return jsonify({'run_id': run_id})
Пример #16
0
 def _remove_run(self, run: Run):
     run.remove_source()
     db.session.delete(run)
     db.session.commit()
Пример #17
0
    def setUp(self):
        super().setUp()

        self.create_ejudge_problems()
        self.create_problems()
        self.create_statements()
        self.create_statement_problems()
        self.create_course_module_statement()

        self.user1 = SimpleUser(firstname='user1', lastname='user1')
        self.user2 = SimpleUser(firstname='user2', lastname='user2')
        db.session.add_all([self.user1, self.user2])
        db.session.flush()

        self.run1 = Run(user_id=self.user1.id,
                        problem_id=self.problems[1].id,
                        ejudge_status=0,
                        ejudge_language_id=1,
                        is_visible=True)
        self.run2 = Run(user_id=self.user1.id,
                        problem_id=self.problems[2].id,
                        ejudge_status=0,
                        ejudge_language_id=1,
                        is_visible=True)
        self.run3 = Run(user_id=self.user2.id,
                        problem_id=self.problems[1].id,
                        ejudge_status=2,
                        ejudge_language_id=2,
                        is_visible=True)
        self.run4 = Run(user_id=self.user2.id,
                        problem_id=self.problems[2].id,
                        ejudge_status=2,
                        ejudge_language_id=2,
                        is_visible=True)
        self.run5 = Run(user_id=self.user2.id,
                        problem_id=self.problems[1].id,
                        ejudge_status=2,
                        ejudge_language_id=2,
                        is_visible=False)

        self.run4.create_time = datetime.utcnow() - timedelta(days=1)

        # Context tests fixtures
        self.run1.context_source = CONTEXT_SOURCE
        self.run5.context_source = CONTEXT_SOURCE

        self.run1.statement_id = CONTEXT_ID_1
        self.run3.statement_id = CONTEXT_ID_1
        self.run5.statement_id = CONTEXT_ID_1
        self.run2.statement_id = CONTEXT_ID_2
        self.run4.statement_id = CONTEXT_ID_2

        db.session.add_all(
            [self.run1, self.run2, self.run3, self.run4, self.run5])

        self.group = Group()
        db.session.add(self.group)
        db.session.flush()

        user_group = UserGroup(user_id=self.user1.id, group_id=self.group.id)
        db.session.add(user_group)

        db.session.commit()