[0-9a-f]+)/releases/",
view_name="browse-snapshot-releases",
checksum_args=["snapshot_id"],
)
def snapshot_releases_browse(request, snapshot_id):
"""Django view that produces an HTML display of the list of releases
collected in a snapshot.
The url that points to it is
:http:get:`/browse/snapshot/(snapshot_id)/releases/`
"""
return browse_snapshot_releases(request, snapshot_id=snapshot_id)
diff --git a/swh/web/templates/browse/help.html b/swh/web/templates/browse/help.html
index 22ca9940..9f4ac175 100644
--- a/swh/web/templates/browse/help.html
+++ b/swh/web/templates/browse/help.html
@@ -1,189 +1,189 @@
{% extends "./layout.html" %}
{% comment %}
Copyright (C) 2017-2018 The Software Heritage developers
See the AUTHORS file at the top-level directory of this distribution
License: GNU Affero General Public License version 3, or any later version
See top-level LICENSE file for more information
{% endcomment %}
{% block navbar-content %}
How to browse the archive ?
{% endblock %}
{% block browse-content %}
Overview
This web application aims to provide HTML views to easily navigate in the Software Heritage archive. This is an ongoing development
and new features and improvements will be progressively added over time.
URI scheme
The current URI scheme of that web application is described below and depends on the type of Software Heritage object to
browse. Its exhaustive documentation can be consulted from the official
Software Heritage development documentation
Context-independent browsing
Context-independent URLs provide information about objects (e.g., revisions, directories, contents, persons, …), independently
of the contexts where they have been found (e.g., specific software origins, branches, commits, …).
Below are some examples of endpoints used to just render the corresponding information for user consumption:
Where hyperlinks are created when browsing these kind of endpoints, they always point to other context-independent browsing
URLs.
Context-dependent browsing
Context-dependent URLs provide information about objects, limited to specific contexts where the objects have been found.
Currently, browsing the Software Heritage objects in the context of an
origin is available. Below are some examples of such endpoints:
Search software origins to browse
In order to facilitate the browsing of the archive and generate relevant entry points to it, a
search interface is available. Currently, it enables to search software origins from the URLs they were retrieved
from. More search criteria will be added in the future.
{% endblock %}
diff --git a/swh/web/tests/browse/test_snapshot_context.py b/swh/web/tests/browse/test_snapshot_context.py
index 63531163..960490ba 100644
--- a/swh/web/tests/browse/test_snapshot_context.py
+++ b/swh/web/tests/browse/test_snapshot_context.py
@@ -1,329 +1,341 @@
# Copyright (C) 2020 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU Affero General Public License version 3, or any later version
# See top-level LICENSE file for more information
import random
from hypothesis import given
from swh.web.browse.snapshot_context import (
get_origin_visit_snapshot,
get_snapshot_content,
get_snapshot_context,
)
from swh.web.common.identifiers import get_swh_persistent_id
from swh.web.common.origin_visits import get_origin_visit, get_origin_visits
from swh.web.common.typing import (
SnapshotBranchInfo,
SnapshotReleaseInfo,
SnapshotContext,
)
from swh.web.common.utils import format_utc_iso_date, reverse
from swh.web.tests.strategies import origin_with_multiple_visits, snapshot
@given(origin_with_multiple_visits())
def test_get_origin_visit_snapshot_simple(archive_data, origin):
visits = archive_data.origin_visit_get(origin["url"])
for visit in visits:
snapshot = archive_data.snapshot_get(visit["snapshot"])
branches = []
releases = []
def _process_branch_data(branch, branch_data):
if branch_data["target_type"] == "revision":
rev_data = archive_data.revision_get(branch_data["target"])
branches.append(
SnapshotBranchInfo(
name=branch,
revision=branch_data["target"],
directory=rev_data["directory"],
date=format_utc_iso_date(rev_data["date"]),
message=rev_data["message"],
url=None,
)
)
elif branch_data["target_type"] == "release":
rel_data = archive_data.release_get(branch_data["target"])
rev_data = archive_data.revision_get(rel_data["target"])
releases.append(
SnapshotReleaseInfo(
name=rel_data["name"],
branch_name=branch,
date=format_utc_iso_date(rel_data["date"]),
id=rel_data["id"],
message=rel_data["message"],
target_type=rel_data["target_type"],
target=rel_data["target"],
directory=rev_data["directory"],
url=None,
)
)
for branch in sorted(snapshot["branches"].keys()):
branch_data = snapshot["branches"][branch]
if branch_data["target_type"] == "alias":
target_data = snapshot["branches"][branch_data["target"]]
_process_branch_data(branch, target_data)
else:
_process_branch_data(branch, branch_data)
assert branches and releases, "Incomplete test data."
origin_visit_branches = get_origin_visit_snapshot(
origin, visit_id=visit["visit"]
)
assert origin_visit_branches == (branches, releases)
@given(snapshot())
def test_get_snapshot_context_no_origin(archive_data, snapshot):
for browse_context, kwargs in (
("content", {"snapshot_id": snapshot, "path": "/some/path"}),
("directory", {"snapshot_id": snapshot}),
("log", {"snapshot_id": snapshot}),
):
url_args = {"snapshot_id": snapshot}
+ query_params = dict(kwargs)
+ query_params.pop("snapshot_id")
+
snapshot_context = get_snapshot_context(**kwargs, browse_context=browse_context)
branches, releases = get_snapshot_content(snapshot)
releases = list(reversed(releases))
revision_id = None
root_directory = None
for branch in branches:
if branch["name"] == "HEAD":
revision_id = branch["revision"]
root_directory = branch["directory"]
branch["url"] = reverse(
f"browse-snapshot-{browse_context}",
- url_args=kwargs,
- query_params={"branch": branch["name"]},
+ url_args=url_args,
+ query_params={"branch": branch["name"], **query_params},
)
for release in releases:
release["url"] = reverse(
f"browse-snapshot-{browse_context}",
- url_args=kwargs,
- query_params={"release": release["name"]},
+ url_args=url_args,
+ query_params={"release": release["name"], **query_params},
)
branches_url = reverse("browse-snapshot-branches", url_args=url_args)
releases_url = reverse("browse-snapshot-releases", url_args=url_args)
is_empty = not branches and not releases
snapshot_swhid = get_swh_persistent_id("snapshot", snapshot)
snapshot_sizes = {"revision": len(branches), "release": len(releases)}
expected = SnapshotContext(
branch="HEAD",
branches=branches,
branches_url=branches_url,
is_empty=is_empty,
origin_info=None,
origin_visits_url=None,
release=None,
release_id=None,
- query_params={},
+ query_params=query_params,
releases=releases,
releases_url=releases_url,
revision_id=revision_id,
root_directory=root_directory,
snapshot_id=snapshot,
snapshot_sizes=snapshot_sizes,
snapshot_swhid=snapshot_swhid,
url_args=url_args,
visit_info=None,
)
assert snapshot_context == expected
_check_branch_release_revision_parameters(
archive_data, expected, browse_context, kwargs, branches, releases
)
@given(origin_with_multiple_visits())
def test_get_snapshot_context_with_origin(archive_data, origin):
origin_visits = get_origin_visits(origin)
timestamp = format_utc_iso_date(origin_visits[0]["date"], "%Y-%m-%dT%H:%M:%SZ")
visit_id = origin_visits[1]["visit"]
for browse_context, kwargs in (
("content", {"origin_url": origin["url"], "path": "/some/path"}),
("directory", {"origin_url": origin["url"]}),
("log", {"origin_url": origin["url"]}),
("directory", {"origin_url": origin["url"], "timestamp": timestamp,},),
("directory", {"origin_url": origin["url"], "visit_id": visit_id,},),
):
visit_id = kwargs["visit_id"] if "visit_id" in kwargs else None
visit_ts = kwargs["timestamp"] if "timestamp" in kwargs else None
visit_info = get_origin_visit(
{"url": kwargs["origin_url"]}, visit_ts=visit_ts, visit_id=visit_id
)
snapshot = visit_info["snapshot"]
snapshot_context = get_snapshot_context(**kwargs, browse_context=browse_context)
url_args = dict(kwargs)
+ url_args.pop("path", None)
+ url_args.pop("timestamp", None)
url_args.pop("visit_id", None)
- query_params = {}
- if "visit_id" in kwargs:
- query_params["visit_id"] = kwargs["visit_id"]
+ query_params = dict(kwargs)
+ query_params.pop("origin_url")
branches, releases = get_snapshot_content(snapshot)
releases = list(reversed(releases))
revision_id = None
root_directory = None
for branch in branches:
if branch["name"] == "HEAD":
revision_id = branch["revision"]
root_directory = branch["directory"]
branch["url"] = reverse(
f"browse-origin-{browse_context}",
url_args=url_args,
query_params={"branch": branch["name"], **query_params},
)
for release in releases:
release["url"] = reverse(
f"browse-origin-{browse_context}",
url_args=url_args,
query_params={"release": release["name"], **query_params},
)
- url_args.pop("path", None)
+ query_params.pop("path", None)
branches_url = reverse(
"browse-origin-branches", url_args=url_args, query_params=query_params
)
releases_url = reverse(
"browse-origin-releases", url_args=url_args, query_params=query_params
)
origin_visits_url = reverse(
"browse-origin-visits", url_args={"origin_url": kwargs["origin_url"]}
)
is_empty = not branches and not releases
snapshot_swhid = get_swh_persistent_id("snapshot", snapshot)
snapshot_sizes = {"revision": len(branches), "release": len(releases)}
visit_info["url"] = reverse(
"browse-origin-directory", url_args=url_args, query_params=query_params
)
visit_info["formatted_date"] = format_utc_iso_date(visit_info["date"])
+ if "path" in kwargs:
+ query_params["path"] = kwargs["path"]
+
expected = SnapshotContext(
branch="HEAD",
branches=branches,
branches_url=branches_url,
is_empty=is_empty,
origin_info={"url": origin["url"]},
origin_visits_url=origin_visits_url,
release=None,
release_id=None,
query_params=query_params,
releases=releases,
releases_url=releases_url,
revision_id=revision_id,
root_directory=root_directory,
snapshot_id=snapshot,
snapshot_sizes=snapshot_sizes,
snapshot_swhid=snapshot_swhid,
url_args=url_args,
visit_info=visit_info,
)
assert snapshot_context == expected
_check_branch_release_revision_parameters(
archive_data, expected, browse_context, kwargs, branches, releases
)
def _check_branch_release_revision_parameters(
archive_data, base_expected_context, browse_context, kwargs, branches, releases,
):
branch = random.choice(branches)
snapshot_context = get_snapshot_context(
**kwargs, browse_context=browse_context, branch_name=branch["name"]
)
- query_params = {}
- if "visit_id" in kwargs:
- query_params["visit_id"] = kwargs["visit_id"]
+ url_args = dict(kwargs)
+ url_args.pop("path", None)
+ url_args.pop("timestamp", None)
+ url_args.pop("visit_id", None)
+
+ query_params = dict(kwargs)
+ query_params.pop("origin_url", None)
+ query_params.pop("snapshot_id", None)
expected_branch = dict(base_expected_context)
expected_branch["branch"] = branch["name"]
expected_branch["revision_id"] = branch["revision"]
expected_branch["root_directory"] = branch["directory"]
expected_branch["query_params"] = {"branch": branch["name"], **query_params}
assert snapshot_context == expected_branch
if releases:
release = random.choice(releases)
snapshot_context = get_snapshot_context(
**kwargs, browse_context=browse_context, release_name=release["name"]
)
expected_release = dict(base_expected_context)
expected_release["branch"] = None
expected_release["release"] = release["name"]
expected_release["release_id"] = release["id"]
if release["target_type"] == "revision":
expected_release["revision_id"] = release["target"]
expected_release["root_directory"] = release["directory"]
expected_release["query_params"] = {"release": release["name"], **query_params}
assert snapshot_context == expected_release
revision_log = archive_data.revision_log(branch["revision"])
revision = revision_log[-1]
snapshot_context = get_snapshot_context(
**kwargs, browse_context=browse_context, revision_id=revision["id"]
)
if "origin_url" in kwargs:
view_name = f"browse-origin-{browse_context}"
else:
view_name = f"browse-snapshot-{browse_context}"
kwargs.pop("visit_id", None)
revision_browse_url = reverse(
view_name,
- url_args=kwargs,
+ url_args=url_args,
query_params={"revision": revision["id"], **query_params},
)
branches.append(
SnapshotBranchInfo(
name=revision["id"],
revision=revision["id"],
directory=revision["directory"],
date=revision["date"],
message=revision["message"],
url=revision_browse_url,
)
)
expected_revision = dict(base_expected_context)
expected_revision["branch"] = revision["id"]
expected_revision["branches"] = branches
expected_revision["revision_id"] = revision["id"]
expected_revision["root_directory"] = revision["directory"]
expected_revision["query_params"] = {"revision": revision["id"], **query_params}
assert snapshot_context == expected_revision
diff --git a/swh/web/tests/browse/views/test_origin.py b/swh/web/tests/browse/views/test_origin.py
index f53114bc..6980f4fb 100644
--- a/swh/web/tests/browse/views/test_origin.py
+++ b/swh/web/tests/browse/views/test_origin.py
@@ -1,1102 +1,1119 @@
# Copyright (C) 2017-2020 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU Affero General Public License version 3, or any later version
# See top-level LICENSE file for more information
from datetime import datetime
import random
import re
import string
from django.utils.html import escape
from hypothesis import given
from swh.model.hashutil import hash_to_bytes
from swh.model.model import (
Snapshot,
SnapshotBranch,
TargetType,
)
from swh.web.browse.snapshot_context import process_snapshot_branches
from swh.web.common.exc import NotFoundExc
from swh.web.common.identifiers import get_swh_persistent_id
from swh.web.common.utils import (
reverse,
gen_path_info,
format_utc_iso_date,
parse_timestamp,
)
from swh.web.config import get_config
from swh.web.tests.data import get_content, random_sha1
from swh.web.tests.django_asserts import assert_contains, assert_template_used
from swh.web.tests.strategies import (
origin,
origin_with_multiple_visits,
new_origin,
new_snapshot,
visit_dates,
revisions,
origin_with_releases,
release as existing_release,
unknown_revision,
)
@given(origin_with_multiple_visits())
def test_origin_visits_browse(client, archive_data, origin):
url = reverse("browse-origin-visits", url_args={"origin_url": origin["url"]})
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/origin-visits.html")
url = reverse("browse-origin-visits", url_args={"origin_url": origin["url"]})
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/origin-visits.html")
visits = archive_data.origin_visit_get(origin["url"])
for v in visits:
vdate = format_utc_iso_date(v["date"], "%Y-%m-%dT%H:%M:%SZ")
browse_dir_url = reverse(
"browse-origin-directory",
- url_args={"origin_url": origin["url"], "timestamp": vdate},
+ url_args={"origin_url": origin["url"]},
+ query_params={"timestamp": vdate},
)
assert_contains(resp, browse_dir_url)
@given(origin_with_multiple_visits())
def test_origin_content_view(client, archive_data, origin):
origin_visits = archive_data.origin_visit_get(origin["url"])
def _get_archive_data(visit_idx):
snapshot = archive_data.snapshot_get(origin_visits[visit_idx]["snapshot"])
head_rev_id = archive_data.snapshot_get_head(snapshot)
head_rev = archive_data.revision_get(head_rev_id)
dir_content = archive_data.directory_ls(head_rev["directory"])
dir_files = [e for e in dir_content if e["type"] == "file"]
dir_file = random.choice(dir_files)
branches, releases = process_snapshot_branches(snapshot)
return {
"branches": branches,
"releases": releases,
"root_dir_sha1": head_rev["directory"],
"content": get_content(dir_file["checksums"]["sha1"]),
"visit": origin_visits[visit_idx],
}
tdata = _get_archive_data(-1)
_origin_content_view_test_helper(
client,
origin,
origin_visits,
tdata["branches"],
tdata["releases"],
tdata["root_dir_sha1"],
tdata["content"],
)
_origin_content_view_test_helper(
client,
origin,
origin_visits,
tdata["branches"],
tdata["releases"],
tdata["root_dir_sha1"],
tdata["content"],
timestamp=tdata["visit"]["date"],
)
visit_unix_ts = parse_timestamp(tdata["visit"]["date"]).timestamp()
visit_unix_ts = int(visit_unix_ts)
_origin_content_view_test_helper(
client,
origin,
origin_visits,
tdata["branches"],
tdata["releases"],
tdata["root_dir_sha1"],
tdata["content"],
timestamp=visit_unix_ts,
)
tdata = _get_archive_data(0)
_origin_content_view_test_helper(
client,
origin,
origin_visits,
tdata["branches"],
tdata["releases"],
tdata["root_dir_sha1"],
tdata["content"],
visit_id=tdata["visit"]["visit"],
)
@given(origin())
def test_origin_root_directory_view(client, archive_data, origin):
origin_visits = archive_data.origin_visit_get(origin["url"])
visit = origin_visits[-1]
snapshot = archive_data.snapshot_get(visit["snapshot"])
head_rev_id = archive_data.snapshot_get_head(snapshot)
head_rev = archive_data.revision_get(head_rev_id)
root_dir_sha1 = head_rev["directory"]
dir_content = archive_data.directory_ls(root_dir_sha1)
branches, releases = process_snapshot_branches(snapshot)
visit_unix_ts = parse_timestamp(visit["date"]).timestamp()
visit_unix_ts = int(visit_unix_ts)
_origin_directory_view_test_helper(
client, origin, origin_visits, branches, releases, root_dir_sha1, dir_content
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
dir_content,
visit_id=visit["visit"],
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
dir_content,
timestamp=visit_unix_ts,
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
dir_content,
timestamp=visit["date"],
)
origin = dict(origin)
del origin["type"]
_origin_directory_view_test_helper(
client, origin, origin_visits, branches, releases, root_dir_sha1, dir_content
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
dir_content,
visit_id=visit["visit"],
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
dir_content,
timestamp=visit_unix_ts,
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
dir_content,
timestamp=visit["date"],
)
@given(origin())
def test_origin_sub_directory_view(client, archive_data, origin):
origin_visits = archive_data.origin_visit_get(origin["url"])
visit = origin_visits[-1]
snapshot = archive_data.snapshot_get(visit["snapshot"])
head_rev_id = archive_data.snapshot_get_head(snapshot)
head_rev = archive_data.revision_get(head_rev_id)
root_dir_sha1 = head_rev["directory"]
subdirs = [
e for e in archive_data.directory_ls(root_dir_sha1) if e["type"] == "dir"
]
branches, releases = process_snapshot_branches(snapshot)
visit_unix_ts = parse_timestamp(visit["date"]).timestamp()
visit_unix_ts = int(visit_unix_ts)
if len(subdirs) == 0:
return
subdir = random.choice(subdirs)
subdir_content = archive_data.directory_ls(subdir["target"])
subdir_path = subdir["name"]
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
subdir_content,
path=subdir_path,
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
subdir_content,
path=subdir_path,
visit_id=visit["visit"],
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
subdir_content,
path=subdir_path,
timestamp=visit_unix_ts,
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
subdir_content,
path=subdir_path,
timestamp=visit["date"],
)
origin = dict(origin)
del origin["type"]
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
subdir_content,
path=subdir_path,
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
subdir_content,
path=subdir_path,
visit_id=visit["visit"],
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
subdir_content,
path=subdir_path,
timestamp=visit_unix_ts,
)
_origin_directory_view_test_helper(
client,
origin,
origin_visits,
branches,
releases,
root_dir_sha1,
subdir_content,
path=subdir_path,
timestamp=visit["date"],
)
@given(origin())
def test_origin_branches(client, archive_data, origin):
origin_visits = archive_data.origin_visit_get(origin["url"])
visit = origin_visits[-1]
snapshot = archive_data.snapshot_get(visit["snapshot"])
snapshot_content = process_snapshot_branches(snapshot)
_origin_branches_test_helper(client, origin, snapshot_content)
origin = dict(origin)
origin["type"] = None
_origin_branches_test_helper(client, origin, snapshot_content)
@given(origin())
def test_origin_releases(client, archive_data, origin):
origin_visits = archive_data.origin_visit_get(origin["url"])
visit = origin_visits[-1]
snapshot = archive_data.snapshot_get(visit["snapshot"])
snapshot_content = process_snapshot_branches(snapshot)
_origin_releases_test_helper(client, origin, snapshot_content)
origin = dict(origin)
origin["type"] = None
_origin_releases_test_helper(client, origin, snapshot_content)
@given(
new_origin(),
new_snapshot(min_size=4, max_size=4),
visit_dates(),
revisions(min_size=3, max_size=3),
)
def test_origin_snapshot_null_branch(
client, archive_data, new_origin, new_snapshot, visit_dates, revisions
):
snp_dict = new_snapshot.to_dict()
new_origin = archive_data.origin_add([new_origin])[0]
for i, branch in enumerate(snp_dict["branches"].keys()):
if i == 0:
snp_dict["branches"][branch] = None
else:
snp_dict["branches"][branch] = {
"target_type": "revision",
"target": hash_to_bytes(revisions[i - 1]),
}
archive_data.snapshot_add([Snapshot.from_dict(snp_dict)])
visit = archive_data.origin_visit_add(new_origin["url"], visit_dates[0], type="git")
archive_data.origin_visit_update(
new_origin["url"], visit.visit, status="partial", snapshot=snp_dict["id"]
)
url = reverse("browse-origin-directory", url_args={"origin_url": new_origin["url"]})
rv = client.get(url)
assert rv.status_code == 200
@given(
new_origin(),
new_snapshot(min_size=4, max_size=4),
visit_dates(),
revisions(min_size=4, max_size=4),
)
def test_origin_snapshot_invalid_branch(
client, archive_data, new_origin, new_snapshot, visit_dates, revisions
):
snp_dict = new_snapshot.to_dict()
new_origin = archive_data.origin_add([new_origin])[0]
for i, branch in enumerate(snp_dict["branches"].keys()):
snp_dict["branches"][branch] = {
"target_type": "revision",
"target": hash_to_bytes(revisions[i]),
}
archive_data.snapshot_add([Snapshot.from_dict(snp_dict)])
visit = archive_data.origin_visit_add(new_origin["url"], visit_dates[0], type="git")
archive_data.origin_visit_update(
new_origin["url"], visit.visit, status="full", snapshot=snp_dict["id"]
)
url = reverse(
"browse-origin-directory",
url_args={"origin_url": new_origin["url"]},
query_params={"branch": "invalid_branch"},
)
rv = client.get(url)
assert rv.status_code == 404
@given(new_origin())
def test_browse_visits_origin_not_found(client, new_origin):
url = reverse("browse-origin-visits", url_args={"origin_url": new_origin.url})
resp = client.get(url)
assert resp.status_code == 404
assert_template_used(resp, "error.html")
assert_contains(
resp, f"Origin with url {new_origin.url} not found", status_code=404
)
@given(origin())
def test_browse_origin_directory_no_visit(client, mocker, origin):
mock_get_origin_visits = mocker.patch(
"swh.web.common.origin_visits.get_origin_visits"
)
mock_get_origin_visits.return_value = []
url = reverse("browse-origin-directory", url_args={"origin_url": origin["url"]})
resp = client.get(url)
assert resp.status_code == 404
assert_template_used(resp, "error.html")
assert_contains(resp, "No visit", status_code=404)
assert mock_get_origin_visits.called
@given(origin())
def test_browse_origin_directory_unknown_visit(client, mocker, origin):
mock_get_origin_visits = mocker.patch(
"swh.web.common.origin_visits.get_origin_visits"
)
mock_get_origin_visits.return_value = [{"visit": 1}]
url = reverse(
"browse-origin-directory",
url_args={"origin_url": origin["url"]},
query_params={"visit_id": 2},
)
resp = client.get(url)
assert resp.status_code == 404
assert_template_used(resp, "error.html")
assert re.search("Visit.*not found", resp.content.decode("utf-8"))
assert mock_get_origin_visits.called
@given(origin())
def test_browse_origin_directory_not_found(client, origin):
url = reverse(
"browse-origin-directory",
- url_args={"origin_url": origin["url"], "path": "/invalid/dir/path/"},
+ url_args={"origin_url": origin["url"]},
+ query_params={"path": "/invalid/dir/path/"},
)
resp = client.get(url)
assert resp.status_code == 404
assert_template_used(resp, "error.html")
assert re.search("Directory.*not found", resp.content.decode("utf-8"))
@given(origin())
def test_browse_origin_content_no_visit(client, mocker, origin):
mock_get_origin_visits = mocker.patch(
"swh.web.common.origin_visits.get_origin_visits"
)
mock_get_origin_visits.return_value = []
url = reverse(
- "browse-origin-content", url_args={"origin_url": origin["url"], "path": "foo"}
+ "browse-origin-content",
+ url_args={"origin_url": origin["url"]},
+ query_params={"path": "foo"},
)
resp = client.get(url)
assert resp.status_code == 404
assert_template_used(resp, "error.html")
assert_contains(resp, "No visit", status_code=404)
assert mock_get_origin_visits.called
@given(origin())
def test_browse_origin_content_unknown_visit(client, mocker, origin):
mock_get_origin_visits = mocker.patch(
"swh.web.common.origin_visits.get_origin_visits"
)
mock_get_origin_visits.return_value = [{"visit": 1}]
url = reverse(
"browse-origin-content",
- url_args={"origin_url": origin["url"], "path": "foo"},
- query_params={"visit_id": 2},
+ url_args={"origin_url": origin["url"]},
+ query_params={"path": "foo", "visit_id": 2},
)
resp = client.get(url)
assert resp.status_code == 404
assert_template_used(resp, "error.html")
assert re.search("Visit.*not found", resp.content.decode("utf-8"))
assert mock_get_origin_visits.called
@given(origin())
def test_browse_origin_content_empty_snapshot(client, mocker, origin):
mock_snapshot_service = mocker.patch("swh.web.browse.snapshot_context.service")
mock_get_origin_visit_snapshot = mocker.patch(
"swh.web.browse.snapshot_context.get_origin_visit_snapshot"
)
mock_get_origin_visit_snapshot.return_value = ([], [])
mock_snapshot_service.lookup_origin.return_value = origin
mock_snapshot_service.lookup_snapshot_sizes.return_value = {
"revision": 0,
"release": 0,
}
url = reverse(
- "browse-origin-content", url_args={"origin_url": origin["url"], "path": "baz"}
+ "browse-origin-content",
+ url_args={"origin_url": origin["url"]},
+ query_params={"path": "baz"},
)
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/content.html")
assert re.search("snapshot.*is empty", resp.content.decode("utf-8"))
assert mock_get_origin_visit_snapshot.called
assert mock_snapshot_service.lookup_origin.called
assert mock_snapshot_service.lookup_snapshot_sizes.called
@given(origin())
def test_browse_origin_content_not_found(client, origin):
url = reverse(
"browse-origin-content",
- url_args={"origin_url": origin["url"], "path": "/invalid/file/path"},
+ url_args={"origin_url": origin["url"]},
+ query_params={"path": "/invalid/file/path"},
)
resp = client.get(url)
assert resp.status_code == 404
assert_template_used(resp, "error.html")
assert re.search("Directory entry.*not found", resp.content.decode("utf-8"))
@given(origin())
def test_browse_directory_snapshot_not_found(client, mocker, origin):
mock_get_snapshot_context = mocker.patch(
"swh.web.browse.snapshot_context.get_snapshot_context"
)
mock_get_snapshot_context.side_effect = NotFoundExc("Snapshot not found")
url = reverse("browse-origin-directory", url_args={"origin_url": origin["url"]})
resp = client.get(url)
assert resp.status_code == 404
assert_template_used(resp, "error.html")
assert_contains(resp, "Snapshot not found", status_code=404)
assert mock_get_snapshot_context.called
@given(origin())
def test_origin_empty_snapshot(client, mocker, origin):
mock_service = mocker.patch("swh.web.browse.snapshot_context.service")
mock_get_origin_visit_snapshot = mocker.patch(
"swh.web.browse.snapshot_context.get_origin_visit_snapshot"
)
mock_get_origin_visit_snapshot.return_value = ([], [])
mock_service.lookup_snapshot_sizes.return_value = {
"revision": 0,
"release": 0,
}
mock_service.lookup_origin.return_value = origin
url = reverse("browse-origin-directory", url_args={"origin_url": origin["url"]})
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/directory.html")
resp_content = resp.content.decode("utf-8")
assert re.search("snapshot.*is empty", resp_content)
assert not re.search("swh-tr-link", resp_content)
assert mock_get_origin_visit_snapshot.called
assert mock_service.lookup_snapshot_sizes.called
@given(origin_with_releases())
def test_origin_release_browse(client, archive_data, origin):
# for swh.web.browse.snapshot_context.get_snapshot_content to only return one branch
config = get_config()
snapshot_max_size = int(config["snapshot_content_max_size"])
config["snapshot_content_max_size"] = 1
try:
snapshot = archive_data.snapshot_get_latest(origin["url"])
release = [
b for b in snapshot["branches"].values() if b["target_type"] == "release"
][-1]
release_data = archive_data.release_get(release["target"])
url = reverse(
"browse-origin-directory",
url_args={"origin_url": origin["url"]},
query_params={"release": release_data["name"]},
)
resp = client.get(url)
assert resp.status_code == 200
assert_contains(resp, release_data["name"])
assert_contains(resp, release["target"])
finally:
config["snapshot_content_max_size"] = snapshot_max_size
@given(origin_with_releases())
def test_origin_release_browse_not_found(client, origin):
invalid_release_name = "swh-foo-bar"
url = reverse(
"browse-origin-directory",
url_args={"origin_url": origin["url"]},
query_params={"release": invalid_release_name},
)
resp = client.get(url)
assert resp.status_code == 404
assert re.search(
f"Release {invalid_release_name}.*not found", resp.content.decode("utf-8")
)
@given(new_origin(), unknown_revision())
def test_origin_browse_directory_branch_with_non_resolvable_revision(
client, archive_data, new_origin, unknown_revision
):
branch_name = "master"
snapshot = Snapshot(
branches={
branch_name.encode(): SnapshotBranch(
target=hash_to_bytes(unknown_revision), target_type=TargetType.REVISION,
)
}
)
new_origin = archive_data.origin_add([new_origin])[0]
archive_data.snapshot_add([snapshot])
visit = archive_data.origin_visit_add(new_origin["url"], datetime.now(), type="git")
archive_data.origin_visit_update(
new_origin["url"], visit.visit, status="full", snapshot=snapshot.id
)
url = reverse(
"browse-origin-directory",
url_args={"origin_url": new_origin["url"]},
query_params={"branch": branch_name},
)
resp = client.get(url)
assert resp.status_code == 200
assert_contains(
resp, f"Revision {unknown_revision } could not be found in the archive."
)
+@given(origin())
+def test_origin_content_no_path(client, origin):
+ url = reverse("browse-origin-content", url_args={"origin_url": origin["url"]})
+
+ resp = client.get(url)
+
+ assert resp.status_code == 400
+ assert_contains(
+ resp, "The path of a content must be given as query parameter.", status_code=400
+ )
+
+
def _origin_content_view_test_helper(
client,
origin_info,
origin_visits,
origin_branches,
origin_releases,
root_dir_sha1,
content,
visit_id=None,
timestamp=None,
):
content_path = "/".join(content["path"].split("/")[1:])
- url_args = {"origin_url": origin_info["url"], "path": content_path}
+ url_args = {"origin_url": origin_info["url"]}
if not visit_id:
visit_id = origin_visits[-1]["visit"]
- query_params = {}
+ query_params = {"path": content_path}
if timestamp:
- url_args["timestamp"] = timestamp
+ query_params["timestamp"] = timestamp
if visit_id:
query_params["visit_id"] = visit_id
url = reverse("browse-origin-content", url_args=url_args, query_params=query_params)
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/content.html")
assert type(content["data"]) == str
assert_contains(resp, '' % content["hljs_language"])
assert_contains(resp, escape(content["data"]))
split_path = content_path.split("/")
filename = split_path[-1]
path = content_path.replace(filename, "")[:-1]
path_info = gen_path_info(path)
- del url_args["path"]
+ del query_params["path"]
if timestamp:
- url_args["timestamp"] = format_utc_iso_date(
+ query_params["timestamp"] = format_utc_iso_date(
parse_timestamp(timestamp).isoformat(), "%Y-%m-%dT%H:%M:%SZ"
)
root_dir_url = reverse(
"browse-origin-directory", url_args=url_args, query_params=query_params
)
assert_contains(resp, '', count=len(path_info) + 1)
assert_contains(resp, '%s' % (root_dir_url, root_dir_sha1[:7]))
for p in path_info:
- url_args["path"] = p["path"]
+ query_params["path"] = p["path"]
dir_url = reverse(
"browse-origin-directory", url_args=url_args, query_params=query_params
)
assert_contains(resp, '%s' % (dir_url, p["name"]))
assert_contains(resp, "%s" % filename)
query_string = "sha1_git:" + content["sha1_git"]
url_raw = reverse(
"browse-content-raw",
url_args={"query_string": query_string},
query_params={"filename": filename},
)
assert_contains(resp, url_raw)
- if "args" in url_args:
- del url_args["path"]
+ if "path" in query_params:
+ del query_params["path"]
origin_branches_url = reverse(
"browse-origin-branches", url_args=url_args, query_params=query_params
)
assert_contains(
resp,
- 'Branches (%s)' % (origin_branches_url, len(origin_branches)),
+ 'Branches (%s)'
+ % (escape(origin_branches_url), len(origin_branches)),
)
origin_releases_url = reverse(
"browse-origin-releases", url_args=url_args, query_params=query_params
)
assert_contains(
resp,
- 'Releases (%s)' % (origin_releases_url, len(origin_releases)),
+ 'Releases (%s)'
+ % (escape(origin_releases_url), len(origin_releases)),
)
assert_contains(resp, '', count=len(origin_branches))
- url_args["path"] = content_path
+ query_params["path"] = content_path
for branch in origin_branches:
query_params["branch"] = branch["name"]
root_dir_branch_url = reverse(
"browse-origin-content", url_args=url_args, query_params=query_params
)
assert_contains(resp, '' % root_dir_branch_url)
assert_contains(resp, '', count=len(origin_releases))
query_params["branch"] = None
for release in origin_releases:
query_params["release"] = release["name"]
root_dir_release_url = reverse(
"browse-origin-content", url_args=url_args, query_params=query_params
)
assert_contains(resp, '' % root_dir_release_url)
url = reverse("browse-origin-content", url_args=url_args, query_params=query_params)
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/content.html")
swh_cnt_id = get_swh_persistent_id("content", content["sha1_git"])
swh_cnt_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_cnt_id})
assert_contains(resp, swh_cnt_id)
assert_contains(resp, swh_cnt_id_url)
assert_contains(resp, "swh-take-new-snapshot")
def _origin_directory_view_test_helper(
client,
origin_info,
origin_visits,
origin_branches,
origin_releases,
root_directory_sha1,
directory_entries,
visit_id=None,
timestamp=None,
path=None,
):
dirs = [e for e in directory_entries if e["type"] in ("dir", "rev")]
files = [e for e in directory_entries if e["type"] == "file"]
if not visit_id:
visit_id = origin_visits[-1]["visit"]
url_args = {"origin_url": origin_info["url"]}
query_params = {}
if timestamp:
- url_args["timestamp"] = timestamp
+ query_params["timestamp"] = timestamp
else:
query_params["visit_id"] = visit_id
if path:
- url_args["path"] = path
+ query_params["path"] = path
url = reverse(
"browse-origin-directory", url_args=url_args, query_params=query_params
)
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/directory.html")
assert resp.status_code == 200
assert_template_used(resp, "browse/directory.html")
assert_contains(resp, '', count=len(dirs))
assert_contains(resp, ' | ', count=len(files))
if timestamp:
- url_args["timestamp"] = format_utc_iso_date(
+ query_params["timestamp"] = format_utc_iso_date(
parse_timestamp(timestamp).isoformat(), "%Y-%m-%dT%H:%M:%SZ"
)
for d in dirs:
if d["type"] == "rev":
dir_url = reverse("browse-revision", url_args={"sha1_git": d["target"]})
else:
dir_path = d["name"]
if path:
dir_path = "%s/%s" % (path, d["name"])
- dir_url_args = dict(url_args)
- dir_url_args["path"] = dir_path
+ query_params["path"] = dir_path
dir_url = reverse(
- "browse-origin-directory",
- url_args=dir_url_args,
- query_params=query_params,
+ "browse-origin-directory", url_args=url_args, query_params=query_params,
)
assert_contains(resp, dir_url)
for f in files:
file_path = f["name"]
if path:
file_path = "%s/%s" % (path, f["name"])
- file_url_args = dict(url_args)
- file_url_args["path"] = file_path
+ query_params["path"] = file_path
file_url = reverse(
- "browse-origin-content", url_args=file_url_args, query_params=query_params
+ "browse-origin-content", url_args=url_args, query_params=query_params
)
assert_contains(resp, file_url)
- if "path" in url_args:
- del url_args["path"]
+ if "path" in query_params:
+ del query_params["path"]
root_dir_branch_url = reverse(
"browse-origin-directory", url_args=url_args, query_params=query_params
)
nb_bc_paths = 1
if path:
nb_bc_paths = len(path.split("/")) + 1
assert_contains(resp, '', count=nb_bc_paths)
assert_contains(
resp, '%s' % (root_dir_branch_url, root_directory_sha1[:7])
)
origin_branches_url = reverse(
"browse-origin-branches", url_args=url_args, query_params=query_params
)
assert_contains(
resp,
'Branches (%s)' % (origin_branches_url, len(origin_branches)),
)
origin_releases_url = reverse(
"browse-origin-releases", url_args=url_args, query_params=query_params
)
nb_releases = len(origin_releases)
if nb_releases > 0:
assert_contains(
resp, 'Releases (%s)' % (origin_releases_url, nb_releases)
)
if path:
- url_args["path"] = path
+ query_params["path"] = path
assert_contains(resp, '', count=len(origin_branches))
for branch in origin_branches:
query_params["branch"] = branch["name"]
root_dir_branch_url = reverse(
"browse-origin-directory", url_args=url_args, query_params=query_params
)
assert_contains(resp, '' % root_dir_branch_url)
assert_contains(resp, '', count=len(origin_releases))
query_params["branch"] = None
for release in origin_releases:
query_params["release"] = release["name"]
root_dir_release_url = reverse(
"browse-origin-directory", url_args=url_args, query_params=query_params
)
assert_contains(resp, '' % root_dir_release_url)
assert_contains(resp, "vault-cook-directory")
assert_contains(resp, "vault-cook-revision")
swh_dir_id = get_swh_persistent_id("directory", directory_entries[0]["dir_id"])
swh_dir_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_dir_id})
assert_contains(resp, swh_dir_id)
assert_contains(resp, swh_dir_id_url)
assert_contains(resp, "swh-take-new-snapshot")
def _origin_branches_test_helper(client, origin_info, origin_snapshot):
url_args = {"origin_url": origin_info["url"]}
url = reverse("browse-origin-branches", url_args=url_args)
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/branches.html")
origin_branches = origin_snapshot[0]
origin_releases = origin_snapshot[1]
origin_branches_url = reverse("browse-origin-branches", url_args=url_args)
assert_contains(
resp,
'Branches (%s)' % (origin_branches_url, len(origin_branches)),
)
origin_releases_url = reverse("browse-origin-releases", url_args=url_args)
nb_releases = len(origin_releases)
if nb_releases > 0:
assert_contains(
resp, 'Releases (%s)' % (origin_releases_url, nb_releases)
)
assert_contains(resp, '' % escape(browse_branch_url))
browse_revision_url = reverse(
"browse-revision",
url_args={"sha1_git": branch["revision"]},
query_params={"origin": origin_info["url"]},
)
assert_contains(resp, '' % escape(browse_revision_url))
def _origin_releases_test_helper(client, origin_info, origin_snapshot):
url_args = {"origin_url": origin_info["url"]}
url = reverse("browse-origin-releases", url_args=url_args)
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/releases.html")
origin_branches = origin_snapshot[0]
origin_releases = origin_snapshot[1]
origin_branches_url = reverse("browse-origin-branches", url_args=url_args)
assert_contains(
resp,
'Branches (%s)' % (origin_branches_url, len(origin_branches)),
)
origin_releases_url = reverse("browse-origin-releases", url_args=url_args)
nb_releases = len(origin_releases)
if nb_releases > 0:
assert_contains(
resp, 'Releases (%s)' % (origin_releases_url, nb_releases)
)
assert_contains(resp, ' ' % escape(browse_release_url))
assert_contains(resp, '' % escape(browse_revision_url))
@given(
new_origin(), visit_dates(), revisions(min_size=10, max_size=10), existing_release()
)
def test_origin_branches_pagination_with_alias(
client, archive_data, mocker, new_origin, visit_dates, revisions, existing_release
):
"""
When a snapshot contains a branch or a release alias, pagination links
in the branches / releases view should be displayed.
"""
mocker.patch("swh.web.browse.snapshot_context.PER_PAGE", len(revisions) / 2)
snp_dict = {"branches": {}, "id": hash_to_bytes(random_sha1())}
for i in range(len(revisions)):
branch = "".join(random.choices(string.ascii_lowercase, k=8))
snp_dict["branches"][branch.encode()] = {
"target_type": "revision",
"target": hash_to_bytes(revisions[i]),
}
release = "".join(random.choices(string.ascii_lowercase, k=8))
snp_dict["branches"][b"RELEASE_ALIAS"] = {
"target_type": "alias",
"target": release.encode(),
}
snp_dict["branches"][release.encode()] = {
"target_type": "release",
"target": hash_to_bytes(existing_release),
}
new_origin = archive_data.origin_add([new_origin])[0]
archive_data.snapshot_add([Snapshot.from_dict(snp_dict)])
visit = archive_data.origin_visit_add(new_origin["url"], visit_dates[0], type="git")
archive_data.origin_visit_update(
new_origin["url"], visit.visit, status="full", snapshot=snp_dict["id"]
)
url = reverse("browse-origin-branches", url_args={"origin_url": new_origin["url"]})
resp = client.get(url)
assert resp.status_code == 200
assert_template_used(resp, "browse/branches.html")
assert_contains(resp, ' |