Skip to content

Commit

Permalink
tests: updated tests
Browse files Browse the repository at this point in the history
  • Loading branch information
alejandromumo committed Jun 21, 2023
1 parent 5b01170 commit 9826cc0
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 100 deletions.
5 changes: 0 additions & 5 deletions invenio_github/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,11 +493,6 @@ def download_release_file(self):
with session.get(self.release_zipball_url, stream=True) as s:
yield s.raw

@cached_property
def author(self):
"""Extract the author's GitHub username from a release."""
return self.release.get("author", {}).get("login")

@cached_property
def status(self):
"""Get the release status."""
Expand Down
9 changes: 9 additions & 0 deletions invenio_github/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ def __init__(self, repo=None, message=None):
self.repo = repo


class RepositoryNotFoundError(GitHubError):
message = "The repository does not exist."

def __init__(self, repo=None, message=None):
"""Constructor."""
super(RepositoryNotFoundError, self).__init__(message or self.message)
self.repo = repo


class InvalidSenderError(GitHubError):
"""Invalid release sender error."""

Expand Down
25 changes: 17 additions & 8 deletions invenio_github/receivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
ReleaseAlreadyReceivedError,
RepositoryAccessError,
RepositoryDisabledError,
RepositoryNotFoundError,
)

from sqlalchemy.orm.exc import NoResultFound


class GitHubReceiver(Receiver):
"""Handle incoming notification from GitHub on a new release."""
Expand All @@ -59,13 +62,12 @@ def run(self, event):
with db.session.begin_nested():
try:
self._handle_event(event)
except Exception:
# Event failed to be processed and error was not handled yet (response code is still not an error code)
if event.response_code < 400:
pass
# TODO code 418 I'm a teapot
# TODO code 501 Not implemented
event.response_code = 500
except Exception as e:
# Event failed to be processed and error was not handled yet
if not event.response or event.response_code < 400:
event.response = {"status": 500, "message": str(e)}
event.response_code = 500
# Other cases were already handled (e.g. response/response_code were set by the event handler)

def _handle_event(self, event):
"""Handles an incoming github event."""
Expand Down Expand Up @@ -101,7 +103,11 @@ def _create_release(event):
# Create the Release
repo_id = event.payload["repository"]["id"]
repo_name = event.payload["repository"]["name"]
repo = Repository.get(github_id=repo_id, name=repo_name)
try:
repo = Repository.get(repo_id, repo_name)
except NoResultFound:
raise RepositoryNotFoundError(repo_name)

if repo.enabled:
release_object = Release(
release_id=release_id,
Expand Down Expand Up @@ -150,6 +156,9 @@ def _verify_sender(event):
except (RepositoryAccessError, InvalidSenderError) as e:
event.response_code = 403
event.response = dict(message=str(e), status=403)
except RepositoryNotFoundError as e:
event.response_code = 404
event.response = dict(message=str(e), status=404)
except Exception as e:
# deal with it or default
raise e
44 changes: 29 additions & 15 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@

from invenio_github.models import Release, ReleaseStatus, Repository

from .fixtures import TestGithubRelease, github_repo_metadata, github_user_metadata
from .fixtures import (
TestGithubRelease,
github_file_contents,
github_repo_metadata,
github_user_metadata,
)


@pytest.fixture(scope="module")
Expand Down Expand Up @@ -138,7 +143,7 @@ def running_app(app, location, cache, resource_type_v, relation_type_v):
def test_user(app, db, github_remote_app):
"""Creates a test user.
Links the user to a github RemoteAccount.
Links the user to a github RemoteToken.
"""
datastore = app.extensions["security"].datastore
user = datastore.create_user(
Expand Down Expand Up @@ -327,22 +332,31 @@ def github_api(
),
mock_api.session,
)

repo_2.hooks = MagicMock(return_value=[])
repo_2.create_hook = MagicMock(return_value=12345)

def mock_metadata_contents(path, ref):
data = json.dumps(
dict(
upload_type="dataset",
license="mit-license",
creators=[
dict(name="Smith, Joe", affiliation="CERN"),
dict(name="Smith, Sam", affiliation="NASA"),
],
)
)
return MagicMock(decoded=b(data))
file_path = "test.py"

def mock_file_content():
# File contents mocking
owner = "auser"
repo = test_repo_data_two["name"]
ref = ""

# Dummy data to be encoded as the file contents
data = "dummy".encode("ascii")
return github_file_contents(owner, repo, file_path, ref, data)

file_data = mock_file_content()

def mock_file_contents(path, ref=None):
if path == file_path:
# Mock github3.contents.Content with file_data
return MagicMock(decoded=file_data)
return None

repo_2.file_contents = MagicMock(side_effect=mock_metadata_contents)
repo_2.file_contents = MagicMock(side_effect=mock_file_contents)

repo_3 = github3.repos.Repository(
fixtures.github_repo_metadata(
Expand Down
9 changes: 5 additions & 4 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def publish(self):
Does not create a "real" record, as this only used to test the API.
"""
self.release_object.status = ReleaseStatus.PUBLISHED
self.release_object.record_id = "445aaacd-9de1-41ab-af52-25ab6cb93df7"
return {}

def process_release(self):
Expand Down Expand Up @@ -458,7 +459,7 @@ def ORG(login):
}


def CONTENT(owner, repo, file_, ref, data):
def github_file_contents(owner, repo, file_path, ref, data):
"""Github content fixture generator."""
import os
from base64 import b64encode
Expand All @@ -467,7 +468,7 @@ def CONTENT(owner, repo, file_, ref, data):
url="%s/%s" % (owner, repo),
owner=owner,
repo=repo,
file=file_,
file=file_path,
ref=ref,
)

Expand All @@ -484,8 +485,8 @@ def CONTENT(owner, repo, file_, ref, data):
"git_url": "https://api.github.com/repos/%(url)s/git/blobs/"
"aaaffdfbead0b67bd6a5f5819c458a1215ecb0f6" % c,
"html_url": "https://github.com/%(url)s/blob/%(ref)s/%(file)s" % c,
"name": os.path.basename(file_),
"path": file_,
"name": os.path.basename(file_path),
"path": file_path,
"sha": "aaaffdfbead0b67bd6a5f5819c458a1215ecb0f6",
"size": 1209,
"type": "file",
Expand Down
91 changes: 61 additions & 30 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@
# Invenio-Github is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.
"""Test invenio-github api."""
import json

from invenio_github.api import GitHubAPI
import pytest
from invenio_webhooks.models import Event

from invenio_github.api import GitHubAPI, GitHubRelease
from invenio_github.models import Release, ReleaseStatus

def test_create_hook(app, test_user, github_api):
from .fixtures import PAYLOAD as github_payload_fixture

# GithubAPI tests


def test_github_api_create_hook(app, test_user, github_api):
"""Test hook creation."""
api = GitHubAPI(test_user.id)
api.init_account()
Expand All @@ -19,31 +28,53 @@ def test_create_hook(app, test_user, github_api):
assert hook_created


# TODO add tests for GithubRelease base class (e.g. test public interface)

# TODO this test might be moved to invenio-rdm-records
# def test_extract_metadata(app, test_user, github_api):
# api = GitHubAPI(test_user.id)
# api.init_account()
# repo_id = 1
# repo_name = "repo-1"

# # Create a repo hook
# hook_created = api.create_hook(repo_id=repo_id, repo_name=repo_name)
# assert hook_created

# headers = [("Content-Type", "application/json")]
# payload = json.dumps(fixtures.PAYLOAD("auser", repo_name, repo_id, tag="v1.0"))
# with app.test_request_context(headers=headers, data=payload):
# event = Event.create(
# receiver_id="github",
# user_id=test_user.id,
# )
# release = Release.create(event)
# gh = GitHubRelease(release)
# metadata = gh.metadata

# assert metadata["resource_type"]["id"] == "software"
# # TODO maybe will fail, use default from rdm
# assert metadata["rights"]["id"] == "cc-by-4.0"
# assert len(metadata["creators"]) == 1
# GithubRelease api tests


def test_release_api(app, test_user, github_api):
api = GitHubAPI(test_user.id)
api.init_account()
repo_id = 2
repo_name = "repo-2"

# Create a repo hook
hook_created = api.create_hook(repo_id=repo_id, repo_name=repo_name)
assert hook_created

headers = [("Content-Type", "application/json")]

payload = github_payload_fixture("auser", repo_name, repo_id, tag="v1.0")
with app.test_request_context(headers=headers, data=json.dumps(payload)):
event = Event.create(
receiver_id="github",
user_id=test_user.id,
)
release = Release(
release_id=payload["release"]["id"],
tag=event.payload["release"]["tag_name"],
repository_id=repo_id,
event=event,
status=ReleaseStatus.RECEIVED,
)
# Idea is to test the public interface of GithubRelease
gh = GitHubRelease(release)

# Validate that public methods raise NotImplementedError
with pytest.raises(NotImplementedError):
gh.process_release()

with pytest.raises(NotImplementedError):
gh.publish()

assert getattr(gh, "retrieve_remote_file") is not None

# Validate that an invalid file returns None
invalid_remote_file_contents = gh.retrieve_remote_file("test")

assert invalid_remote_file_contents is None

# Validate that a valid file returns its data
valid_remote_file_contents = gh.retrieve_remote_file("test.py")

assert valid_remote_file_contents is not None
assert valid_remote_file_contents.decoded["name"] == "test.py"
56 changes: 21 additions & 35 deletions tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@
from mock import patch

from invenio_github.api import GitHubAPI
from invenio_github.models import ReleaseStatus, Repository
from invenio_github.models import Release, ReleaseStatus, Repository
from invenio_github.proxies import current_github
from invenio_github.tasks import refresh_accounts
from invenio_github.tasks import process_release, refresh_accounts
from invenio_github.utils import iso_utcnow

from . import fixtures


# TODO does it make sense to have this test under test_tasks ?
# TODO we can have test_process_release and test other things (e.g. error handlers)
def test_handle_payload(app, db, location, tester_id, remote_token, github_api):
def test_real_process_release_task(
app, db, location, tester_id, remote_token, github_api
):
# Initialise account
api = GitHubAPI(tester_id)
api.init_account()
Expand All @@ -68,36 +68,22 @@ def test_handle_payload(app, db, location, tester_id, remote_token, github_api):
payload=fixtures.PAYLOAD("auser", "repo-1", 1),
)

# Process incoming event. It should create a release and publish it.
event.process()

repo_1 = Repository.query.filter_by(name="repo-1", github_id=1).first()
assert repo_1.releases.count() == 1

release_object = repo_1.releases.first()
assert release_object.status == ReleaseStatus.PUBLISHED
assert release_object.errors is None
assert release_object.tag == "v1.0"

# Inspect release
release_api = current_github.release_api_class(release_object)
assert release_api.release_object is not None
assert release_api.payload is not None
assert release_api.release_file_name is not None
assert release_api.release_zipball_url is not None

# Validate files consistency
# files_service = current_rdm_records_service.files
# record_files = files_service.list_files(system_identity, release.record.json["id"])
# files = list(record_files.entries)
# assert len(files) == 1
# assert files[0]["size"] > 0

# # Validate bucket consistency
# bucket = Bucket.get(files[0]["bucket_id"])
# assert bucket is not None
# assert len(bucket.objects) == 1
# assert bucket.objects[0].key == "auser/repo-1-v1.0.zip"
release_object = Release(
release_id=event.payload["release"]["id"],
tag=event.payload["release"]["tag_name"],
repository=repo,
event=event,
status=ReleaseStatus.RECEIVED,
)
db.session.add(release_object)
db.session.commit()

process_release.delay(release_object.release_id)
assert repo.releases.count() == 1
release = repo.releases.first()
assert release.status == ReleaseStatus.PUBLISHED
# This uuid is a fake one set by TestGithubRelease fixture
assert str(release.record_id) == "445aaacd-9de1-41ab-af52-25ab6cb93df7"


def test_refresh_accounts(app, db, tester_id, remote_token, github_api):
Expand Down
Loading

0 comments on commit 9826cc0

Please sign in to comment.