Skip to content

Commit 059d78b

Browse files
Rasmus Oscar Welanderglpatcern
authored andcommitted
Added checkpoint API, examples and tests
1 parent b518b2f commit 059d78b

File tree

3 files changed

+218
-0
lines changed

3 files changed

+218
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
checkpoints_api_example.py
3+
4+
Example script to demonstrate the usage of the checkpoint API in the CS3Client class.
5+
note that these are examples, and is not meant to be run as a script.
6+
7+
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
8+
9+
Last updated: 19/08/2024
10+
"""
11+
12+
import logging
13+
import configparser
14+
from cs3client import CS3Client
15+
from cs3resource import Resource
16+
17+
config = configparser.ConfigParser()
18+
with open("default.conf") as fdef:
19+
config.read_file(fdef)
20+
# log
21+
log = logging.getLogger(__name__)
22+
23+
client = CS3Client(config, "cs3client", log)
24+
# client.auth.set_token("<your_token_here>")
25+
# OR
26+
client.auth.set_client_secret("<your_client_secret_here>")
27+
28+
res = None
29+
30+
markdown_resource = Resource.from_file_ref_and_endpoint("/eos/user/r/rwelande/test.md")
31+
32+
res = client.checkpoint.list_file_versions(markdown_resource)
33+
34+
if res is not None:
35+
for ver in res:
36+
print(ver)
37+
38+
res = client.checkpoint.restore_file_version(markdown_resource, "1722936250.0569fa2f")
39+
if res is not None:
40+
for ver in res:
41+
print(ver)

src/checkpoint.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""
2+
checkpoint.py
3+
4+
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
5+
6+
Last updated: 19/08/2024
7+
"""
8+
9+
from typing import Generator
10+
import logging
11+
from auth import Auth
12+
import cs3.storage.provider.v1beta1.resources_pb2 as cs3spr
13+
import cs3.storage.provider.v1beta1.provider_api_pb2 as cs3spp
14+
from cs3.gateway.v1beta1.gateway_api_pb2_grpc import GatewayAPIStub
15+
from config import Config
16+
from statuscodehandler import StatusCodeHandler
17+
from cs3resource import Resource
18+
19+
20+
class Checkpoint:
21+
"""
22+
Checkpoint class to handle checkpoint related API calls with CS3 Gateway API.
23+
"""
24+
25+
def __init__(
26+
self,
27+
config: Config,
28+
log: logging.Logger,
29+
gateway: GatewayAPIStub,
30+
auth: Auth,
31+
status_code_handler: StatusCodeHandler,
32+
) -> None:
33+
"""
34+
Initializes the checkpoint class with configuration, logger, auth, and gateway stub,
35+
36+
:param config: Config object containing the configuration parameters.
37+
:param log: Logger instance for logging.
38+
:param gateway: GatewayAPIStub instance for interacting with CS3 Gateway.
39+
:param auth: An instance of the auth class.
40+
:param status_code_handler: An instance of the StatusCodeHandler class.
41+
"""
42+
self._gateway: GatewayAPIStub = gateway
43+
self._log: logging.Logger = log
44+
self._config: Config = config
45+
self._auth: Auth = auth
46+
self._status_code_handler: StatusCodeHandler = status_code_handler
47+
48+
def list_file_versions(
49+
self, resource: Resource, page_token: str = "", page_size: int = 0
50+
) -> Generator[cs3spr.FileVersion, any, any]:
51+
"""
52+
List all versions of a file.
53+
54+
:param resource: Resource object containing the resource information.
55+
:param page_token: Token for pagination.
56+
:param page_size: Number of file versions to return.
57+
(default is zero, where the server decides the number of versions to return)
58+
:return: List of file versions (None if no versions are found).
59+
:raises: AuthenticationException (Operation not permitted)
60+
:raises: NotFoundException (File not found)
61+
:raises: UnknownException (Unknown error)
62+
"""
63+
req = cs3spp.ListFileVersionsRequest(ref=resource.ref, page_token=page_token, page_size=page_size)
64+
res = self._gateway.ListFileVersions(request=req, metadata=[self._auth.get_token()])
65+
self._status_code_handler.handle_errors(res.status, "list file versions", f"{resource.get_file_ref_str()}")
66+
self._log.debug(f'msg="list file versions" {resource.get_file_ref_str()} trace="{res.status.trace}"')
67+
return res.versions
68+
69+
def restore_file_version(self, resource: Resource, version_key: str, lock_id: str = None) -> None:
70+
"""
71+
Restore a file to a previous version.
72+
73+
:param resource: Resource object containing the resource information.
74+
:param version_key: Key of the version to restore.
75+
:param lock_id: Lock ID of the file (OPTIONAL).
76+
:return: None (Success)
77+
:raises: AuthenticationException (Operation not permitted)
78+
:raises: NotFoundException (File not found)
79+
:raises: UnknownException (Unknown error)
80+
"""
81+
req = cs3spp.RestoreFileVersionRequest(ref=resource.ref, key=version_key, lock_id=lock_id)
82+
res = self._gateway.RestoreFileVersion(request=req, metadata=[self._auth.get_token()])
83+
self._status_code_handler.handle_errors(res.status, "restore file version", f"{resource.get_file_ref_str()}")
84+
self._log.debug(f'msg="restore file version" {resource.get_file_ref_str()} trace="{res.status.trace}"')
85+
return

tests/test_checkpoint.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""
2+
test_checkpoint.py
3+
4+
Tests that the App class methods work as expected.
5+
6+
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
7+
8+
Last updated: 19/08/2024
9+
"""
10+
11+
from exceptions.exceptions import (
12+
AuthenticationException,
13+
NotFoundException,
14+
UnknownException,
15+
)
16+
17+
from cs3resource import Resource
18+
19+
import cs3.rpc.v1beta1.code_pb2 as cs3code
20+
from fixtures import ( # noqa: F401 (they are used, the framework is not detecting it)
21+
mock_config,
22+
mock_logger,
23+
mock_authentication,
24+
mock_gateway,
25+
checkpoint_instance,
26+
mock_status_code_handler,
27+
)
28+
29+
from unittest.mock import Mock, patch
30+
31+
import pytest
32+
33+
# Test cases for the Checkpoint class
34+
35+
36+
@pytest.mark.parametrize(
37+
"status_code, status_message, expected_exception, versions",
38+
[
39+
(cs3code.CODE_OK, None, None, [Mock(), Mock()]),
40+
(cs3code.CODE_UNAUTHENTICATED, "error", AuthenticationException, None),
41+
(cs3code.CODE_NOT_FOUND, "error", NotFoundException, None),
42+
(-2, "error", UnknownException, None),
43+
],
44+
)
45+
def test_list_file_versions(
46+
checkpoint_instance, status_code, status_message, expected_exception, versions # noqa: F811 (not a redefinition)
47+
):
48+
resource = Resource.from_file_ref_and_endpoint(endpoint="", file="testfile")
49+
page_token = "page_token"
50+
page_size = 10
51+
52+
mock_response = Mock()
53+
mock_response.status.code = status_code
54+
mock_response.status.message = status_message
55+
mock_response.versions = versions
56+
57+
with patch.object(checkpoint_instance._gateway, "ListFileVersions", return_value=mock_response):
58+
if expected_exception:
59+
with pytest.raises(expected_exception):
60+
checkpoint_instance.list_file_versions(resource, page_token, page_size)
61+
else:
62+
result = checkpoint_instance.list_file_versions(resource, page_token, page_size)
63+
assert result == versions
64+
65+
66+
@pytest.mark.parametrize(
67+
"status_code, status_message, expected_exception",
68+
[
69+
(cs3code.CODE_OK, None, None),
70+
(cs3code.CODE_UNAUTHENTICATED, "error", AuthenticationException),
71+
(cs3code.CODE_NOT_FOUND, "error", NotFoundException),
72+
(-2, "error", UnknownException),
73+
],
74+
)
75+
def test_restore_file_version(
76+
checkpoint_instance, status_code, status_message, expected_exception # noqa: F811 (not a redefinition)
77+
):
78+
resource = Resource.from_file_ref_and_endpoint(endpoint="", file="testfile")
79+
version_key = "version_key"
80+
lock_id = "lock_id"
81+
82+
mock_response = Mock()
83+
mock_response.status.code = status_code
84+
mock_response.status.message = status_message
85+
86+
with patch.object(checkpoint_instance._gateway, "RestoreFileVersion", return_value=mock_response):
87+
if expected_exception:
88+
with pytest.raises(expected_exception):
89+
checkpoint_instance.restore_file_version(resource, version_key, lock_id)
90+
else:
91+
result = checkpoint_instance.restore_file_version(resource, version_key, lock_id)
92+
assert result is None

0 commit comments

Comments
 (0)