Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Joseph/ta error #979

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Draft

Joseph/ta error #979

wants to merge 14 commits into from

Conversation

joseph-sentry
Copy link
Contributor

we want to start generating UploadError objects when we have trouble parsing a JUnit XML so we can show them to the user in the error comment and the regular TA comment.

these 2 new tasks are meant to replace the test results processor and
test results finisher tasks

the difference between the tasks is that the new tasks:
- use the new parse_raw_upload function provided by the test results
  parser library
- instead of writing to the database in the processor, the finisher
  takes care of writing to the database
- the processor writes the results of its parsing and the finisher pulls
  from that
the upload task will check the new ta tasks feature flag to determine
whether to use the newly introduced ta processor and ta finisher tasks

we also call the new ta processor and ta finisher tasks via a chord
since we removed the concurrent db writes from the processors
also update test results parser version
we don't need to chunk them anymore and each upload can get its own
processing task
i want to introduce the new finished state in the test results upload
pipeline

to do so safely i'm adding the new v2_processed and v2_finished states

the reason for this is that the meaning of processed and v2_processed
are different

processed means that test instances are in the db and persisted
but in the new pipeline v2_finished has that meaning and v2_processed
just means that the intermediate results are in redis for now
we want to start persisting errors so we can display in the relevant
comments (coverage or TA)
we want to be able to pass UploadError objects to the test results
notifier so it can display the specific parser error to the user to
give them more information on the issue
we want to fetch any relevant upload errors and pass them to the test
results notifier in the finisher so it can display them
Copy link

This PR includes changes to shared. Please review them here: https://github.com/codecov/shared/compare/2674ae99811767e63151590906691aed4c5ce1f9...

Copy link

codecov bot commented Dec 23, 2024

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
1779 2 1777 1
View the top 2 failed tests by shortest run time
tasks/tests/unit/test_ta_finisher_task.py::::test_test_analytics_error_comment
Stack Traces | 0.128s run time
self = <sqlalchemy.engine.base.Connection object at 0x7fb153548110>
dialect = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
constructor = <bound method DefaultExecutionContext._init_compiled of <class 'sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2'>>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
args = (<sqlalchemy.dialects.postgresql.psycopg2.PGCompiler_psycopg2 object at 0x7fb160fb19d0>, [immutabledict({})])
conn = <sqlalchemy.pool.base._ConnectionFairy object at 0x7fb150dab950>
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def _execute_context(
        self, dialect, constructor, statement, parameters, *args
    ):
        """Create an :class:`.ExecutionContext` and execute, returning
        a :class:`_engine.ResultProxy`.
    
        """
    
        try:
            try:
                conn = self.__connection
            except AttributeError:
                # escape "except AttributeError" before revalidating
                # to prevent misleading stacktraces in Py3K
                conn = None
            if conn is None:
                conn = self._revalidate_connection()
    
            context = constructor(dialect, self, conn, *args)
        except BaseException as e:
            self._handle_dbapi_exception(
                e, util.text_type(statement), parameters, None, None
            )
    
        if context.compiled:
            context.pre_exec()
    
        cursor, statement, parameters = (
            context.cursor,
            context.statement,
            context.parameters,
        )
    
        if not context.executemany:
            parameters = parameters[0]
    
        if self._has_events or self.engine._has_events:
            for fn in self.dispatch.before_cursor_execute:
                statement, parameters = fn(
                    self,
                    cursor,
                    statement,
                    parameters,
                    context,
                    context.executemany,
                )
    
        if self._echo:
            self.engine.logger.info(statement)
            if not self.engine.hide_parameters:
                self.engine.logger.info(
                    "%r",
                    sql_util._repr_params(
                        parameters, batches=10, ismulti=context.executemany
                    ),
                )
            else:
                self.engine.logger.info(
                    "[SQL parameters hidden due to hide_parameters=True]"
                )
    
        evt_handled = False
        try:
            if context.executemany:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_executemany:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_executemany(
                        cursor, statement, parameters, context
                    )
            elif not parameters and context.no_parameters:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute_no_params:
                        if fn(cursor, statement, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_execute_no_params(
                        cursor, statement, context
                    )
            else:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
>                   self.dialect.do_execute(
                        cursor, statement, parameters, context
                    )

.../local/lib/python3.13.../sqlalchemy/engine/base.py:1276: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
cursor = <cursor object at 0x7fb1853a4220; closed: -1>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       psycopg2.errors.UndefinedTable: relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^

.../local/lib/python3.13.../sqlalchemy/engine/default.py:608: UndefinedTable

The above exception was the direct cause of the following exception:

dbsession = <sqlalchemy.orm.session.Session object at 0x7fb184220d70>
mocker = <pytest_mock.plugin.MockFixture object at 0x7fb1845c3290>
mock_storage = <shared.storage.memory.MemoryStorageService object at 0x7fb150dd3bf0>
celery_app = <Celery celery.tests at 0x7fb185702e90>
mock_repo_provider_service = <AsyncMock id='140399579021728'>
mock_pull_request_information = <AsyncMock id='140399579033152'>
generate_junit = <function generate_junit.<locals>._generate_junit at 0x7fb150da5da0>

    def test_test_analytics_error_comment(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        wrong_xml = """<?xml version="1.0" encoding="utf-8"?>
    <testsuites>
        <testsuite>
            <testcase time="0.001">
                <failure message="hello world"/>
            </testcase>
        </testsuite>
    </testsuites>
    """
        upload = generate_junit(raw=wrong_xml)
    
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
    
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
    
        assert result is False
    
>       result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )

.../tests/unit/test_ta_finisher_task.py:372: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tasks/ta_finisher.py:255: in run_impl
    notify_task_sig.apply_async()
.../local/lib/python3.13.../site-packages/celery/canvas.py:400: in apply_async
    return _apply(args, kwargs, **options)
.../local/lib/python3.13.../site-packages/sentry_sdk/tracing_utils.py:673: in func_with_tracing
    return func(*args, **kwargs)
tasks/base.py:150: in apply_async
    user_plan = _get_user_plan_from_task(db_session, self.name, kwargs)
celery_task_router.py:144: in _get_user_plan_from_task
    return func_to_use(dbsession, **task_kwargs)
celery_task_router.py:24: in _get_user_plan_from_repoid
    .first()
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3429: in first
    ret = list(self[0:1])
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3203: in __getitem__
    return list(res)
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3535: in __iter__
    return self._execute_and_instances(context)
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3560: in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1011: in execute
    return meth(self, multiparams, params)
.../local/lib/python3.13.../sqlalchemy/sql/elements.py:298: in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1124: in _execute_clauseelement
    ret = self._execute_context(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1316: in _execute_context
    self._handle_dbapi_exception(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1510: in _handle_dbapi_exception
    util.raise_(
.../local/lib/python3.13.../sqlalchemy/util/compat.py:182: in raise_
    raise exception
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1276: in _execute_context
    self.dialect.do_execute(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
cursor = <cursor object at 0x7fb1853a4220; closed: -1>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^
E       
E       [SQL: SELECT owners.plan AS owners_plan 
E       FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E       WHERE repos.repoid = %(repoid_1)s 
E        LIMIT %(param_1)s]
E       [parameters: {'repoid_1': 1022, 'param_1': 1}]
E       (Background on this error at: http://sqlalche..../e/13/f405)

.../local/lib/python3.13.../sqlalchemy/engine/default.py:608: ProgrammingError
tasks/tests/unit/test_ta_finisher_task.py::::test_test_analytics_regular_comment_with_error
Stack Traces | 0.156s run time
dbsession = <sqlalchemy.orm.session.Session object at 0x7fb1853a7c50>
mocker = <pytest_mock.plugin.MockFixture object at 0x7fb153549910>
mock_storage = <shared.storage.memory.MemoryStorageService object at 0x7fb1536cb170>
celery_app = <Celery celery.tests at 0x7fb185703ed0>
mock_repo_provider_service = <AsyncMock id='140399579023744'>
mock_pull_request_information = <AsyncMock id='140400773030512'>
generate_junit = <function generate_junit.<locals>._generate_junit at 0x7fb15323fa60>

    def test_test_analytics_regular_comment_with_error(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        commit = CommitFactory.create()
    
        wrong_xml = """<?xml version="1.0" encoding="utf-8"?>
    <testsuites>
        <testsuite>
            <testcase time="0.001">
                <failure message="hello world"/>
            </testcase>
        </testsuite>
    </testsuites>
    """
    
        upload = generate_junit(raw=wrong_xml, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        first_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert first_result is False
    
        testruns = [
            {
                "name": "test_divide",
                "outcome": "fail",
                "duration_seconds": 0.001,
                "failure_message": "hello world",
            },
        ]
    
        upload = generate_junit(testruns, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        second_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert second_result is True
    
        result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[first_result, second_result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )
    
        assert result["notify_attempted"] is True
        assert result["notify_succeeded"] is True
        assert result["queue_notify"] is False
    
        short_form_service_name = services_short_dict.get(
            upload.report.commit.repository.owner.service
        )
    
        mock_repo_provider_service.edit_comment.assert_called_once()
>       mock_repo_provider_service.edit_comment.assert_called_once_with(
            mock_pull_request_information.database_pull.pullid,
            mock_pull_request_information.database_pull.commentid,
            f"""### :x: Unsupported file format
    
    > Upload processing failed due to unsupported file format. Please review the parser error message:
    > `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`
    > For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).
    
    ---
    ### :x: 1 Tests Failed:
    | Tests completed | Failed | Passed | Skipped |
    |---|---|---|---|
    | 1 | 1 | 0 | 0 |
    <details><summary>View the top 1 failed tests by shortest run time</summary>
    
    >
    > ```python
    > tests.test_parsers.TestParsers test_divide
    > ```
    >
    > <details><summary>Stack Traces | 0.001s run time</summary>
    >
    > >
    > > ```python
    > > hello world
    > > ```
    >
    > </details>
    
    </details>
    
    To view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov.io/{short_form_service_name}/{upload.report.commit.repository.owner.username}/{upload.report.commit.repository.name}/tests/{upload.report.commit.branch})
    :loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)""",
        )
E       AssertionError: expected call not found.
E       Expected: edit_comment(<AsyncMock name='mock.database_pull.pullid' id='140400427567152'>, <AsyncMock name='mock.database_pull.commentid' id='140400142717616'>, '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestParsers test_divide\n> ```\n> \n> <details><summary>Stack Traces | 0.001s run time</summary>\n> \n> > \n> > ```python\n> > hello world\n> > ```\n> \n> </details>\n\n</details>\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov..../real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)')
E         Actual: edit_comment(<AsyncMock name='mock.database_pull.pullid' id='140400427567152'>, <AsyncMock name='mock.database_pull.commentid' id='140400142717616'>, '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestParsers test_divide\n> ```\n> \n> <details><summary>Stack Traces | 0.001s run time</summary>\n> \n> > \n> > ```python\n> > hello world\n> > ```\n> \n> </details>\n\n</details>\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov..../real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)')
E       
E       pytest introspection follows:
E       
E       Args:
E       assert (<AsyncMock n.../issues/304)') == (<AsyncMock n.../issues/304)')
E         
E         At index 2 diff: '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestPa...
E         
E         ...Full output truncated (2 lines hidden), use '-vv' to show

.../tests/unit/test_ta_finisher_task.py:478: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

@codecov-staging
Copy link

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
1779 2 1777 1
View the top 2 failed tests by shortest run time
tasks/tests/unit/test_ta_finisher_task.py::::test_test_analytics_error_comment
Stack Traces | 0.128s run time
self = <sqlalchemy.engine.base.Connection object at 0x7fb153548110>
dialect = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
constructor = <bound method DefaultExecutionContext._init_compiled of <class 'sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2'>>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
args = (<sqlalchemy.dialects.postgresql.psycopg2.PGCompiler_psycopg2 object at 0x7fb160fb19d0>, [immutabledict({})])
conn = <sqlalchemy.pool.base._ConnectionFairy object at 0x7fb150dab950>
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def _execute_context(
        self, dialect, constructor, statement, parameters, *args
    ):
        """Create an :class:`.ExecutionContext` and execute, returning
        a :class:`_engine.ResultProxy`.
    
        """
    
        try:
            try:
                conn = self.__connection
            except AttributeError:
                # escape "except AttributeError" before revalidating
                # to prevent misleading stacktraces in Py3K
                conn = None
            if conn is None:
                conn = self._revalidate_connection()
    
            context = constructor(dialect, self, conn, *args)
        except BaseException as e:
            self._handle_dbapi_exception(
                e, util.text_type(statement), parameters, None, None
            )
    
        if context.compiled:
            context.pre_exec()
    
        cursor, statement, parameters = (
            context.cursor,
            context.statement,
            context.parameters,
        )
    
        if not context.executemany:
            parameters = parameters[0]
    
        if self._has_events or self.engine._has_events:
            for fn in self.dispatch.before_cursor_execute:
                statement, parameters = fn(
                    self,
                    cursor,
                    statement,
                    parameters,
                    context,
                    context.executemany,
                )
    
        if self._echo:
            self.engine.logger.info(statement)
            if not self.engine.hide_parameters:
                self.engine.logger.info(
                    "%r",
                    sql_util._repr_params(
                        parameters, batches=10, ismulti=context.executemany
                    ),
                )
            else:
                self.engine.logger.info(
                    "[SQL parameters hidden due to hide_parameters=True]"
                )
    
        evt_handled = False
        try:
            if context.executemany:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_executemany:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_executemany(
                        cursor, statement, parameters, context
                    )
            elif not parameters and context.no_parameters:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute_no_params:
                        if fn(cursor, statement, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_execute_no_params(
                        cursor, statement, context
                    )
            else:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
>                   self.dialect.do_execute(
                        cursor, statement, parameters, context
                    )

.../local/lib/python3.13.../sqlalchemy/engine/base.py:1276: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
cursor = <cursor object at 0x7fb1853a4220; closed: -1>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       psycopg2.errors.UndefinedTable: relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^

.../local/lib/python3.13.../sqlalchemy/engine/default.py:608: UndefinedTable

The above exception was the direct cause of the following exception:

dbsession = <sqlalchemy.orm.session.Session object at 0x7fb184220d70>
mocker = <pytest_mock.plugin.MockFixture object at 0x7fb1845c3290>
mock_storage = <shared.storage.memory.MemoryStorageService object at 0x7fb150dd3bf0>
celery_app = <Celery celery.tests at 0x7fb185702e90>
mock_repo_provider_service = <AsyncMock id='140399579021728'>
mock_pull_request_information = <AsyncMock id='140399579033152'>
generate_junit = <function generate_junit.<locals>._generate_junit at 0x7fb150da5da0>

    def test_test_analytics_error_comment(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        wrong_xml = """<?xml version="1.0" encoding="utf-8"?>
    <testsuites>
        <testsuite>
            <testcase time="0.001">
                <failure message="hello world"/>
            </testcase>
        </testsuite>
    </testsuites>
    """
        upload = generate_junit(raw=wrong_xml)
    
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
    
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
    
        assert result is False
    
>       result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )

.../tests/unit/test_ta_finisher_task.py:372: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tasks/ta_finisher.py:255: in run_impl
    notify_task_sig.apply_async()
.../local/lib/python3.13.../site-packages/celery/canvas.py:400: in apply_async
    return _apply(args, kwargs, **options)
.../local/lib/python3.13.../site-packages/sentry_sdk/tracing_utils.py:673: in func_with_tracing
    return func(*args, **kwargs)
tasks/base.py:150: in apply_async
    user_plan = _get_user_plan_from_task(db_session, self.name, kwargs)
celery_task_router.py:144: in _get_user_plan_from_task
    return func_to_use(dbsession, **task_kwargs)
celery_task_router.py:24: in _get_user_plan_from_repoid
    .first()
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3429: in first
    ret = list(self[0:1])
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3203: in __getitem__
    return list(res)
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3535: in __iter__
    return self._execute_and_instances(context)
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3560: in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1011: in execute
    return meth(self, multiparams, params)
.../local/lib/python3.13.../sqlalchemy/sql/elements.py:298: in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1124: in _execute_clauseelement
    ret = self._execute_context(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1316: in _execute_context
    self._handle_dbapi_exception(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1510: in _handle_dbapi_exception
    util.raise_(
.../local/lib/python3.13.../sqlalchemy/util/compat.py:182: in raise_
    raise exception
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1276: in _execute_context
    self.dialect.do_execute(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
cursor = <cursor object at 0x7fb1853a4220; closed: -1>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^
E       
E       [SQL: SELECT owners.plan AS owners_plan 
E       FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E       WHERE repos.repoid = %(repoid_1)s 
E        LIMIT %(param_1)s]
E       [parameters: {'repoid_1': 1022, 'param_1': 1}]
E       (Background on this error at: http://sqlalche..../e/13/f405)

.../local/lib/python3.13.../sqlalchemy/engine/default.py:608: ProgrammingError
tasks/tests/unit/test_ta_finisher_task.py::::test_test_analytics_regular_comment_with_error
Stack Traces | 0.156s run time
dbsession = <sqlalchemy.orm.session.Session object at 0x7fb1853a7c50>
mocker = <pytest_mock.plugin.MockFixture object at 0x7fb153549910>
mock_storage = <shared.storage.memory.MemoryStorageService object at 0x7fb1536cb170>
celery_app = <Celery celery.tests at 0x7fb185703ed0>
mock_repo_provider_service = <AsyncMock id='140399579023744'>
mock_pull_request_information = <AsyncMock id='140400773030512'>
generate_junit = <function generate_junit.<locals>._generate_junit at 0x7fb15323fa60>

    def test_test_analytics_regular_comment_with_error(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        commit = CommitFactory.create()
    
        wrong_xml = """<?xml version="1.0" encoding="utf-8"?>
    <testsuites>
        <testsuite>
            <testcase time="0.001">
                <failure message="hello world"/>
            </testcase>
        </testsuite>
    </testsuites>
    """
    
        upload = generate_junit(raw=wrong_xml, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        first_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert first_result is False
    
        testruns = [
            {
                "name": "test_divide",
                "outcome": "fail",
                "duration_seconds": 0.001,
                "failure_message": "hello world",
            },
        ]
    
        upload = generate_junit(testruns, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        second_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert second_result is True
    
        result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[first_result, second_result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )
    
        assert result["notify_attempted"] is True
        assert result["notify_succeeded"] is True
        assert result["queue_notify"] is False
    
        short_form_service_name = services_short_dict.get(
            upload.report.commit.repository.owner.service
        )
    
        mock_repo_provider_service.edit_comment.assert_called_once()
>       mock_repo_provider_service.edit_comment.assert_called_once_with(
            mock_pull_request_information.database_pull.pullid,
            mock_pull_request_information.database_pull.commentid,
            f"""### :x: Unsupported file format
    
    > Upload processing failed due to unsupported file format. Please review the parser error message:
    > `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`
    > For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).
    
    ---
    ### :x: 1 Tests Failed:
    | Tests completed | Failed | Passed | Skipped |
    |---|---|---|---|
    | 1 | 1 | 0 | 0 |
    <details><summary>View the top 1 failed tests by shortest run time</summary>
    
    >
    > ```python
    > tests.test_parsers.TestParsers test_divide
    > ```
    >
    > <details><summary>Stack Traces | 0.001s run time</summary>
    >
    > >
    > > ```python
    > > hello world
    > > ```
    >
    > </details>
    
    </details>
    
    To view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov.io/{short_form_service_name}/{upload.report.commit.repository.owner.username}/{upload.report.commit.repository.name}/tests/{upload.report.commit.branch})
    :loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)""",
        )
E       AssertionError: expected call not found.
E       Expected: edit_comment(<AsyncMock name='mock.database_pull.pullid' id='140400427567152'>, <AsyncMock name='mock.database_pull.commentid' id='140400142717616'>, '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestParsers test_divide\n> ```\n> \n> <details><summary>Stack Traces | 0.001s run time</summary>\n> \n> > \n> > ```python\n> > hello world\n> > ```\n> \n> </details>\n\n</details>\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov..../real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)')
E         Actual: edit_comment(<AsyncMock name='mock.database_pull.pullid' id='140400427567152'>, <AsyncMock name='mock.database_pull.commentid' id='140400142717616'>, '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestParsers test_divide\n> ```\n> \n> <details><summary>Stack Traces | 0.001s run time</summary>\n> \n> > \n> > ```python\n> > hello world\n> > ```\n> \n> </details>\n\n</details>\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov..../real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)')
E       
E       pytest introspection follows:
E       
E       Args:
E       assert (<AsyncMock n.../issues/304)') == (<AsyncMock n.../issues/304)')
E         
E         At index 2 diff: '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestPa...
E         
E         ...Full output truncated (2 lines hidden), use '-vv' to show

.../tests/unit/test_ta_finisher_task.py:478: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

@codecov-qa
Copy link

codecov-qa bot commented Dec 23, 2024

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
1779 2 1777 1
View the top 2 failed tests by shortest run time
tasks/tests/unit/test_ta_finisher_task.py::::test_test_analytics_error_comment
Stack Traces | 0.128s run time
self = <sqlalchemy.engine.base.Connection object at 0x7fb153548110>
dialect = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
constructor = <bound method DefaultExecutionContext._init_compiled of <class 'sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2'>>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
args = (<sqlalchemy.dialects.postgresql.psycopg2.PGCompiler_psycopg2 object at 0x7fb160fb19d0>, [immutabledict({})])
conn = <sqlalchemy.pool.base._ConnectionFairy object at 0x7fb150dab950>
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def _execute_context(
        self, dialect, constructor, statement, parameters, *args
    ):
        """Create an :class:`.ExecutionContext` and execute, returning
        a :class:`_engine.ResultProxy`.
    
        """
    
        try:
            try:
                conn = self.__connection
            except AttributeError:
                # escape "except AttributeError" before revalidating
                # to prevent misleading stacktraces in Py3K
                conn = None
            if conn is None:
                conn = self._revalidate_connection()
    
            context = constructor(dialect, self, conn, *args)
        except BaseException as e:
            self._handle_dbapi_exception(
                e, util.text_type(statement), parameters, None, None
            )
    
        if context.compiled:
            context.pre_exec()
    
        cursor, statement, parameters = (
            context.cursor,
            context.statement,
            context.parameters,
        )
    
        if not context.executemany:
            parameters = parameters[0]
    
        if self._has_events or self.engine._has_events:
            for fn in self.dispatch.before_cursor_execute:
                statement, parameters = fn(
                    self,
                    cursor,
                    statement,
                    parameters,
                    context,
                    context.executemany,
                )
    
        if self._echo:
            self.engine.logger.info(statement)
            if not self.engine.hide_parameters:
                self.engine.logger.info(
                    "%r",
                    sql_util._repr_params(
                        parameters, batches=10, ismulti=context.executemany
                    ),
                )
            else:
                self.engine.logger.info(
                    "[SQL parameters hidden due to hide_parameters=True]"
                )
    
        evt_handled = False
        try:
            if context.executemany:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_executemany:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_executemany(
                        cursor, statement, parameters, context
                    )
            elif not parameters and context.no_parameters:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute_no_params:
                        if fn(cursor, statement, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_execute_no_params(
                        cursor, statement, context
                    )
            else:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
>                   self.dialect.do_execute(
                        cursor, statement, parameters, context
                    )

.../local/lib/python3.13.../sqlalchemy/engine/base.py:1276: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
cursor = <cursor object at 0x7fb1853a4220; closed: -1>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       psycopg2.errors.UndefinedTable: relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^

.../local/lib/python3.13.../sqlalchemy/engine/default.py:608: UndefinedTable

The above exception was the direct cause of the following exception:

dbsession = <sqlalchemy.orm.session.Session object at 0x7fb184220d70>
mocker = <pytest_mock.plugin.MockFixture object at 0x7fb1845c3290>
mock_storage = <shared.storage.memory.MemoryStorageService object at 0x7fb150dd3bf0>
celery_app = <Celery celery.tests at 0x7fb185702e90>
mock_repo_provider_service = <AsyncMock id='140399579021728'>
mock_pull_request_information = <AsyncMock id='140399579033152'>
generate_junit = <function generate_junit.<locals>._generate_junit at 0x7fb150da5da0>

    def test_test_analytics_error_comment(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        wrong_xml = """<?xml version="1.0" encoding="utf-8"?>
    <testsuites>
        <testsuite>
            <testcase time="0.001">
                <failure message="hello world"/>
            </testcase>
        </testsuite>
    </testsuites>
    """
        upload = generate_junit(raw=wrong_xml)
    
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
    
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
    
        assert result is False
    
>       result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )

.../tests/unit/test_ta_finisher_task.py:372: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tasks/ta_finisher.py:255: in run_impl
    notify_task_sig.apply_async()
.../local/lib/python3.13.../site-packages/celery/canvas.py:400: in apply_async
    return _apply(args, kwargs, **options)
.../local/lib/python3.13.../site-packages/sentry_sdk/tracing_utils.py:673: in func_with_tracing
    return func(*args, **kwargs)
tasks/base.py:150: in apply_async
    user_plan = _get_user_plan_from_task(db_session, self.name, kwargs)
celery_task_router.py:144: in _get_user_plan_from_task
    return func_to_use(dbsession, **task_kwargs)
celery_task_router.py:24: in _get_user_plan_from_repoid
    .first()
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3429: in first
    ret = list(self[0:1])
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3203: in __getitem__
    return list(res)
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3535: in __iter__
    return self._execute_and_instances(context)
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3560: in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1011: in execute
    return meth(self, multiparams, params)
.../local/lib/python3.13.../sqlalchemy/sql/elements.py:298: in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1124: in _execute_clauseelement
    ret = self._execute_context(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1316: in _execute_context
    self._handle_dbapi_exception(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1510: in _handle_dbapi_exception
    util.raise_(
.../local/lib/python3.13.../sqlalchemy/util/compat.py:182: in raise_
    raise exception
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1276: in _execute_context
    self.dialect.do_execute(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
cursor = <cursor object at 0x7fb1853a4220; closed: -1>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^
E       
E       [SQL: SELECT owners.plan AS owners_plan 
E       FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E       WHERE repos.repoid = %(repoid_1)s 
E        LIMIT %(param_1)s]
E       [parameters: {'repoid_1': 1022, 'param_1': 1}]
E       (Background on this error at: http://sqlalche..../e/13/f405)

.../local/lib/python3.13.../sqlalchemy/engine/default.py:608: ProgrammingError
tasks/tests/unit/test_ta_finisher_task.py::::test_test_analytics_regular_comment_with_error
Stack Traces | 0.156s run time
dbsession = <sqlalchemy.orm.session.Session object at 0x7fb1853a7c50>
mocker = <pytest_mock.plugin.MockFixture object at 0x7fb153549910>
mock_storage = <shared.storage.memory.MemoryStorageService object at 0x7fb1536cb170>
celery_app = <Celery celery.tests at 0x7fb185703ed0>
mock_repo_provider_service = <AsyncMock id='140399579023744'>
mock_pull_request_information = <AsyncMock id='140400773030512'>
generate_junit = <function generate_junit.<locals>._generate_junit at 0x7fb15323fa60>

    def test_test_analytics_regular_comment_with_error(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        commit = CommitFactory.create()
    
        wrong_xml = """<?xml version="1.0" encoding="utf-8"?>
    <testsuites>
        <testsuite>
            <testcase time="0.001">
                <failure message="hello world"/>
            </testcase>
        </testsuite>
    </testsuites>
    """
    
        upload = generate_junit(raw=wrong_xml, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        first_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert first_result is False
    
        testruns = [
            {
                "name": "test_divide",
                "outcome": "fail",
                "duration_seconds": 0.001,
                "failure_message": "hello world",
            },
        ]
    
        upload = generate_junit(testruns, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        second_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert second_result is True
    
        result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[first_result, second_result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )
    
        assert result["notify_attempted"] is True
        assert result["notify_succeeded"] is True
        assert result["queue_notify"] is False
    
        short_form_service_name = services_short_dict.get(
            upload.report.commit.repository.owner.service
        )
    
        mock_repo_provider_service.edit_comment.assert_called_once()
>       mock_repo_provider_service.edit_comment.assert_called_once_with(
            mock_pull_request_information.database_pull.pullid,
            mock_pull_request_information.database_pull.commentid,
            f"""### :x: Unsupported file format
    
    > Upload processing failed due to unsupported file format. Please review the parser error message:
    > `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`
    > For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).
    
    ---
    ### :x: 1 Tests Failed:
    | Tests completed | Failed | Passed | Skipped |
    |---|---|---|---|
    | 1 | 1 | 0 | 0 |
    <details><summary>View the top 1 failed tests by shortest run time</summary>
    
    >
    > ```python
    > tests.test_parsers.TestParsers test_divide
    > ```
    >
    > <details><summary>Stack Traces | 0.001s run time</summary>
    >
    > >
    > > ```python
    > > hello world
    > > ```
    >
    > </details>
    
    </details>
    
    To view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov.io/{short_form_service_name}/{upload.report.commit.repository.owner.username}/{upload.report.commit.repository.name}/tests/{upload.report.commit.branch})
    :loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)""",
        )
E       AssertionError: expected call not found.
E       Expected: edit_comment(<AsyncMock name='mock.database_pull.pullid' id='140400427567152'>, <AsyncMock name='mock.database_pull.commentid' id='140400142717616'>, '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestParsers test_divide\n> ```\n> \n> <details><summary>Stack Traces | 0.001s run time</summary>\n> \n> > \n> > ```python\n> > hello world\n> > ```\n> \n> </details>\n\n</details>\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov..../real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)')
E         Actual: edit_comment(<AsyncMock name='mock.database_pull.pullid' id='140400427567152'>, <AsyncMock name='mock.database_pull.commentid' id='140400142717616'>, '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestParsers test_divide\n> ```\n> \n> <details><summary>Stack Traces | 0.001s run time</summary>\n> \n> > \n> > ```python\n> > hello world\n> > ```\n> \n> </details>\n\n</details>\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov..../real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)')
E       
E       pytest introspection follows:
E       
E       Args:
E       assert (<AsyncMock n.../issues/304)') == (<AsyncMock n.../issues/304)')
E         
E         At index 2 diff: '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestPa...
E         
E         ...Full output truncated (2 lines hidden), use '-vv' to show

.../tests/unit/test_ta_finisher_task.py:478: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

Copy link

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
1779 2 1777 1
View the top 2 failed tests by shortest run time
tasks/tests/unit/test_ta_finisher_task.py::::test_test_analytics_error_comment
Stack Traces | 0.128s run time
self = <sqlalchemy.engine.base.Connection object at 0x7fb153548110>
dialect = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
constructor = <bound method DefaultExecutionContext._init_compiled of <class 'sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2'>>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
args = (<sqlalchemy.dialects.postgresql.psycopg2.PGCompiler_psycopg2 object at 0x7fb160fb19d0>, [immutabledict({})])
conn = <sqlalchemy.pool.base._ConnectionFairy object at 0x7fb150dab950>
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def _execute_context(
        self, dialect, constructor, statement, parameters, *args
    ):
        """Create an :class:`.ExecutionContext` and execute, returning
        a :class:`_engine.ResultProxy`.
    
        """
    
        try:
            try:
                conn = self.__connection
            except AttributeError:
                # escape "except AttributeError" before revalidating
                # to prevent misleading stacktraces in Py3K
                conn = None
            if conn is None:
                conn = self._revalidate_connection()
    
            context = constructor(dialect, self, conn, *args)
        except BaseException as e:
            self._handle_dbapi_exception(
                e, util.text_type(statement), parameters, None, None
            )
    
        if context.compiled:
            context.pre_exec()
    
        cursor, statement, parameters = (
            context.cursor,
            context.statement,
            context.parameters,
        )
    
        if not context.executemany:
            parameters = parameters[0]
    
        if self._has_events or self.engine._has_events:
            for fn in self.dispatch.before_cursor_execute:
                statement, parameters = fn(
                    self,
                    cursor,
                    statement,
                    parameters,
                    context,
                    context.executemany,
                )
    
        if self._echo:
            self.engine.logger.info(statement)
            if not self.engine.hide_parameters:
                self.engine.logger.info(
                    "%r",
                    sql_util._repr_params(
                        parameters, batches=10, ismulti=context.executemany
                    ),
                )
            else:
                self.engine.logger.info(
                    "[SQL parameters hidden due to hide_parameters=True]"
                )
    
        evt_handled = False
        try:
            if context.executemany:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_executemany:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_executemany(
                        cursor, statement, parameters, context
                    )
            elif not parameters and context.no_parameters:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute_no_params:
                        if fn(cursor, statement, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_execute_no_params(
                        cursor, statement, context
                    )
            else:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
>                   self.dialect.do_execute(
                        cursor, statement, parameters, context
                    )

.../local/lib/python3.13.../sqlalchemy/engine/base.py:1276: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
cursor = <cursor object at 0x7fb1853a4220; closed: -1>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       psycopg2.errors.UndefinedTable: relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^

.../local/lib/python3.13.../sqlalchemy/engine/default.py:608: UndefinedTable

The above exception was the direct cause of the following exception:

dbsession = <sqlalchemy.orm.session.Session object at 0x7fb184220d70>
mocker = <pytest_mock.plugin.MockFixture object at 0x7fb1845c3290>
mock_storage = <shared.storage.memory.MemoryStorageService object at 0x7fb150dd3bf0>
celery_app = <Celery celery.tests at 0x7fb185702e90>
mock_repo_provider_service = <AsyncMock id='140399579021728'>
mock_pull_request_information = <AsyncMock id='140399579033152'>
generate_junit = <function generate_junit.<locals>._generate_junit at 0x7fb150da5da0>

    def test_test_analytics_error_comment(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        wrong_xml = """<?xml version="1.0" encoding="utf-8"?>
    <testsuites>
        <testsuite>
            <testcase time="0.001">
                <failure message="hello world"/>
            </testcase>
        </testsuite>
    </testsuites>
    """
        upload = generate_junit(raw=wrong_xml)
    
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
    
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
    
        assert result is False
    
>       result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )

.../tests/unit/test_ta_finisher_task.py:372: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tasks/ta_finisher.py:255: in run_impl
    notify_task_sig.apply_async()
.../local/lib/python3.13.../site-packages/celery/canvas.py:400: in apply_async
    return _apply(args, kwargs, **options)
.../local/lib/python3.13.../site-packages/sentry_sdk/tracing_utils.py:673: in func_with_tracing
    return func(*args, **kwargs)
tasks/base.py:150: in apply_async
    user_plan = _get_user_plan_from_task(db_session, self.name, kwargs)
celery_task_router.py:144: in _get_user_plan_from_task
    return func_to_use(dbsession, **task_kwargs)
celery_task_router.py:24: in _get_user_plan_from_repoid
    .first()
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3429: in first
    ret = list(self[0:1])
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3203: in __getitem__
    return list(res)
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3535: in __iter__
    return self._execute_and_instances(context)
.../local/lib/python3.13.../sqlalchemy/orm/query.py:3560: in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1011: in execute
    return meth(self, multiparams, params)
.../local/lib/python3.13.../sqlalchemy/sql/elements.py:298: in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1124: in _execute_clauseelement
    ret = self._execute_context(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1316: in _execute_context
    self._handle_dbapi_exception(
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1510: in _handle_dbapi_exception
    util.raise_(
.../local/lib/python3.13.../sqlalchemy/util/compat.py:182: in raise_
    raise exception
.../local/lib/python3.13.../sqlalchemy/engine/base.py:1276: in _execute_context
    self.dialect.do_execute(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00>
cursor = <cursor object at 0x7fb1853a4220; closed: -1>
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^
E       
E       [SQL: SELECT owners.plan AS owners_plan 
E       FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E       WHERE repos.repoid = %(repoid_1)s 
E        LIMIT %(param_1)s]
E       [parameters: {'repoid_1': 1022, 'param_1': 1}]
E       (Background on this error at: http://sqlalche..../e/13/f405)

.../local/lib/python3.13.../sqlalchemy/engine/default.py:608: ProgrammingError
tasks/tests/unit/test_ta_finisher_task.py::::test_test_analytics_regular_comment_with_error
Stack Traces | 0.156s run time
dbsession = <sqlalchemy.orm.session.Session object at 0x7fb1853a7c50>
mocker = <pytest_mock.plugin.MockFixture object at 0x7fb153549910>
mock_storage = <shared.storage.memory.MemoryStorageService object at 0x7fb1536cb170>
celery_app = <Celery celery.tests at 0x7fb185703ed0>
mock_repo_provider_service = <AsyncMock id='140399579023744'>
mock_pull_request_information = <AsyncMock id='140400773030512'>
generate_junit = <function generate_junit.<locals>._generate_junit at 0x7fb15323fa60>

    def test_test_analytics_regular_comment_with_error(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        commit = CommitFactory.create()
    
        wrong_xml = """<?xml version="1.0" encoding="utf-8"?>
    <testsuites>
        <testsuite>
            <testcase time="0.001">
                <failure message="hello world"/>
            </testcase>
        </testsuite>
    </testsuites>
    """
    
        upload = generate_junit(raw=wrong_xml, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        first_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert first_result is False
    
        testruns = [
            {
                "name": "test_divide",
                "outcome": "fail",
                "duration_seconds": 0.001,
                "failure_message": "hello world",
            },
        ]
    
        upload = generate_junit(testruns, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        second_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert second_result is True
    
        result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[first_result, second_result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )
    
        assert result["notify_attempted"] is True
        assert result["notify_succeeded"] is True
        assert result["queue_notify"] is False
    
        short_form_service_name = services_short_dict.get(
            upload.report.commit.repository.owner.service
        )
    
        mock_repo_provider_service.edit_comment.assert_called_once()
>       mock_repo_provider_service.edit_comment.assert_called_once_with(
            mock_pull_request_information.database_pull.pullid,
            mock_pull_request_information.database_pull.commentid,
            f"""### :x: Unsupported file format
    
    > Upload processing failed due to unsupported file format. Please review the parser error message:
    > `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`
    > For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).
    
    ---
    ### :x: 1 Tests Failed:
    | Tests completed | Failed | Passed | Skipped |
    |---|---|---|---|
    | 1 | 1 | 0 | 0 |
    <details><summary>View the top 1 failed tests by shortest run time</summary>
    
    >
    > ```python
    > tests.test_parsers.TestParsers test_divide
    > ```
    >
    > <details><summary>Stack Traces | 0.001s run time</summary>
    >
    > >
    > > ```python
    > > hello world
    > > ```
    >
    > </details>
    
    </details>
    
    To view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov.io/{short_form_service_name}/{upload.report.commit.repository.owner.username}/{upload.report.commit.repository.name}/tests/{upload.report.commit.branch})
    :loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)""",
        )
E       AssertionError: expected call not found.
E       Expected: edit_comment(<AsyncMock name='mock.database_pull.pullid' id='140400427567152'>, <AsyncMock name='mock.database_pull.commentid' id='140400142717616'>, '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestParsers test_divide\n> ```\n> \n> <details><summary>Stack Traces | 0.001s run time</summary>\n> \n> > \n> > ```python\n> > hello world\n> > ```\n> \n> </details>\n\n</details>\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov..../real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)')
E         Actual: edit_comment(<AsyncMock name='mock.database_pull.pullid' id='140400427567152'>, <AsyncMock name='mock.database_pull.commentid' id='140400142717616'>, '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestParsers test_divide\n> ```\n> \n> <details><summary>Stack Traces | 0.001s run time</summary>\n> \n> > \n> > ```python\n> > hello world\n> > ```\n> \n> </details>\n\n</details>\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov..../real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github..../feedback/issues/304)')
E       
E       pytest introspection follows:
E       
E       Args:
E       assert (<AsyncMock n.../issues/304)') == (<AsyncMock n.../issues/304)')
E         
E         At index 2 diff: '### :x: Unsupported file format\n\n> Upload processing failed due to unsupported file format. Please review the parser error message:\n> `Error parsing JUnit XML at 4:32: ParserError: No name found`\n> For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n<details><summary>View the top 1 failed tests by shortest run time</summary>\n\n> \n> ```python\n> tests.test_parsers.TestPa...
E         
E         ...Full output truncated (2 lines hidden), use '-vv' to show

.../tests/unit/test_ta_finisher_task.py:478: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

Copy link

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
1780 2 1777 1
View the top 2 failed tests by shortest run time
test_test_analytics_error_comment
Stack Traces | 0.128s run time
self = &lt;sqlalchemy.engine.base.Connection object at 0x7fb153548110&gt;
dialect = &lt;sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00&gt;
constructor = &lt;bound method DefaultExecutionContext._init_compiled of &lt;class 'sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2'&gt;&gt;
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
args = (&lt;sqlalchemy.dialects.postgresql.psycopg2.PGCompiler_psycopg2 object at 0x7fb160fb19d0&gt;, [immutabledict({})])
conn = &lt;sqlalchemy.pool.base._ConnectionFairy object at 0x7fb150dab950&gt;
context = &lt;sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650&gt;

    def _execute_context(
        self, dialect, constructor, statement, parameters, *args
    ):
        """Create an :class:`.ExecutionContext` and execute, returning
        a :class:`_engine.ResultProxy`.
    
        """
    
        try:
            try:
                conn = self.__connection
            except AttributeError:
                # escape "except AttributeError" before revalidating
                # to prevent misleading stacktraces in Py3K
                conn = None
            if conn is None:
                conn = self._revalidate_connection()
    
            context = constructor(dialect, self, conn, *args)
        except BaseException as e:
            self._handle_dbapi_exception(
                e, util.text_type(statement), parameters, None, None
            )
    
        if context.compiled:
            context.pre_exec()
    
        cursor, statement, parameters = (
            context.cursor,
            context.statement,
            context.parameters,
        )
    
        if not context.executemany:
            parameters = parameters[0]
    
        if self._has_events or self.engine._has_events:
            for fn in self.dispatch.before_cursor_execute:
                statement, parameters = fn(
                    self,
                    cursor,
                    statement,
                    parameters,
                    context,
                    context.executemany,
                )
    
        if self._echo:
            self.engine.logger.info(statement)
            if not self.engine.hide_parameters:
                self.engine.logger.info(
                    "%r",
                    sql_util._repr_params(
                        parameters, batches=10, ismulti=context.executemany
                    ),
                )
            else:
                self.engine.logger.info(
                    "[SQL parameters hidden due to hide_parameters=True]"
                )
    
        evt_handled = False
        try:
            if context.executemany:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_executemany:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_executemany(
                        cursor, statement, parameters, context
                    )
            elif not parameters and context.no_parameters:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute_no_params:
                        if fn(cursor, statement, context):
                            evt_handled = True
                            break
                if not evt_handled:
                    self.dialect.do_execute_no_params(
                        cursor, statement, context
                    )
            else:
                if self.dialect._has_events:
                    for fn in self.dialect.dispatch.do_execute:
                        if fn(cursor, statement, parameters, context):
                            evt_handled = True
                            break
                if not evt_handled:
&gt;                   self.dialect.do_execute(
                        cursor, statement, parameters, context
                    )

/usr/local/lib/python3.13/site-packages/sqlalchemy/engine/base.py:1276: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = &lt;sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00&gt;
cursor = &lt;cursor object at 0x7fb1853a4220; closed: -1&gt;
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = &lt;sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650&gt;

    def do_execute(self, cursor, statement, parameters, context=None):
&gt;       cursor.execute(statement, parameters)
E       psycopg2.errors.UndefinedTable: relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^

/usr/local/lib/python3.13/site-packages/sqlalchemy/engine/default.py:608: UndefinedTable

The above exception was the direct cause of the following exception:

dbsession = &lt;sqlalchemy.orm.session.Session object at 0x7fb184220d70&gt;
mocker = &lt;pytest_mock.plugin.MockFixture object at 0x7fb1845c3290&gt;
mock_storage = &lt;shared.storage.memory.MemoryStorageService object at 0x7fb150dd3bf0&gt;
celery_app = &lt;Celery celery.tests at 0x7fb185702e90&gt;
mock_repo_provider_service = &lt;AsyncMock id='140399579021728'&gt;
mock_pull_request_information = &lt;AsyncMock id='140399579033152'&gt;
generate_junit = &lt;function generate_junit.&lt;locals&gt;._generate_junit at 0x7fb150da5da0&gt;

    def test_test_analytics_error_comment(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        wrong_xml = """&lt;?xml version="1.0" encoding="utf-8"?&gt;
    &lt;testsuites&gt;
        &lt;testsuite&gt;
            &lt;testcase time="0.001"&gt;
                &lt;failure message="hello world"/&gt;
            &lt;/testcase&gt;
        &lt;/testsuite&gt;
    &lt;/testsuites&gt;
    """
        upload = generate_junit(raw=wrong_xml)
    
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
    
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
    
        assert result is False
    
&gt;       result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )

tasks/tests/unit/test_ta_finisher_task.py:372: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tasks/ta_finisher.py:255: in run_impl
    notify_task_sig.apply_async()
/usr/local/lib/python3.13/site-packages/celery/canvas.py:400: in apply_async
    return _apply(args, kwargs, **options)
/usr/local/lib/python3.13/site-packages/sentry_sdk/tracing_utils.py:673: in func_with_tracing
    return func(*args, **kwargs)
tasks/base.py:150: in apply_async
    user_plan = _get_user_plan_from_task(db_session, self.name, kwargs)
celery_task_router.py:144: in _get_user_plan_from_task
    return func_to_use(dbsession, **task_kwargs)
celery_task_router.py:24: in _get_user_plan_from_repoid
    .first()
/usr/local/lib/python3.13/site-packages/sqlalchemy/orm/query.py:3429: in first
    ret = list(self[0:1])
/usr/local/lib/python3.13/site-packages/sqlalchemy/orm/query.py:3203: in __getitem__
    return list(res)
/usr/local/lib/python3.13/site-packages/sqlalchemy/orm/query.py:3535: in __iter__
    return self._execute_and_instances(context)
/usr/local/lib/python3.13/site-packages/sqlalchemy/orm/query.py:3560: in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
/usr/local/lib/python3.13/site-packages/sqlalchemy/engine/base.py:1011: in execute
    return meth(self, multiparams, params)
/usr/local/lib/python3.13/site-packages/sqlalchemy/sql/elements.py:298: in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
/usr/local/lib/python3.13/site-packages/sqlalchemy/engine/base.py:1124: in _execute_clauseelement
    ret = self._execute_context(
/usr/local/lib/python3.13/site-packages/sqlalchemy/engine/base.py:1316: in _execute_context
    self._handle_dbapi_exception(
/usr/local/lib/python3.13/site-packages/sqlalchemy/engine/base.py:1510: in _handle_dbapi_exception
    util.raise_(
/usr/local/lib/python3.13/site-packages/sqlalchemy/util/compat.py:182: in raise_
    raise exception
/usr/local/lib/python3.13/site-packages/sqlalchemy/engine/base.py:1276: in _execute_context
    self.dialect.do_execute(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = &lt;sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7fb197b93e00&gt;
cursor = &lt;cursor object at 0x7fb1853a4220; closed: -1&gt;
statement = 'SELECT owners.plan AS owners_plan \nFROM repos JOIN owners ON owners.ownerid = repos.ownerid \nWHERE repos.repoid = %(repoid_1)s \n LIMIT %(param_1)s'
parameters = {'param_1': 1, 'repoid_1': 1022}
context = &lt;sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fb150d18650&gt;

    def do_execute(self, cursor, statement, parameters, context=None):
&gt;       cursor.execute(statement, parameters)
E       sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "repos" does not exist
E       LINE 2: FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E                    ^
E       
E       [SQL: SELECT owners.plan AS owners_plan 
E       FROM repos JOIN owners ON owners.ownerid = repos.ownerid 
E       WHERE repos.repoid = %(repoid_1)s 
E        LIMIT %(param_1)s]
E       [parameters: {'repoid_1': 1022, 'param_1': 1}]
E       (Background on this error at: http://sqlalche.me/e/13/f405)

/usr/local/lib/python3.13/site-packages/sqlalchemy/engine/default.py:608: ProgrammingError
test_test_analytics_regular_comment_with_error
Stack Traces | 0.156s run time
dbsession = &lt;sqlalchemy.orm.session.Session object at 0x7fb1853a7c50&gt;
mocker = &lt;pytest_mock.plugin.MockFixture object at 0x7fb153549910&gt;
mock_storage = &lt;shared.storage.memory.MemoryStorageService object at 0x7fb1536cb170&gt;
celery_app = &lt;Celery celery.tests at 0x7fb185703ed0&gt;
mock_repo_provider_service = &lt;AsyncMock id='140399579023744'&gt;
mock_pull_request_information = &lt;AsyncMock id='140400773030512'&gt;
generate_junit = &lt;function generate_junit.&lt;locals&gt;._generate_junit at 0x7fb15323fa60&gt;

    def test_test_analytics_regular_comment_with_error(
        dbsession,
        mocker,
        mock_storage,
        celery_app,
        mock_repo_provider_service,
        mock_pull_request_information,
        generate_junit,
    ):
        mocker.patch.object(TAProcessorTask, "app", celery_app)
        mocker.patch.object(TAFinisherTask, "app", celery_app)
    
        commit = CommitFactory.create()
    
        wrong_xml = """&lt;?xml version="1.0" encoding="utf-8"?&gt;
    &lt;testsuites&gt;
        &lt;testsuite&gt;
            &lt;testcase time="0.001"&gt;
                &lt;failure message="hello world"/&gt;
            &lt;/testcase&gt;
        &lt;/testsuite&gt;
    &lt;/testsuites&gt;
    """
    
        upload = generate_junit(raw=wrong_xml, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        first_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert first_result is False
    
        testruns = [
            {
                "name": "test_divide",
                "outcome": "fail",
                "duration_seconds": 0.001,
                "failure_message": "hello world",
            },
        ]
    
        upload = generate_junit(testruns, commit=commit)
        argument = {"url": upload.storage_path, "upload_id": upload.id_}
        second_result = TAProcessorTask().run_impl(
            dbsession,
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
            argument=argument,
        )
        assert second_result is True
    
        result = TAFinisherTask().run_impl(
            dbsession,
            chord_result=[first_result, second_result],
            repoid=upload.report.commit.repoid,
            commitid=upload.report.commit.commitid,
            commit_yaml={"codecov": {"max_report_age": False}},
        )
    
        assert result["notify_attempted"] is True
        assert result["notify_succeeded"] is True
        assert result["queue_notify"] is False
    
        short_form_service_name = services_short_dict.get(
            upload.report.commit.repository.owner.service
        )
    
        mock_repo_provider_service.edit_comment.assert_called_once()
&gt;       mock_repo_provider_service.edit_comment.assert_called_once_with(
            mock_pull_request_information.database_pull.pullid,
            mock_pull_request_information.database_pull.commentid,
            f"""### :x: Unsupported file format
    
    &gt; Upload processing failed due to unsupported file format. Please review the parser error message:
    &gt; `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`
    &gt; For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).
    
    ---
    ### :x: 1 Tests Failed:
    | Tests completed | Failed | Passed | Skipped |
    |---|---|---|---|
    | 1 | 1 | 0 | 0 |
    &lt;details&gt;&lt;summary&gt;View the top 1 failed tests by shortest run time&lt;/summary&gt;
    
    &gt;
    &gt; ```python
    &gt; tests.test_parsers.TestParsers test_divide
    &gt; ```
    &gt;
    &gt; &lt;details&gt;&lt;summary&gt;Stack Traces | 0.001s run time&lt;/summary&gt;
    &gt;
    &gt; &gt;
    &gt; &gt; ```python
    &gt; &gt; hello world
    &gt; &gt; ```
    &gt;
    &gt; &lt;/details&gt;
    
    &lt;/details&gt;
    
    To view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov.io/{short_form_service_name}/{upload.report.commit.repository.owner.username}/{upload.report.commit.repository.name}/tests/{upload.report.commit.branch})
    :loudspeaker:  Thoughts on this report? [Let us know!](https://github.com/codecov/feedback/issues/304)""",
        )
E       AssertionError: expected call not found.
E       Expected: edit_comment(&lt;AsyncMock name='mock.database_pull.pullid' id='140400427567152'&gt;, &lt;AsyncMock name='mock.database_pull.commentid' id='140400142717616'&gt;, '### :x: Unsupported file format\n\n&gt; Upload processing failed due to unsupported file format. Please review the parser error message:\n&gt; `Error parsing JUnit XML in hello_world.junit.xml at 4:32: ParserError: No name found`\n&gt; For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n&lt;details&gt;&lt;summary&gt;View the top 1 failed tests by shortest run time&lt;/summary&gt;\n\n&gt; \n&gt; ```python\n&gt; tests.test_parsers.TestParsers test_divide\n&gt; ```\n&gt; \n&gt; &lt;details&gt;&lt;summary&gt;Stack Traces | 0.001s run time&lt;/summary&gt;\n&gt; \n&gt; &gt; \n&gt; &gt; ```python\n&gt; &gt; hello world\n&gt; &gt; ```\n&gt; \n&gt; &lt;/details&gt;\n\n&lt;/details&gt;\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov.io/bb/anna17/real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github.com/codecov/feedback/issues/304)')
E         Actual: edit_comment(&lt;AsyncMock name='mock.database_pull.pullid' id='140400427567152'&gt;, &lt;AsyncMock name='mock.database_pull.commentid' id='140400142717616'&gt;, '### :x: Unsupported file format\n\n&gt; Upload processing failed due to unsupported file format. Please review the parser error message:\n&gt; `Error parsing JUnit XML at 4:32: ParserError: No name found`\n&gt; For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n&lt;details&gt;&lt;summary&gt;View the top 1 failed tests by shortest run time&lt;/summary&gt;\n\n&gt; \n&gt; ```python\n&gt; tests.test_parsers.TestParsers test_divide\n&gt; ```\n&gt; \n&gt; &lt;details&gt;&lt;summary&gt;Stack Traces | 0.001s run time&lt;/summary&gt;\n&gt; \n&gt; &gt; \n&gt; &gt; ```python\n&gt; &gt; hello world\n&gt; &gt; ```\n&gt; \n&gt; &lt;/details&gt;\n\n&lt;/details&gt;\n\nTo view more test analytics, go to the [Test Analytics Dashboard](https://app.codecov.io/bb/anna17/real-agent-young/tests/main)\n:loudspeaker:  Thoughts on this report? [Let us know!](https://github.com/codecov/feedback/issues/304)')
E       
E       pytest introspection follows:
E       
E       Args:
E       assert (&lt;AsyncMock n.../issues/304)') == (&lt;AsyncMock n.../issues/304)')
E         
E         At index 2 diff: '### :x: Unsupported file format\n\n&gt; Upload processing failed due to unsupported file format. Please review the parser error message:\n&gt; `Error parsing JUnit XML at 4:32: ParserError: No name found`\n&gt; For more help, visit our [troubleshooting guide](https://docs.codecov.com/docs/test-analytics#troubleshooting).\n\n---\n### :x: 1 Tests Failed:\n| Tests completed | Failed | Passed | Skipped |\n|---|---|---|---|\n| 1 | 1 | 0 | 0 |\n&lt;details&gt;&lt;summary&gt;View the top 1 failed tests by shortest run time&lt;/summary&gt;\n\n&gt; \n&gt; ```python\n&gt; tests.test_parsers.TestPa...
E         
E         ...Full output truncated (2 lines hidden), use '-vv' to show

tasks/tests/unit/test_ta_finisher_task.py:478: AssertionError

📣 Thoughts on this report? Let Codecov know! | Powered by Codecov

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant