Repository: packit/packit-service
Issue: AttributeError: 'JobConfig' object has no attribute 'job'

Sentry Issue: [RED-HAT-0P-2B0](https://sentry.io/organizations/red-hat-0p/issues/1555902127/?referrer=github_integration)

```
AttributeError: 'JobConfig' object has no attribute 'job'
  File "packit_service/worker/tasks.py", line 42, in process_message
    return SteveJobs().process_message(event=event, topic=topic)
  File "packit_service/worker/jobs.py", line 292, in process_message
    jobs_results = self.process_jobs(event_object)
  File "packit_service/worker/jobs.py", line 131, in process_jobs
    if handler.pre_check():
  File "packit_service/worker/handlers/github_handlers.py", line 387, in pre_check
    super().pre_check()
  File "packit_service/worker/handlers/github_handlers.py", line 304, in pre_check
    if self.job_config.job == JobType.tests and any(
```

Changed files:
tests/integration/test_handler.py, packit_service/worker/handlers/github_handlers.py, packit_service/trigger_mapping.py, tests/unit/test_build_helper.py, tests/conftest.py, tests/unit/test_copr_build.py, packit_service/worker/build/build_helper.py

diff --git a/packit_service/trigger_mapping.py b/packit_service/trigger_mapping.py
index 79261895..e9590084 100644
--- a/packit_service/trigger_mapping.py
+++ b/packit_service/trigger_mapping.py
@@ -22,7 +22,7 @@
 
 from typing import Dict, Optional
 
-from packit.config import JobConfigTriggerType, JobConfig
+from packit.config import JobConfigTriggerType, JobConfig, JobType
 
 from packit_service.service.events import TheJobTriggerType
 
@@ -49,3 +49,10 @@ def is_trigger_matching_job_config(
     """
     config_trigger = JOB_TRIGGER_TO_CONFIG_MAPPING.get(trigger)
     return bool(config_trigger and job_config.trigger == config_trigger)
+
+
+def are_job_types_same(first: JobType, second: JobType) -> bool:
+    """
+    We need to treat `build` alias in a special way.
+    """
+    return first == second or {first, second} == {JobType.build, JobType.copr_build}
diff --git a/packit_service/worker/build/build_helper.py b/packit_service/worker/build/build_helper.py
index edf312d5..f1759a4c 100644
--- a/packit_service/worker/build/build_helper.py
+++ b/packit_service/worker/build/build_helper.py
@@ -36,7 +36,10 @@ from packit_service.service.events import (
     PushGitHubEvent,
     ReleaseEvent,
 )
-from packit_service.trigger_mapping import is_trigger_matching_job_config
+from packit_service.trigger_mapping import (
+    is_trigger_matching_job_config,
+    are_job_types_same,
+)
 from packit_service.worker.reporting import StatusReporter
 
 logger = logging.getLogger(__name__)
@@ -86,8 +89,12 @@ class BaseBuildJobHelper:
         self._build_check_names: Optional[List[str]] = None
 
         # lazy properties, current job by default
-        self._job_build = job if job and job.job == self.job_type_build else None
-        self._job_tests = job if job and job.job == self.job_type_test else None
+        self._job_build = (
+            job if job and are_job_types_same(job.type, self.job_type_build) else None
+        )
+        self._job_tests = (
+            job if job and are_job_types_same(job.type, self.job_type_test) else None
+        )
 
     @property
     def local_project(self) -> LocalProject:
@@ -165,7 +172,9 @@ class BaseBuildJobHelper:
 
         if not self._job_build:
             for job in self.package_config.jobs:
-                if job.type == self.job_type_build and is_trigger_matching_job_config(
+                if are_job_types_same(
+                    job.type, self.job_type_build
+                ) and is_trigger_matching_job_config(
                     trigger=self.event.trigger, job_config=job
                 ):
                     self._job_build = job
@@ -183,7 +192,9 @@ class BaseBuildJobHelper:
 
         if not self._job_tests:
             for job in self.package_config.jobs:
-                if job.type == self.job_type_test and is_trigger_matching_job_config(
+                if are_job_types_same(
+                    job.type, self.job_type_test
+                ) and is_trigger_matching_job_config(
                     trigger=self.event.trigger, job_config=job
                 ):
                     self._job_tests = job
diff --git a/packit_service/worker/handlers/github_handlers.py b/packit_service/worker/handlers/github_handlers.py
index 805d45db..56b4692b 100644
--- a/packit_service/worker/handlers/github_handlers.py
+++ b/packit_service/worker/handlers/github_handlers.py
@@ -38,6 +38,7 @@ from packit.config.aliases import get_branches
 from packit.exceptions import PackitException
 from packit.local_project import LocalProject
 
+from packit_service import sentry_integration
 from packit_service.config import ServiceConfig, GithubPackageConfigGetter
 from packit_service.constants import PERMISSIONS_ERROR_WRITE_OR_ADMIN
 from packit_service.service.events import (
@@ -51,7 +52,6 @@ from packit_service.service.events import (
     TheJobTriggerType,
 )
 from packit_service.service.models import Installation
-from packit_service import sentry_integration
 from packit_service.worker.build import CoprBuildJobHelper
 from packit_service.worker.handlers import (
     CommentActionHandler,
@@ -299,9 +299,9 @@ class AbstractGithubCoprBuildHandler(AbstractGithubJobHandler):
     def pre_check(self) -> bool:
         is_copr_build: Callable[
             [JobConfig], bool
-        ] = lambda job: job.job == JobType.copr_build
+        ] = lambda job: job.type == JobType.copr_build
 
-        if self.job_config.job == JobType.tests and any(
+        if self.job_config.type == JobType.tests and any(
             filter(is_copr_build, self.package_config.jobs)
         ):
             logger.info(
diff --git a/tests/conftest.py b/tests/conftest.py
index cd9e3664..4120abff 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -19,6 +19,7 @@
 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
+import json
 import os
 from pathlib import Path
 
@@ -33,8 +34,14 @@ from packit.local_project import LocalProject
 from packit_service.config import ServiceConfig
 from packit_service.constants import SANDCASTLE_WORK_DIR
 from packit_service.models import GitProject, PullRequest, CoprBuild
+from packit_service.service.events import (
+    PullRequestEvent,
+    PushGitHubEvent,
+    ReleaseEvent,
+)
+from packit_service.worker.parser import Parser
 from packit_service.worker.whitelist import Whitelist
-from tests.spellbook import SAVED_HTTPD_REQS
+from tests.spellbook import SAVED_HTTPD_REQS, DATA_DIR
 
 
 @pytest.fixture()
@@ -161,3 +168,36 @@ def copr_build():
     c.pr = pr
     c.commit_sha = "0011223344"
     return c
+
+
+@pytest.fixture()
+def pull_request_webhhok() -> dict:
+    with open(DATA_DIR / "webhooks" / "github_pr_event.json", "r") as outfile:
+        return json.load(outfile)
+
+
+@pytest.fixture()
+def branch_push_webhook() -> dict:
+    with open(DATA_DIR / "webhooks" / "github_push_branch.json", "r") as outfile:
+        return json.load(outfile)
+
+
+@pytest.fixture()
+def release_webhook() -> dict:
+    with open(DATA_DIR / "webhooks" / "github_release_event.json", "r") as outfile:
+        return json.load(outfile)
+
+
+@pytest.fixture()
+def branch_push_event(branch_push_webhook) -> PushGitHubEvent:
+    return Parser.parse_push_event(branch_push_webhook)
+
+
+@pytest.fixture()
+def release_event(release_webhook) -> ReleaseEvent:
+    return Parser.parse_release_event(release_webhook)
+
+
+@pytest.fixture()
+def pull_request_event(pull_request_webhhok) -> PullRequestEvent:
+    return Parser.parse_pr_event(pull_request_webhhok)
diff --git a/tests/integration/test_handler.py b/tests/integration/test_handler.py
index f0a92efe..60e0440c 100644
--- a/tests/integration/test_handler.py
+++ b/tests/integration/test_handler.py
@@ -23,11 +23,15 @@ import os
 from pathlib import Path
 
 import pytest
-from packit.config import JobConfig, JobType, JobConfigTriggerType
+from flexmock import flexmock
+from packit.config import JobConfig, JobType, JobConfigTriggerType, PackageConfig
 
 from packit_service.config import ServiceConfig
 from packit_service.service.events import Event, TheJobTriggerType
 from packit_service.worker.handlers import JobHandler
+from packit_service.worker.handlers.github_handlers import (
+    AbstractGithubCoprBuildHandler,
+)
 
 
 @pytest.fixture()
@@ -60,3 +64,63 @@ def test_handler_cleanup(tmpdir, trick_p_s_with_k8s):
     j._clean_workplace()
 
     assert len(list(t.iterdir())) == 0
+
+
+def test_precheck(pull_request_event):
+    flexmock(AbstractGithubCoprBuildHandler).should_receive(
+        "get_package_config_from_repo"
+    ).and_return(
+        PackageConfig(
+            jobs=[
+                JobConfig(
+                    type=JobType.copr_build,
+                    trigger=JobConfigTriggerType.pull_request,
+                    metadata={},
+                ),
+                JobConfig(
+                    type=JobType.tests,
+                    trigger=JobConfigTriggerType.pull_request,
+                    metadata={},
+                ),
+            ]
+        )
+    )
+    copr_build_handler = AbstractGithubCoprBuildHandler(
+        config=flexmock(),
+        job_config=JobConfig(
+            type=JobType.copr_build,
+            trigger=JobConfigTriggerType.pull_request,
+            metadata={},
+        ),
+        event=pull_request_event,
+    )
+    assert copr_build_handler.pre_check()
+
+
+def test_precheck_skip_tests_when_build_defined(pull_request_event):
+    flexmock(AbstractGithubCoprBuildHandler).should_receive(
+        "get_package_config_from_repo"
+    ).and_return(
+        PackageConfig(
+            jobs=[
+                JobConfig(
+                    type=JobType.copr_build,
+                    trigger=JobConfigTriggerType.pull_request,
+                    metadata={},
+                ),
+                JobConfig(
+                    type=JobType.tests,
+                    trigger=JobConfigTriggerType.pull_request,
+                    metadata={},
+                ),
+            ]
+        )
+    )
+    copr_build_handler = AbstractGithubCoprBuildHandler(
+        config=flexmock(),
+        job_config=JobConfig(
+            type=JobType.tests, trigger=JobConfigTriggerType.pull_request, metadata={},
+        ),
+        event=pull_request_event,
+    )
+    assert not copr_build_handler.pre_check()
diff --git a/tests/unit/test_build_helper.py b/tests/unit/test_build_helper.py
index 7e449ea4..52c4cfde 100644
--- a/tests/unit/test_build_helper.py
+++ b/tests/unit/test_build_helper.py
@@ -226,6 +226,24 @@ from packit_service.worker.build.copr_build import CoprBuildJobHelper
             {"fedora-29-x86_64"},
             id="build_without_target&test_with_one_str_target",
         ),
+        pytest.param(
+            [
+                JobConfig(
+                    type=JobType.build,
+                    trigger=JobConfigTriggerType.pull_request,
+                    metadata={},
+                ),
+                JobConfig(
+                    type=JobType.tests,
+                    trigger=JobConfigTriggerType.pull_request,
+                    metadata={"targets": "fedora-29"},
+                ),
+            ],
+            TheJobTriggerType.pull_request,
+            {"fedora-29-x86_64"},
+            {"fedora-29-x86_64"},
+            id="build_with_mixed_build_alias",
+        ),
     ],
 )
 def test_targets(jobs, trigger, build_targets, test_targets):
diff --git a/tests/unit/test_copr_build.py b/tests/unit/test_copr_build.py
index b05944a8..b486d1cb 100644
--- a/tests/unit/test_copr_build.py
+++ b/tests/unit/test_copr_build.py
@@ -1,4 +1,4 @@
-import json
+from typing import Union
 
 from flexmock import flexmock
 from ogr.abstract import GitProject, GitService, CommitStatus
@@ -6,37 +6,19 @@ from packit.api import PackitAPI
 from packit.config import PackageConfig, JobConfig, JobType, JobConfigTriggerType
 from packit.exceptions import FailedCreateSRPM
 
+from packit_service import sentry_integration
 from packit_service.config import ServiceConfig
 from packit_service.models import CoprBuild, SRPMBuild
+from packit_service.service.events import (
+    PullRequestEvent,
+    PullRequestCommentEvent,
+    CoprBuildEvent,
+    PushGitHubEvent,
+    ReleaseEvent,
+)
 from packit_service.service.models import CoprBuild as RedisCoprBuild
-from packit_service import sentry_integration
 from packit_service.worker.build.copr_build import CoprBuildJobHelper
-from packit_service.worker.parser import Parser
 from packit_service.worker.reporting import StatusReporter
-from tests.spellbook import DATA_DIR
-
-
-def pull_request_webhhok():
-    with open(DATA_DIR / "webhooks" / "github_pr_event.json", "r") as outfile:
-        return json.load(outfile)
-
-
-def branch_push_webhook():
-    with open(DATA_DIR / "webhooks" / "github_push_branch.json", "r") as outfile:
-        return json.load(outfile)
-
-
-def release_webhook():
-    with open(DATA_DIR / "webhooks" / "github_release_event.json", "r") as outfile:
-        return json.load(outfile)
-
-
-def branch_push_event():
-    return Parser.parse_pr_event(branch_push_webhook())
-
-
-def release_event():
-    return Parser.parse_pr_event(release_webhook())
 
 
 class FakeCoprBuildModel:
@@ -49,7 +31,18 @@ class FakeCoprBuildModel:
         pass
 
 
-def build_helper(metadata=None, trigger=None, jobs=None, event=None):
+def build_helper(
+    event: Union[
+        PullRequestEvent,
+        PullRequestCommentEvent,
+        CoprBuildEvent,
+        PushGitHubEvent,
+        ReleaseEvent,
+    ],
+    metadata=None,
+    trigger=None,
+    jobs=None,
+):
     if not metadata:
         metadata = {
             "owner": "nobody",
@@ -69,7 +62,6 @@ def build_helper(metadata=None, trigger=None, jobs=None, event=None):
         )
     )
     pkg_conf = PackageConfig(jobs=jobs, downstream_package_name="dummy")
-    event = event or Parser.parse_pr_event(pull_request_webhhok())
     handler = CoprBuildJobHelper(
         config=ServiceConfig(),
         package_config=pkg_conf,
@@ -80,9 +72,11 @@ def build_helper(metadata=None, trigger=None, jobs=None, event=None):
     return handler
 
 
-def test_copr_build_check_names():
-    metadata = {"owner": "nobody", "targets": ["bright-future-x86_64"]}
-    helper = build_helper(metadata)
+def test_copr_build_check_names(pull_request_event):
+    helper = build_helper(
+        event=pull_request_event,
+        metadata={"owner": "nobody", "targets": ["bright-future-x86_64"]},
+    )
     flexmock(StatusReporter).should_receive("set_status").with_args(
         state=CommitStatus.pending,
         description="Building SRPM ...",
@@ -104,7 +98,7 @@ def test_copr_build_check_names():
     assert helper.run_copr_build()["success"]
 
 
-def test_copr_build_success_set_test_check():
+def test_copr_build_success_set_test_check(pull_request_event):
     # status is set for each build-target (4x):
     #  - Building SRPM ...
     #  - Building RPM ...
@@ -114,7 +108,7 @@ def test_copr_build_success_set_test_check():
     test_job = JobConfig(
         type=JobType.tests, trigger=JobConfigTriggerType.pull_request, metadata={}
     )
-    helper = build_helper(jobs=[test_job])
+    helper = build_helper(jobs=[test_job], event=pull_request_event)
     flexmock(GitProject).should_receive("set_commit_status").and_return().times(16)
     flexmock(RedisCoprBuild).should_receive("create").and_return(FakeCoprBuildModel())
     flexmock(SRPMBuild).should_receive("create").and_return(SRPMBuild())
@@ -123,16 +117,25 @@ def test_copr_build_success_set_test_check():
     assert helper.run_copr_build()["success"]
 
 
-def test_copr_build_for_branch():
+def test_copr_build_for_branch(branch_push_event):
     # status is set for each build-target (4x):
     #  - Building SRPM ...
     #  - Building RPM ...
     branch_build_job = JobConfig(
         type=JobType.build,
         trigger=JobConfigTriggerType.commit,
-        metadata={"branch": "build-branch"},
+        metadata={
+            "branch": "build-branch",
+            "owner": "nobody",
+            "targets": [
+                "fedora-29-x86_64",
+                "fedora-30-x86_64",
+                "fedora-31-x86_64",
+                "fedora-rawhide-x86_64",
+            ],
+        },
     )
-    helper = build_helper(jobs=[branch_build_job], event=branch_push_event())
+    helper = build_helper(jobs=[branch_build_job], event=branch_push_event)
     flexmock(GitProject).should_receive("set_commit_status").and_return().times(8)
     flexmock(RedisCoprBuild).should_receive("create").and_return(FakeCoprBuildModel())
     flexmock(SRPMBuild).should_receive("create").and_return(SRPMBuild())
@@ -141,14 +144,25 @@ def test_copr_build_for_branch():
     assert helper.run_copr_build()["success"]
 
 
-def test_copr_build_for_release():
+def test_copr_build_for_release(release_event):
     # status is set for each build-target (4x):
     #  - Building SRPM ...
     #  - Building RPM ...
     branch_build_job = JobConfig(
-        type=JobType.build, trigger=JobConfigTriggerType.release, metadata={},
+        type=JobType.build,
+        trigger=JobConfigTriggerType.release,
+        metadata={
+            "branch": "build-branch",
+            "owner": "nobody",
+            "targets": [
+                "fedora-29-x86_64",
+                "fedora-30-x86_64",
+                "fedora-31-x86_64",
+                "fedora-rawhide-x86_64",
+            ],
+        },
     )
-    helper = build_helper(jobs=[branch_build_job], event=release_event())
+    helper = build_helper(jobs=[branch_build_job], event=release_event)
     flexmock(GitProject).should_receive("set_commit_status").and_return().times(8)
     flexmock(RedisCoprBuild).should_receive("create").and_return(FakeCoprBuildModel())
     flexmock(SRPMBuild).should_receive("create").and_return(SRPMBuild())
@@ -157,11 +171,11 @@ def test_copr_build_for_release():
     assert helper.run_copr_build()["success"]
 
 
-def test_copr_build_success():
+def test_copr_build_success(pull_request_event):
     # status is set for each build-target (4x):
     #  - Building SRPM ...
     #  - Building RPM ...
-    helper = build_helper()
+    helper = build_helper(event=pull_request_event)
     flexmock(GitProject).should_receive("set_commit_status").and_return().times(8)
     flexmock(RedisCoprBuild).should_receive("create").and_return(FakeCoprBuildModel())
     flexmock(SRPMBuild).should_receive("create").and_return(SRPMBuild())
@@ -170,11 +184,11 @@ def test_copr_build_success():
     assert helper.run_copr_build()["success"]
 
 
-def test_copr_build_fails_in_packit():
+def test_copr_build_fails_in_packit(pull_request_event):
     # status is set for each build-target (4x):
     #  - Building SRPM ...
     #  - Build failed, check latest comment for details.
-    helper = build_helper()
+    helper = build_helper(event=pull_request_event)
     templ = "packit-stg/rpm-build-fedora-{ver}-x86_64"
     for v in ["29", "30", "31", "rawhide"]:
         flexmock(GitProject).should_receive("set_commit_status").with_args(
@@ -204,11 +218,11 @@ def test_copr_build_fails_in_packit():
     assert not helper.run_copr_build()["success"]
 
 
-def test_copr_build_no_targets():
+def test_copr_build_no_targets(pull_request_event):
     # status is set for each build-target (fedora-stable => 2x):
     #  - Building SRPM ...
     #  - Building RPM ...
-    helper = build_helper(metadata={"owner": "nobody"})
+    helper = build_helper(event=pull_request_event, metadata={"owner": "nobody"})
     flexmock(GitProject).should_receive("set_commit_status").and_return().times(4)
     flexmock(RedisCoprBuild).should_receive("create").and_return(FakeCoprBuildModel())
     flexmock(SRPMBuild).should_receive("create").and_return(SRPMBuild())