# Path: hotness/domain/package.py
# class Package:
#     """
#     Internal representation of package object.
# 
#     Attributes:
#         name (str): Name of the package
#         version (str): Latest version of the package
#         distro (str): Distribution assigned
#     """
# 
#     def __init__(self, name: str, version: str, distro: str) -> None:
#         """
#         Class constructor
#         """
#         self.name = name
#         self.version = version
#         self.distro = distro
# 
#     def to_dict(self) -> dict:
#         """
#         Convert object to dictionary.
# 
#         Return:
#             Dictionary created from package object.
#         """
#         return {"name": self.name, "version": self.version, "distro": self.distro}
# 
#     @classmethod
#     def from_dict(cls, package_dict: dict) -> object:
#         """
#         Convert dictionary to object.
# 
#         Params:
#             package_dict: Dictionary to create package from.
# 
#         Return:
#             Package object.
#         """
#         package = Package(
#             name=package_dict["name"],
#             version=package_dict["version"],
#             distro=package_dict["distro"],
#         )
#         return package
# 
#     def __eq__(self, other: object) -> bool:
#         """
#         Compare method for package object.
# 
#         Params:
#             other: object to compare with
# 
#         Return:
#             Compare result.
#         """
#         return self.to_dict() == other.to_dict()  # type: ignore
# 
# Path: hotness/exceptions/patcher_exception.py
# class PatcherException(BaseHotnessException):
#     """
#     Class representing patcher exception.
#     This exception is raised by patcher
#     when it encounters error.
# 
#     Attributes:
#         message: Error message.
#     """
# 
#     def __init__(self, message: str) -> None:
#         """
#         Class constructor.
#         """
#         self.message = message
#         super(PatcherException, self).__init__(self.message)
# 
# Path: hotness/patchers/bugzilla.py
# class Bugzilla(Patcher):
#     """
#     This class is a wrapper for https://bugzilla.redhat.com/
#     It submit patches to Bugzilla.
# 
#     Attributes:
#         bugzilla (bugzilla.Bugzilla): Bugzilla session
#     """
# 
#     def __init__(
#         self,
#         server_url: str,
#         api_key: str,
#     ) -> None:
#         """
#         Class constructor.
# 
#         It initializes bugzilla session using the provided credentials.
#         If the `api_key` is not provided it raises an `PatcherException`.
# 
#         Params:
#             server_url: URL of the bugzilla server
#             api_key: API key to use for authentication
# 
#         Raises:
#             PatcherException: When the bugzilla session can't be established
#         """
#         super(Bugzilla, self).__init__()
#         if api_key:
#             self.bugzilla = bugzilla.Bugzilla(
#                 url=server_url, api_key=api_key, cookiefile=None, tokenfile=None
#             )
#         else:
#             raise PatcherException("Authentication info not provided! Provide API key.")
#         self.bugzilla.bug_autorefresh = True
# 
#     def submit_patch(self, package: Package, patch: str, opts: dict) -> dict:
#         """
#         This method is inherited from `hotness.patchers.Patcher`.
# 
#         It attaches file to existing ticket in bugzilla.
# 
#         Params:
#             package: Package to create notification for
#             patch: Patch to attach, it needs to be converted to file first
#             opts: Additional options for bugzilla. Example:
#                 {
#                     "bz_id": 100, # Bugzilla ticket id, if provided the
#                                   # new message will be added as new comment to this ticket
#                     "patch_filename": "patch" # Name of the file, that should be attached
#                 }
# 
#         Returns:
#             Dictionary containing ticket bugzilla id
#             Example:
#             {
#                 "bz_id": 100
#             }
#         """
#         output = {}
#         bug_id = opts.get("bz_id", 0)
#         filename = opts.get("patch_filename", "")
#         if bug_id == 0 or not filename:
#             raise PatcherException(
#                 "Additional parameters are missing! "
#                 "Please provide `bz_id` and `patch_filename`."
#             )
# 
#         # Write file to temporary directory
#         # and stop bandit from complaining about a hardcoded temporary directory
#         # because it's needed for OpenShift
#         with TemporaryDirectory(prefix="thn-", dir="/var/tmp") as tmp:  # nosec
#             filepath = os.path.join(tmp, filename)
#             with open(filepath, "w") as f:
#                 f.write(patch)
# 
#             _logger.debug("Attaching file to bug %r" % bug_id)
#             description = "Update to {} (#{})".format(package.version, bug_id)
#             self.bugzilla.attachfile(bug_id, filepath, description, is_patch=True)
#             _logger.info("Attached file to bug: %r" % bug_id)
# 
#         output["bz_id"] = bug_id
#         return output


import os
import pytest
from unittest import mock
from hotness.domain import Package
from hotness.exceptions import PatcherException
from hotness.patchers import Bugzilla
        Assert that Bugzilla patcher object raises exception during initialization
        if authentication info is not provided.
        """
        server_url = "https://example.com/"
        api_key = ""

        with pytest.raises(PatcherException) as exc:
            Bugzilla(
                server_url,
                api_key,
            )

        assert exc.value.message == (
            "Authentication info not provided! Provide API key."
        )


class TestBugzillaSubmitPatch:
    """
    Test class for `hotness.patchers.Bugzilla.submit_patch` method.
    """

    def setup(self):
        """
        Create patcher instance for tests.
        """
        server_url = "https://example.com/"
        api_key = "some API key"
        with mock.patch("hotness.patchers.bugzilla.bugzilla") as mock_bugzilla:
            bugzilla_session = mock.Mock()

# Path: hotness/domain/package.py
# class Package:
#     """
#     Internal representation of package object.
# 
#     Attributes:
#         name (str): Name of the package
#         version (str): Latest version of the package
#         distro (str): Distribution assigned
#     """
# 
#     def __init__(self, name: str, version: str, distro: str) -> None:
#         """
#         Class constructor
#         """
#         self.name = name
#         self.version = version
#         self.distro = distro
# 
#     def to_dict(self) -> dict:
#         """
#         Convert object to dictionary.
# 
#         Return:
#             Dictionary created from package object.
#         """
#         return {"name": self.name, "version": self.version, "distro": self.distro}
# 
#     @classmethod
#     def from_dict(cls, package_dict: dict) -> object:
#         """
#         Convert dictionary to object.
# 
#         Params:
#             package_dict: Dictionary to create package from.
# 
#         Return:
#             Package object.
#         """
#         package = Package(
#             name=package_dict["name"],
#             version=package_dict["version"],
#             distro=package_dict["distro"],
#         )
#         return package
# 
#     def __eq__(self, other: object) -> bool:
#         """
#         Compare method for package object.
# 
#         Params:
#             other: object to compare with
# 
#         Return:
#             Compare result.
#         """
#         return self.to_dict() == other.to_dict()  # type: ignore
# 
# Path: hotness/exceptions/patcher_exception.py
# class PatcherException(BaseHotnessException):
#     """
#     Class representing patcher exception.
#     This exception is raised by patcher
#     when it encounters error.
# 
#     Attributes:
#         message: Error message.
#     """
# 
#     def __init__(self, message: str) -> None:
#         """
#         Class constructor.
#         """
#         self.message = message
#         super(PatcherException, self).__init__(self.message)
# 
# Path: hotness/patchers/bugzilla.py
# class Bugzilla(Patcher):
#     """
#     This class is a wrapper for https://bugzilla.redhat.com/
#     It submit patches to Bugzilla.
# 
#     Attributes:
#         bugzilla (bugzilla.Bugzilla): Bugzilla session
#     """
# 
#     def __init__(
#         self,
#         server_url: str,
#         api_key: str,
#     ) -> None:
#         """
#         Class constructor.
# 
#         It initializes bugzilla session using the provided credentials.
#         If the `api_key` is not provided it raises an `PatcherException`.
# 
#         Params:
#             server_url: URL of the bugzilla server
#             api_key: API key to use for authentication
# 
#         Raises:
#             PatcherException: When the bugzilla session can't be established
#         """
#         super(Bugzilla, self).__init__()
#         if api_key:
#             self.bugzilla = bugzilla.Bugzilla(
#                 url=server_url, api_key=api_key, cookiefile=None, tokenfile=None
#             )
#         else:
#             raise PatcherException("Authentication info not provided! Provide API key.")
#         self.bugzilla.bug_autorefresh = True
# 
#     def submit_patch(self, package: Package, patch: str, opts: dict) -> dict:
#         """
#         This method is inherited from `hotness.patchers.Patcher`.
# 
#         It attaches file to existing ticket in bugzilla.
# 
#         Params:
#             package: Package to create notification for
#             patch: Patch to attach, it needs to be converted to file first
#             opts: Additional options for bugzilla. Example:
#                 {
#                     "bz_id": 100, # Bugzilla ticket id, if provided the
#                                   # new message will be added as new comment to this ticket
#                     "patch_filename": "patch" # Name of the file, that should be attached
#                 }
# 
#         Returns:
#             Dictionary containing ticket bugzilla id
#             Example:
#             {
#                 "bz_id": 100
#             }
#         """
#         output = {}
#         bug_id = opts.get("bz_id", 0)
#         filename = opts.get("patch_filename", "")
#         if bug_id == 0 or not filename:
#             raise PatcherException(
#                 "Additional parameters are missing! "
#                 "Please provide `bz_id` and `patch_filename`."
#             )
# 
#         # Write file to temporary directory
#         # and stop bandit from complaining about a hardcoded temporary directory
#         # because it's needed for OpenShift
#         with TemporaryDirectory(prefix="thn-", dir="/var/tmp") as tmp:  # nosec
#             filepath = os.path.join(tmp, filename)
#             with open(filepath, "w") as f:
#                 f.write(patch)
# 
#             _logger.debug("Attaching file to bug %r" % bug_id)
#             description = "Update to {} (#{})".format(package.version, bug_id)
#             self.bugzilla.attachfile(bug_id, filepath, description, is_patch=True)
#             _logger.info("Attached file to bug: %r" % bug_id)
# 
#         output["bz_id"] = bug_id
#         return output


# Path: tests/patchers/test_bugzilla.py
import os
import pytest
from unittest import mock
from hotness.domain import Package
from hotness.exceptions import PatcherException
from hotness.patchers import Bugzilla

        Assert that Bugzilla patcher object raises exception during initialization
        if authentication info is not provided.
        """
        server_url = "https://example.com/"
        api_key = ""

        with pytest.raises(PatcherException) as exc:
            Bugzilla(
                server_url,
                api_key,
            )

        assert exc.value.message == (
            "Authentication info not provided! Provide API key."
        )


class TestBugzillaSubmitPatch:
    """
    Test class for `hotness.patchers.Bugzilla.submit_patch` method.
    """

    def setup(self):
        """
        Create patcher instance for tests.
        """
        server_url = "https://example.com/"
        api_key = "some API key"
        with mock.patch("hotness.patchers.bugzilla.bugzilla") as mock_bugzilla:
            bugzilla_session = mock.Mock()

            mock_bugzilla.Bugzilla.return_value = bugzilla_session