Source code for bugzoo.client.bug
from typing import Iterator
import logging
from .api import APIClient
from ..core.bug import Bug
from ..core.coverage import TestSuiteCoverage
logger = logging.getLogger(__name__) # type: logging.Logger
logger.setLevel(logging.DEBUG)
__all__ = ['BugManager']
[docs]class BugManager(object):
"""
Provides access to the historical bugs that are registered with the
server. Can be used to install, download, and uninstall registered bugs,
or to dynamically register new bugs with the server.
"""
def __init__(self, api: APIClient) -> None:
self.__api = api
def __contains__(self, name: str) -> bool:
"""Determines whether there is a bug registered under a given name."""
with self.__api.get('bugs/{}'.format(name)) as r:
if r.status_code == 200:
return True
elif r.status_code == 404:
return False
self.__api.handle_erroneous_response(r)
[docs] def __getitem__(self, name: str) -> Bug:
"""Retrieves the bug registered under a given name.
Raises:
KeyError: if no bug is found with the given name.
"""
logger.debug("Fetching information for bug: %s", name)
with self.__api.get('bugs/{}'.format(name)) as r:
if r.status_code == 200:
return Bug.from_dict(r.json())
if r.status_code == 404:
logger.info("Bug not found: %s", name)
raise KeyError("no bug found with given name: {}".format(name))
logger.info("Unexpected API response when retrieving bug: %s", name)
self.__api.handle_erroneous_response(r)
def __delitem__(self, name: str) -> None:
"""Deregisters a bug under a given name.
Raises:
KeyError: if no bug is found with the given name.
"""
with self.__api.delete('bugs/{}'.format(name)) as r:
if r.status_code == 204:
return
if r.status_code == 404:
raise KeyError("no bug found with given name: {}".format(name))
self.__api.handle_erroneous_response(r)
[docs] def __iter__(self) -> Iterator[str]:
"""
Returns an iterator over the names of the bugs registered with
the server.
"""
with self.__api.get('bugs') as r:
if r.status_code == 200:
names = r.json()
assert isinstance(names, list)
assert all(isinstance(n, str) for n in names)
return names.__iter__()
self.__api.handle_erroneous_response(r)
[docs] def is_installed(self, bug: Bug) -> bool:
"""
Determines whether the Docker image for a given bug has been installed
on the server.
"""
with self.__api.get('bugs/{}/installed'.format(bug.name)) as r:
if r.status_code == 200:
answer = r.json()
assert isinstance(answer, bool)
return answer
# TODO bug not registered on server
if r.status_code == 404:
m = "no bug found with given name: {}".format(bug.name)
raise KeyError(m)
self.__api.handle_erroneous_response(r)
[docs] def register(self, bug: Bug) -> None:
"""
Dynamically registers a given bug with the server. Note that the
registration will not persist beyond the lifetime of the server.
(I.e., when the server is closed, the bug will be deregistered.)
Raises:
BugAlreadyExists: if there is already a bug registered on the
server under the same name as this bug.
"""
path = "bugs/{}".format(bug.name)
payload = bug.to_dict()
with self.__api.put(path, json=payload) as r:
if r.status_code != 204:
self.__api.handle_erroneous_response(r)
def coverage(self, bug: Bug) -> TestSuiteCoverage:
logger.info("Fetching coverage information for snapshot: %s",
bug.name)
with self.__api.get('bugs/{}/coverage'.format(bug.name)) as r:
if r.status_code == 200:
jsn = r.json()
coverage = TestSuiteCoverage.from_dict(jsn) # type: ignore
logger.info("Fetched coverage information for snapshot: %s",
bug.name)
return coverage
logger.error("Failed to fetch coverage information for snapshot: %s",
bug.name)
self.__api.handle_erroneous_response(r)
[docs] def uninstall(self, bug: Bug) -> bool:
"""Uninstalls the Docker image associated with a given bug."""
with self.__api.post('bugs/{}/uninstall'.format(bug.name)) as r:
raise NotImplementedError
[docs] def upload(self, bug: Bug) -> bool:
"""
Instructs the server to upload the Docker image associated with a
given bug to DockerHub.
"""
with self.__api.post('bugs/{}/upload'.format(bug.name)) as r:
raise NotImplementedError
[docs] def download(self, bug: Bug) -> bool:
"""
Instructs the server to download the Docker image associated with a
given bug from DockerHub.
"""
with self.__api.post('bugs/{}/download'.format(bug.name)) as r:
raise NotImplementedError
[docs] def build(self, bug: Bug):
"""
Instructs the server to build the Docker image associated with a given
bug.
"""
with self.__api.post('bugs/{}/build'.format(bug.name)) as r:
if r.status_code == 204:
return
if r.status_code == 200:
raise Exception("bug already built: {}".format(bug.name))
# TODO: implement ImageBuildFailed.from_dict
if r.status_code == 400:
raise Exception("build failure")
if r.status_code == 404:
raise KeyError("no bug found with given name: {}".format(bug.name))
self.__api.handle_erroneous_response(r)