From 1f53229c141f7500e36edc592b9a7ef255454338 Mon Sep 17 00:00:00 2001 From: Silvio Ankermann Date: Fri, 29 Jan 2021 13:08:11 +0100 Subject: [PATCH 1/2] Restructure classes --- annexremote/annexremote.py | 154 ++++++++------ docs/annexremote/annexremote.html | 290 +++++++++----------------- tests/test_GitAnnexRequestMessages.py | 186 ++++++++--------- tests/test_SpecialRemoteMessages.py | 92 ++++---- tests/utils.py | 12 +- 5 files changed, 331 insertions(+), 403 deletions(-) diff --git a/annexremote/annexremote.py b/annexremote/annexremote.py index f40d805..59838b9 100644 --- a/annexremote/annexremote.py +++ b/annexremote/annexremote.py @@ -86,7 +86,7 @@ class SpecialRemote(metaclass=ABCMeta): Note that the user is not required to provided all the settings listed here. """ - def __init__(self, annex): + def __init__(self, annex=None): self.annex = annex self.info = {} self.configs = {} @@ -531,8 +531,10 @@ class Protocol(object): It is not further documented as it was never intended to be part of the public API. """ - def __init__(self, remote): + def __init__(self, remote, master): self.remote = remote + self.request_messages = _GitAnnexRequestMessages(self, self.remote) + self.master = master self.version = "VERSION 1" self.exporting = False self.extensions = list() @@ -544,7 +546,7 @@ def command(self, line): raise ProtocolError("Got empty line") - method = self.lookupMethod(parts[0]) or self.do_UNKNOWN + method = self.lookupMethod(parts[0]) try: @@ -555,14 +557,57 @@ def command(self, line): except TypeError as e: raise SyntaxError(e) else: - if method != self.do_EXPORT: + if method != self.request_messages.do_EXPORT: self.exporting = False return reply def lookupMethod(self, command): - return getattr(self, 'do_' + command.upper(), None) + return getattr(self.request_messages, 'do_' + command.upper(), self.request_messages.do_UNKNOWN) - def check_key(self, key): + def error(self, *args): + self._send("ERROR", *args) + + def debug(self, *args): + self._send("DEBUG", *args) + + def _ask(self, request, reply_keyword, reply_count): + self._send(request) + line = self.master.input.readline().rstrip().split(" ", reply_count) + if line and line[0] == reply_keyword: + line.extend([""] * (reply_count+1-len(line))) + return line[1:] + else: + raise UnexpectedMessage("Expected {reply_keyword} and {reply_count} values. Got {line}".format(reply_keyword=reply_keyword, reply_count=reply_count, line=line)) + + def _askvalues(self, request): + self._send(request) + reply = [] + while True: + # due to a bug in python 2 we can't use an iterator here: https://bugs.python.org/issue1633941 + line = self.master.input.readline() + line = line.rstrip() + line = line.split(" ", 1) + if len(line) == 2 and line[0] == "VALUE": + reply.append(line[1]) + elif len(line) == 1 and line[0] == "VALUE": + return reply + else: + raise UnexpectedMessage("Expected VALUE {value}") + + def _askvalue(self, request): + (reply,) = self._ask(request, "VALUE", 1) + return reply + + def _send(self, *args, **kwargs): + print(*args, file=self.master.output, **kwargs) + self.master.output.flush() + +class _GitAnnexRequestMessages(object): + def __init__(self, protocol, remote): + self.protocol = protocol + self.remote = remote + + def _check_key(self, key): if len(key.split()) != 1: raise ValueError("Invalid key. Key contains whitespace character") @@ -578,7 +623,7 @@ def do_INITREMOTE(self): return "INITREMOTE-SUCCESS" def do_EXTENSIONS(self, param): - self.extensions = param.split(" ") + self.protocol.extensions = param.split(" ") return "EXTENSIONS" def do_PREPARE(self): @@ -607,7 +652,7 @@ def do_TRANSFER(self, param): return "TRANSFER-SUCCESS {method} {key}".format(method=method, key=key) def do_CHECKPRESENT(self, key): - self.check_key(key) + self._check_key(key) try: if self.remote.checkpresent(key): return "CHECKPRESENT-SUCCESS {key}".format(key=key) @@ -617,7 +662,7 @@ def do_CHECKPRESENT(self, key): return "CHECKPRESENT-UNKNOWN {key} {e}".format(key=key, e=e) def do_REMOVE(self, key): - self.check_key(key) + self._check_key(key) try: self.remote.remove(key) @@ -695,7 +740,7 @@ def do_CHECKURL(self, url): def do_WHEREIS(self, key): - self.check_key(key) + self._check_key(key) reply = self.remote.whereis(key) if reply: return "WHEREIS-SUCCESS {reply}".format(reply=reply) @@ -721,10 +766,10 @@ def do_EXPORTSUPPORTED(self): return "EXPORTSUPPORTED-FAILURE" def do_EXPORT(self, name): - self.exporting = name + self.protocol.exporting = name def do_TRANSFEREXPORT(self, param): - if not self.exporting: + if not self.protocol.exporting: raise ProtocolError("Export request without prior EXPORT") try: (method, key, file_) = param.split(" ", 2) @@ -736,18 +781,18 @@ def do_TRANSFEREXPORT(self, param): func = getattr(self.remote, "transferexport_{}".format(method.lower()), None) try: - func(key, file_, self.exporting) + func(key, file_, self.protocol.exporting) except RemoteError as e: return "TRANSFER-FAILURE {method} {key} {e}".format(method=method, key=key, e=e) else: return "TRANSFER-SUCCESS {method} {key}".format(method=method, key=key) def do_CHECKPRESENTEXPORT(self, key): - if not self.exporting: + if not self.protocol.exporting: raise ProtocolError("Export request without prior EXPORT") - self.check_key(key) + self._check_key(key) try: - if self.remote.checkpresentexport(key, self.exporting): + if self.remote.checkpresentexport(key, self.protocol.exporting): return "CHECKPRESENT-SUCCESS {key}".format(key=key) else: return "CHECKPRESENT-FAILURE {key}".format(key=key) @@ -755,12 +800,12 @@ def do_CHECKPRESENTEXPORT(self, key): return "CHECKPRESENT-UNKNOWN {key} {e}".format(key=key, e=e) def do_REMOVEEXPORT(self, key): - if not self.exporting: + if not self.protocol.exporting: raise ProtocolError("Export request without prior EXPORT") - self.check_key(key) + self._check_key(key) try: - self.remote.removeexport(key, self.exporting) + self.remote.removeexport(key, self.protocol.exporting) except RemoteError as e: return "REMOVE-FAILURE {key} {e}".format(key=key, e=e) else: @@ -775,7 +820,7 @@ def do_REMOVEEXPORTDIRECTORY(self, name): return "REMOVEEXPORTDIRECTORY-SUCCESS" def do_RENAMEEXPORT(self, param): - if not self.exporting: + if not self.protocol.exporting: raise ProtocolError("Export request without prior EXPORT") try: (key, new_name) = param.split(None, 1) @@ -783,7 +828,7 @@ def do_RENAMEEXPORT(self, param): raise SyntaxError("Expected TRANSFER STORE Key File") try: - self.remote.renameexport(key, self.exporting, new_name) + self.remote.renameexport(key, self.protocol.exporting, new_name) except RemoteError: return "RENAMEEXPORT-FAILURE {key}".format(key=key) else: @@ -819,6 +864,7 @@ def __init__(self, output=sys.stdout): Default: sys.stdout """ self.output = output + self.input = sys.stdin def LinkRemote(self, remote): """ @@ -831,7 +877,8 @@ def LinkRemote(self, remote): ExternalSpecialRemote interface to which this master will be linked. """ self.remote = remote - self.protocol = Protocol(remote) + self.protocol = Protocol(remote, self) + self.remote.annex = SpecialRemoteMessages(self.protocol) def LoggingHandler(self): """ @@ -841,7 +888,7 @@ def LoggingHandler(self): ------- AnnexLoggingHandler """ - return AnnexLoggingHandler(self) + return AnnexLoggingHandler(self.protocol) def Listen(self, input=sys.stdin): """ @@ -862,7 +909,7 @@ def Listen(self, input=sys.stdin): raise NotLinkedError("Please execute LinkRemote(remote) first.") self.input = input - self._send(self.protocol.version) + self.protocol._send(self.protocol.version) while True: # due to a bug in python 2 we can't use an iterator here: https://bugs.python.org/issue1633941 line = self.input.readline() @@ -872,43 +919,32 @@ def Listen(self, input=sys.stdin): try: reply = self.protocol.command(line) if reply: - self._send(reply) + self.protocol._send(reply) except UnsupportedRequest: - self._send ("UNSUPPORTED-REQUEST") + self.protocol._send ("UNSUPPORTED-REQUEST") except Exception as e: for line in traceback.format_exc().splitlines(): - self.debug(line) - self.error(e) + self.protocol.debug(line) + self.protocol.error(e) raise SystemExit - def _ask(self, request, reply_keyword, reply_count): - self._send(request) - line = self.input.readline().rstrip().split(" ", reply_count) - if line and line[0] == reply_keyword: - line.extend([""] * (reply_count+1-len(line))) - return line[1:] - else: - raise UnexpectedMessage("Expected {reply_keyword} and {reply_count} values. Got {line}".format(reply_keyword=reply_keyword, reply_count=reply_count, line=line)) - def _askvalues(self, request): - self._send(request) - reply = [] - while True: - # due to a bug in python 2 we can't use an iterator here: https://bugs.python.org/issue1633941 - line = self.input.readline() - line = line.rstrip() - line = line.split(" ", 1) - if len(line) == 2 and line[0] == "VALUE": - reply.append(line[1]) - elif len(line) == 1 and line[0] == "VALUE": - return reply - else: - raise UnexpectedMessage("Expected VALUE {value}") +class SpecialRemoteMessages: + def __init__(self, protocol): + self.protocol = protocol + + def _ask(self, *args, **kwargs): + return self.protocol._ask(*args, **kwargs) + + def _askvalues(self, *args, **kwargs): + return self.protocol._askvalues(*args, **kwargs) + + def _askvalue(self, *args, **kwargs): + return self.protocol._askvalue(*args, **kwargs) + + def _send(self, *args, **kwargs): + return self.protocol._send(*args, **kwargs) - def _askvalue(self, request): - (reply,) = self._ask(request, "VALUE", 1) - return reply - def getconfig(self, setting): """ Gets one of the special remote's configuration settings, @@ -999,7 +1035,7 @@ def debug(self, *args): The message to be displayed to the user """ - self._send("DEBUG", *args) + self.protocol.debug(*args) def error(self, *args): """ @@ -1013,7 +1049,7 @@ def error(self, *args): error_msg : str The error message to be sent to git-annex """ - self._send("ERROR", *args) + self.protocol.error(*args) def progress(self, progress): """ @@ -1323,8 +1359,4 @@ def getgitremotename(self): return self._askvalue("GETGITREMOTENAME") else: raise ProtocolError("GETGITREMOTENAME not available") - - - def _send(self, *args, **kwargs): - print(*args, file=self.output, **kwargs) - self.output.flush() + \ No newline at end of file diff --git a/docs/annexremote/annexremote.html b/docs/annexremote/annexremote.html index bc36892..af2ba11 100644 --- a/docs/annexremote/annexremote.html +++ b/docs/annexremote/annexremote.html @@ -157,7 +157,7 @@

Methods

class SpecialRemote -(annex) +(annex=None)

Metaclass for non-export remotes.

@@ -465,7 +465,7 @@

Parameters

class ExportRemote -(annex) +(annex=None)

Metaclass for remotes that support non-export and export behaviour.

@@ -660,9 +660,24 @@

Inherited members

+
+class AsyncRemote +
+
+
+

Methods

+
+
+def getRemoteJob(self, job_number) +
+
+
+
+
+
class Protocol -(remote) +(remote, master)

Helper class handling the receiving part of the protocol (git-annex to remote) @@ -683,140 +698,20 @@

Methods

-
-def check_key(self, key) -
-
-
-
-
-def do_UNKNOWN(self, *arg) -
-
-
-
-
-def do_INITREMOTE(self) -
-
-
-
-
-def do_EXTENSIONS(self, param) -
-
-
-
-
-def do_PREPARE(self) -
-
-
-
-
-def do_TRANSFER(self, param) -
-
-
-
-
-def do_CHECKPRESENT(self, key) -
-
-
-
-
-def do_REMOVE(self, key) -
-
-
-
-
-def do_LISTCONFIGS(self) -
-
-
-
-
-def do_GETCOST(self) -
-
-
-
-
-def do_GETAVAILABILITY(self) -
-
-
-
-
-def do_CLAIMURL(self, url) -
-
-
-
-
-def do_CHECKURL(self, url) -
-
-
-
-
-def do_WHEREIS(self, key) -
-
-
-
-
-def do_GETINFO(self) -
-
-
-
-
-def do_ERROR(self, message) -
-
-
-
-
-def do_EXPORTSUPPORTED(self) -
-
-
-
-
-def do_EXPORT(self, name) -
-
-
-
-
-def do_TRANSFEREXPORT(self, param) -
-
-
-
-
-def do_CHECKPRESENTEXPORT(self, key) -
-
-
-
-
-def do_REMOVEEXPORT(self, key) +
+def get_job(self, job_number)
-
-def do_REMOVEEXPORTDIRECTORY(self, name) +
+def error(self, *args)
-
-def do_RENAMEEXPORT(self, param) +
+def debug(self, *args)
@@ -891,7 +786,17 @@

Raises

If there is no remote linked to this master.
-
+ + +
+class SpecialRemoteMessages +(protocol) +
+
+
+

Methods

+
+
def getconfig(self, setting)
@@ -915,7 +820,7 @@

Raises

If git-annex does not respond correctly to this request, which is very unlikely.
-
+
def setconfig(self, setting, value)
@@ -932,7 +837,7 @@

Parameters

The value of the setting
-
+
def getstate(self, key)
@@ -953,7 +858,7 @@

Raises

If git-annex does not respond correctly to this request, which is very unlikely.
-
+
def setstate(self, key, value)
@@ -971,7 +876,7 @@

Parameters

The state for the key to store
-
+
def debug(self, *args)
@@ -982,7 +887,7 @@

Parameters

The message to be displayed to the user
-
+
def error(self, *args)
@@ -996,7 +901,7 @@

Parameters

The error message to be sent to git-annex
-
+
def progress(self, progress)
@@ -1010,7 +915,7 @@

Parameters

The current progress of the transfer in bytes.
-
+
def dirhash(self, key)
@@ -1034,7 +939,7 @@

Raises

If git-annex does not respond correctly to this request, which is very unlikely.
-
+
def dirhash_lower(self, key)
@@ -1059,7 +964,7 @@

Raises

If git-annex does not respond correctly to this request, which is very unlikely.
-
+
def setcreds(self, setting, user, password)
@@ -1083,7 +988,7 @@

Parameters

The password to be stored
-
+
def getcreds(self, setting)
@@ -1109,7 +1014,7 @@

Raises

If git-annex does not respond correctly to this request, which is very unlikely.
-
+
def getuuid(self)
@@ -1120,7 +1025,7 @@

Returns

The UUID of the special remote
-
+
def getgitdir(self)
@@ -1132,7 +1037,7 @@

Returns

The (relative) path to the git directory
-
+
def setwanted(self, prefcontent)
@@ -1148,7 +1053,7 @@

Parameters

see https://git-annex.branchable.com/git-annex-preferred-content/
-
+
def getwanted(self)
@@ -1165,7 +1070,7 @@

Raises

If git-annex does not respond correctly to this request, which is very unlikely.
-
+
def seturlpresent(self, key, url)
@@ -1184,7 +1089,7 @@

Parameters

The URL from which the key can be downloaded
-
+
def seturlmissing(self, key, url)
@@ -1197,7 +1102,7 @@

Parameters

The URL which is no longer accessible
-
+
def seturipresent(self, key, uri)
@@ -1212,7 +1117,7 @@

Parameters

The URI from which the key can be downloaded
-
+
def seturimissing(self, key, uri)
@@ -1225,7 +1130,7 @@

Parameters

The URI which is no longer accessible
-
+
def geturls(self, key, prefix)
@@ -1249,7 +1154,7 @@

Raises

If git-annex does not respond correctly to this request, which is very unlikely.
-
+
def info(self, message)
@@ -1270,7 +1175,7 @@

Raises

If INFO is not available in this version of git-annex.
-
+
def getgitremotename(self)
@@ -1374,63 +1279,54 @@

AsyncRemote

+ + +
  • Protocol

  • Master

    - diff --git a/tests/test_GitAnnexRequestMessages.py b/tests/test_GitAnnexRequestMessages.py index 873ea88..8a61b28 100644 --- a/tests/test_GitAnnexRequestMessages.py +++ b/tests/test_GitAnnexRequestMessages.py @@ -12,103 +12,103 @@ class TestGitAnnexRequestMessages(utils.GitAnnexTestCase): def TestInitremoteSuccess(self): - self.annex.Listen(io.StringIO("INITREMOTE")) + self.master.Listen(io.StringIO("INITREMOTE")) self.remote.initremote.call_count == 1 self.assertEqual(utils.second_buffer_line(self.output), "INITREMOTE-SUCCESS") def TestInitremoteFailure(self): self.remote.initremote.side_effect = RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("INITREMOTE")) + self.master.Listen(io.StringIO("INITREMOTE")) self.remote.initremote.call_count == 1 self.assertEqual(utils.second_buffer_line(self.output), "INITREMOTE-FAILURE ErrorMsg") def TestExtensions(self): - self.annex.Listen(io.StringIO("EXTENSIONS Annex1 Annex2")) + self.master.Listen(io.StringIO("EXTENSIONS Annex1 Annex2")) self.assertEqual(utils.second_buffer_line(self.output), "EXTENSIONS") def TestPrepareSuccess(self): - self.annex.Listen(io.StringIO("PREPARE")) + self.master.Listen(io.StringIO("PREPARE")) self.remote.prepare.call_count == 1 self.assertEqual(utils.second_buffer_line(self.output), "PREPARE-SUCCESS") def TestPrepareFailure(self): self.remote.prepare.side_effect = RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("PREPARE")) + self.master.Listen(io.StringIO("PREPARE")) self.remote.prepare.call_count == 1 self.assertEqual(utils.second_buffer_line(self.output), "PREPARE-FAILURE ErrorMsg") def TestTransferStoreSuccess(self): - self.annex.Listen(io.StringIO("TRANSFER STORE Key File")) + self.master.Listen(io.StringIO("TRANSFER STORE Key File")) self.remote.transfer_store.assert_called_once_with("Key", "File") self.assertEqual(utils.second_buffer_line(self.output), "TRANSFER-SUCCESS STORE Key") def TestTransferStoreFailure(self): self.remote.transfer_store.side_effect = RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("TRANSFER STORE Key File")) + self.master.Listen(io.StringIO("TRANSFER STORE Key File")) self.remote.transfer_store.assert_called_once_with("Key", "File") self.assertEqual(utils.second_buffer_line(self.output), "TRANSFER-FAILURE STORE Key ErrorMsg") def TestTransferStoreMissingFilename(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("TRANSFER STORE Key")) + self.master.Listen(io.StringIO("TRANSFER STORE Key")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Expected Key File") def TestTransferStore_SpaceInFilename(self): - self.annex.Listen(io.StringIO("TRANSFER STORE Key File with spaces")) + self.master.Listen(io.StringIO("TRANSFER STORE Key File with spaces")) self.remote.transfer_store.assert_called_once_with("Key", "File with spaces") def TestTransferRetrieveSuccess(self): - self.annex.Listen(io.StringIO("TRANSFER RETRIEVE Key File")) + self.master.Listen(io.StringIO("TRANSFER RETRIEVE Key File")) self.remote.transfer_retrieve.assert_called_once_with("Key", "File") self.assertEqual(utils.second_buffer_line(self.output), "TRANSFER-SUCCESS RETRIEVE Key") def TestTransferRetrieveFailure(self): self.remote.transfer_retrieve.side_effect = RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("TRANSFER RETRIEVE Key File")) + self.master.Listen(io.StringIO("TRANSFER RETRIEVE Key File")) self.remote.transfer_retrieve.assert_called_once_with("Key", "File") self.assertEqual(utils.second_buffer_line(self.output), "TRANSFER-FAILURE RETRIEVE Key ErrorMsg") def TestTransferRetrieve_MissingFilename(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("TRANSFER RETRIEVE Key")) + self.master.Listen(io.StringIO("TRANSFER RETRIEVE Key")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Expected Key File") def TestTransferRetrieve_SpaceInFilename(self): - self.annex.Listen(io.StringIO("TRANSFER RETRIEVE Key File with spaces")) + self.master.Listen(io.StringIO("TRANSFER RETRIEVE Key File with spaces")) self.remote.transfer_retrieve.assert_called_once_with("Key", "File with spaces") def TestCheckpresentSuccess(self): self.remote.checkpresent.return_value = True - self.annex.Listen(io.StringIO("CHECKPRESENT Key")) + self.master.Listen(io.StringIO("CHECKPRESENT Key")) self.remote.checkpresent.assert_called_once_with("Key") self.assertEqual(utils.second_buffer_line(self.output), "CHECKPRESENT-SUCCESS Key") def TestCheckpresentFailure(self): self.remote.checkpresent.return_value = False - self.annex.Listen(io.StringIO("CHECKPRESENT Key")) + self.master.Listen(io.StringIO("CHECKPRESENT Key")) self.remote.checkpresent.assert_called_once_with("Key") self.assertEqual(utils.second_buffer_line(self.output), "CHECKPRESENT-FAILURE Key") def TestCheckpresentUnknown(self): self.remote.checkpresent.side_effect = RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("CHECKPRESENT Key")) + self.master.Listen(io.StringIO("CHECKPRESENT Key")) self.remote.checkpresent.assert_called_once_with("Key") self.assertEqual(utils.second_buffer_line(self.output), "CHECKPRESENT-UNKNOWN Key ErrorMsg") def TestRemoveSuccess(self): - self.annex.Listen(io.StringIO("REMOVE Key")) + self.master.Listen(io.StringIO("REMOVE Key")) self.remote.remove.assert_called_once_with("Key") self.assertEqual(utils.second_buffer_line(self.output), "REMOVE-SUCCESS Key") def TestRemoveFailure(self): self.remote.remove.side_effect = RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("REMOVE Key")) + self.master.Listen(io.StringIO("REMOVE Key")) self.remote.remove.assert_called_once_with("Key") self.assertEqual(utils.second_buffer_line(self.output), "REMOVE-FAILURE Key ErrorMsg") def TestListconfigs(self): self.remote.listconfigs.return_value = {'Name': 'Description', 'con1': "necessary configuration", 'opt': "optional configuration"} - self.annex.Listen(io.StringIO("LISTCONFIGS")) + self.master.Listen(io.StringIO("LISTCONFIGS")) self.assertEqual(self.remote.listconfigs.call_count, 1) self.assertEqual(utils.buffer_lines(self.output)[1:], ['CONFIG Name Description', @@ -119,83 +119,83 @@ def TestListconfigs(self): def TestListconfigsSpaceInName(self): self.remote.listconfigs.return_value = {'Name with space': 'Description'} with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("LISTCONFIGS")) + self.master.Listen(io.StringIO("LISTCONFIGS")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Name must not contain space characters: Name with space") def TestGetcost(self): self.remote.getcost.return_value = 5 - self.annex.Listen(io.StringIO("GETCOST")) + self.master.Listen(io.StringIO("GETCOST")) self.remote.getcost.call_count == 1 self.assertEqual(utils.second_buffer_line(self.output), "COST 5") def TestGetcostInvalid(self): self.remote.getcost.return_value = "not a number" with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("GETCOST")) + self.master.Listen(io.StringIO("GETCOST")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Cost must be an integer") def TestGetavailabilityGlobal(self): self.remote.getavailability.return_value = "global" - self.annex.Listen(io.StringIO("GETAVAILABILITY")) + self.master.Listen(io.StringIO("GETAVAILABILITY")) self.remote.getavailability.call_count == 1 self.assertEqual(utils.second_buffer_line(self.output), "AVAILABILITY GLOBAL") def TestGetavailabilityLocal(self): self.remote.getavailability.return_value = "local" - self.annex.Listen(io.StringIO("GETAVAILABILITY")) + self.master.Listen(io.StringIO("GETAVAILABILITY")) self.remote.getavailability.call_count == 1 self.assertEqual(utils.second_buffer_line(self.output), "AVAILABILITY LOCAL") def TestGetavailabilityInvalid(self): self.remote.getavailability.return_value = "something else" with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("GETAVAILABILITY")) + self.master.Listen(io.StringIO("GETAVAILABILITY")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Availability must be either 'global' or 'local'") def TestClaimurlSuccess(self): self.remote.claimurl.return_value = True - self.annex.Listen(io.StringIO("CLAIMURL Url")) + self.master.Listen(io.StringIO("CLAIMURL Url")) self.remote.claimurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CLAIMURL-SUCCESS") def TestClaimurlFailure(self): self.remote.claimurl.return_value = False - self.annex.Listen(io.StringIO("CLAIMURL Url")) + self.master.Listen(io.StringIO("CLAIMURL Url")) self.assertEqual(utils.second_buffer_line(self.output), "CLAIMURL-FAILURE") def TestCheckurlContentsTrue(self): self.remote.checkurl.return_value = True - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-CONTENTS UNKNOWN") def TestCheckurlContents(self): self.remote.checkurl.return_value = [{'size':512,'filename':"Filename"}] - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-CONTENTS 512 Filename") def TestCheckurlContentsUnknownSize(self): self.remote.checkurl.return_value = [{'filename':"Filename"}] - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-CONTENTS UNKNOWN Filename") def TestCheckurlContentsWithoutFilename(self): self.remote.checkurl.return_value = [{'size':512}] - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-CONTENTS 512") def TestCheckurlContentsWithoutSizeAndFilename(self): self.remote.checkurl.return_value = True - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-CONTENTS UNKNOWN") def TestCheckurlMultiOneItemWithUrl(self): self.remote.checkurl.return_value = [{'url':"Url_exact", 'size':512,'filename':"Filename"}] - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-MULTI Url_exact 512 Filename") @@ -203,7 +203,7 @@ def TestCheckurlMultiTwoUrls(self): urllist = [{'url':"Url1", 'size':512, 'filename':"Filename1"}, {'url':"Url2", 'filename':"Filename2"}] self.remote.checkurl.return_value = urllist - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-MULTI Url1 512 Filename1 Url2 UNKNOWN Filename2") @@ -214,7 +214,7 @@ def TestCheckurlMultiFiveUrls(self): {'url':"Url4", 'size':134789,'filename':"Filename4"}, {'url':"Url5", 'filename':"Filename5"}] self.remote.checkurl.return_value = urllist - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-MULTI Url1 512 Filename1 Url2 UNKNOWN Filename2 Url3 1024 Url4 134789 Filename4 Url5 UNKNOWN Filename5") @@ -223,7 +223,7 @@ def TestCheckurlMultiSpaceInUrl(self): {'url':"Url2",'filename':"Filename2"}] self.remote.checkurl.return_value = urllist with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Url must not contain spaces.") @@ -232,44 +232,44 @@ def TestCheckurlMultiSpaceInFilename(self): {'url':"Url2", 'filename':"Filename2"}] self.remote.checkurl.return_value = urllist with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Filename must not contain spaces.") def TestCheckurlMultiTabInUrlAndFilename(self): urllist = [{'url':"Url\twith\ttabs", 'size':512, 'filename':"Filename1"}, {'url':"Url2",'filename':"Filename\twith\ttabs"}] self.remote.checkurl.return_value = urllist - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) result = "CHECKURL-MULTI Url\twith\ttabs 512 Filename1 Url2 UNKNOWN Filename\twith\ttabs" self.assertEqual(utils.second_buffer_line(self.output), result) def TestCheckurlFailure(self): self.remote.checkurl.side_effect = RemoteError() - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-FAILURE") def TestCheckurlFailureByException(self): self.remote.checkurl.return_value = False - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.remote.checkurl.assert_called_once_with("Url") self.assertEqual(utils.second_buffer_line(self.output), "CHECKURL-FAILURE") def TestWhereisSuccess(self): self.remote.whereis.return_value = "String" - self.annex.Listen(io.StringIO("WHEREIS Key")) + self.master.Listen(io.StringIO("WHEREIS Key")) self.remote.whereis.assert_called_once_with("Key") self.assertEqual(utils.second_buffer_line(self.output), "WHEREIS-SUCCESS String") def TestWhereisFailure(self): self.remote.whereis.return_value = False - self.annex.Listen(io.StringIO("WHEREIS Key")) + self.master.Listen(io.StringIO("WHEREIS Key")) self.remote.whereis.assert_called_once_with("Key") self.assertEqual(utils.second_buffer_line(self.output), "WHEREIS-FAILURE") def TestGetinfo(self): self.remote.info = {'info field 1': 'infovalue', 'info field 2':'infovalue 2'} - self.annex.Listen(io.StringIO("GETINFO")) + self.master.Listen(io.StringIO("GETINFO")) self.assertEqual(utils.buffer_lines(self.output)[1:], ['INFOFIELD info field 1', 'INFOVALUE infovalue', @@ -280,228 +280,228 @@ def TestGetinfo(self): def TestGetinfoNone(self): self.remote.info = {} - self.annex.Listen(io.StringIO("GETINFO")) + self.master.Listen(io.StringIO("GETINFO")) self.assertEqual(utils.buffer_lines(self.output)[1:], ["INFOEND"]) def TestError(self): - self.annex.Listen(io.StringIO("ERROR ErrorMsg")) + self.master.Listen(io.StringIO("ERROR ErrorMsg")) self.remote.error.assert_called_once_with("ErrorMsg") class TestGitAnnexRequestMessagesExporttree(utils.GitAnnexTestCase): def TestExportsupportedSuccess(self): - self.annex.Listen(io.StringIO("EXPORTSUPPORTED")) + self.master.Listen(io.StringIO("EXPORTSUPPORTED")) self.remote.exportsupported.call_count == 1 self.assertEqual(utils.second_buffer_line(self.output), "EXPORTSUPPORTED-SUCCESS") def TestExportsupportedFailure(self): self.remote.exportsupported.return_value = False - self.annex.Listen(io.StringIO("EXPORTSUPPORTED")) + self.master.Listen(io.StringIO("EXPORTSUPPORTED")) self.remote.exportsupported.call_count == 1 self.assertEqual(utils.second_buffer_line(self.output), "EXPORTSUPPORTED-FAILURE") def TestExport_MissingName(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("EXPORT")) + self.master.Listen(io.StringIO("EXPORT")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR do_EXPORT() missing 1 required positional argument: 'name'") def TestExport_SpaceInName(self): # testing this only with TRANSFEREXPORT - self.annex.Listen(io.StringIO("EXPORT Name with spaces\nTRANSFEREXPORT STORE Key File")) + self.master.Listen(io.StringIO("EXPORT Name with spaces\nTRANSFEREXPORT STORE Key File")) self.remote.transferexport_store.assert_called_once_with("Key", "File", "Name with spaces") def TestTransferexportStoreSuccess(self): - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key File")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key File")) self.remote.transferexport_store.assert_called_once_with("Key", "File", "Name") self.assertEqual(utils.second_buffer_line(self.output), "TRANSFER-SUCCESS STORE Key") def TestTransferexportStoreFailure(self): self.remote.transferexport_store.side_effect = RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key File")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key File")) self.remote.transferexport_store.assert_called_once_with("Key", "File", "Name") self.assertEqual(utils.second_buffer_line(self.output), "TRANSFER-FAILURE STORE Key ErrorMsg") def TestTransferexportStore_WithoutExport(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("TRANSFEREXPORT STORE Key")) + self.master.Listen(io.StringIO("TRANSFEREXPORT STORE Key")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Export request without prior EXPORT") def TestTransferexportStore_MissingFilename(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Expected Key File") def TestTransferexportStore_SpaceInFilename(self): - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key File with spaces")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key File with spaces")) self.remote.transferexport_store.assert_called_once_with("Key", "File with spaces", "Name") def TestTransferexportStore_SpecialCharacterInName(self): - self.annex.Listen(io.StringIO("EXPORT Näme\nTRANSFEREXPORT STORE Key File with spaces")) + self.master.Listen(io.StringIO("EXPORT Näme\nTRANSFEREXPORT STORE Key File with spaces")) self.remote.transferexport_store.assert_called_once_with("Key", "File with spaces", "Näme") def TestTransferexportStore_UnicodeCharacterInName(self): - self.annex.Listen(io.StringIO("EXPORT Name 😀\nTRANSFEREXPORT STORE Key File with spaces")) + self.master.Listen(io.StringIO("EXPORT Name 😀\nTRANSFEREXPORT STORE Key File with spaces")) self.remote.transferexport_store.assert_called_once_with("Key", "File with spaces", "Name 😀") def TestTransferexportRetrieveSuccess(self): - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key File")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key File")) self.remote.transferexport_retrieve.assert_called_once_with("Key", "File", "Name") self.assertEqual(utils.second_buffer_line(self.output), "TRANSFER-SUCCESS RETRIEVE Key") def TestTransferexportRetrieveFailure(self): self.remote.transferexport_retrieve.side_effect = RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key File")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key File")) self.remote.transferexport_retrieve.assert_called_once_with("Key", "File", "Name") self.assertEqual(utils.second_buffer_line(self.output), "TRANSFER-FAILURE RETRIEVE Key ErrorMsg") def TestTransferexportRetrieve_WithoutExport(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("TRANSFEREXPORT RETRIEVE Key")) + self.master.Listen(io.StringIO("TRANSFEREXPORT RETRIEVE Key")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Export request without prior EXPORT") def TestTransferexportRetrieve_MissingFilename(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Expected Key File") def TestTransferexportRetrieve_SpaceInFilename(self): - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key File with spaces")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key File with spaces")) self.remote.transferexport_retrieve.assert_called_once_with("Key", "File with spaces", "Name") def TestCheckpresentexportSuccess(self): self.remote.checkpresentexport.return_value = True - self.annex.Listen(io.StringIO("EXPORT Name\nCHECKPRESENTEXPORT Key")) + self.master.Listen(io.StringIO("EXPORT Name\nCHECKPRESENTEXPORT Key")) self.remote.checkpresentexport.assert_called_once_with("Key", "Name") self.assertEqual(utils.second_buffer_line(self.output), "CHECKPRESENT-SUCCESS Key") def TestCheckpresentexportFailure(self): self.remote.checkpresentexport.return_value = False - self.annex.Listen(io.StringIO("EXPORT Name\nCHECKPRESENTEXPORT Key")) + self.master.Listen(io.StringIO("EXPORT Name\nCHECKPRESENTEXPORT Key")) self.remote.checkpresentexport.assert_called_once_with("Key", "Name") self.assertEqual(utils.second_buffer_line(self.output), "CHECKPRESENT-FAILURE Key") def TestCheckpresentexportUnknown(self): self.remote.checkpresentexport.side_effect=RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("EXPORT Name\nCHECKPRESENTEXPORT Key")) + self.master.Listen(io.StringIO("EXPORT Name\nCHECKPRESENTEXPORT Key")) self.remote.checkpresentexport.assert_called_once_with("Key", "Name") self.assertEqual(utils.second_buffer_line(self.output), "CHECKPRESENT-UNKNOWN Key ErrorMsg") def TestCheckpresentexport_WithoutExport(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("CHECKPRESENTEXPORT Key")) + self.master.Listen(io.StringIO("CHECKPRESENTEXPORT Key")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Export request without prior EXPORT") def TestRemoveexportSuccess(self): - self.annex.Listen(io.StringIO("EXPORT Name\nREMOVEEXPORT Key")) + self.master.Listen(io.StringIO("EXPORT Name\nREMOVEEXPORT Key")) self.remote.removeexport.assert_called_once_with("Key", "Name") self.assertEqual(utils.second_buffer_line(self.output), "REMOVE-SUCCESS Key") def TestRemoveexportFailure(self): self.remote.removeexport.side_effect = RemoteError("ErrorMsg") - self.annex.Listen(io.StringIO("EXPORT Name\nREMOVEEXPORT Key")) + self.master.Listen(io.StringIO("EXPORT Name\nREMOVEEXPORT Key")) self.remote.removeexport.assert_called_once_with("Key", "Name") self.assertEqual(utils.second_buffer_line(self.output), "REMOVE-FAILURE Key ErrorMsg") def TestRemoveexport_WithoutExport(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("REMOVEEXPORT Key")) + self.master.Listen(io.StringIO("REMOVEEXPORT Key")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Export request without prior EXPORT") def TestRemoveexportdirectorySuccess(self): - self.annex.Listen(io.StringIO("REMOVEEXPORTDIRECTORY Directory")) + self.master.Listen(io.StringIO("REMOVEEXPORTDIRECTORY Directory")) self.remote.removeexportdirectory.assert_called_once_with("Directory") self.assertEqual(utils.second_buffer_line(self.output), "REMOVEEXPORTDIRECTORY-SUCCESS") def TestRemoveexportdirectoryFailure(self): self.remote.removeexportdirectory.side_effect = RemoteError() - self.annex.Listen(io.StringIO("REMOVEEXPORTDIRECTORY Directory")) + self.master.Listen(io.StringIO("REMOVEEXPORTDIRECTORY Directory")) self.remote.removeexportdirectory.assert_called_once_with("Directory") self.assertEqual(utils.second_buffer_line(self.output), "REMOVEEXPORTDIRECTORY-FAILURE") def TestRemoveexportdirectory_MissingDirectory(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("REMOVEEXPORTDIRECTORY")) + self.master.Listen(io.StringIO("REMOVEEXPORTDIRECTORY")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR do_REMOVEEXPORTDIRECTORY() missing 1 required positional argument: 'name'") def TestRemoveexportdirectory_SpaceInFilename(self): - self.annex.Listen(io.StringIO("REMOVEEXPORTDIRECTORY Directory with spaces")) + self.master.Listen(io.StringIO("REMOVEEXPORTDIRECTORY Directory with spaces")) self.remote.removeexportdirectory.assert_called_once_with("Directory with spaces") def TestRenameexportSuccess(self): - self.annex.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key NewName")) + self.master.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key NewName")) self.remote.renameexport.assert_called_once_with("Key", "Name", "NewName") self.assertEqual(utils.second_buffer_line(self.output), "RENAMEEXPORT-SUCCESS Key") def TestRenameexportFailure(self): self.remote.renameexport.side_effect = RemoteError() - self.annex.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key NewName")) + self.master.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key NewName")) self.remote.renameexport.assert_called_once_with("Key", "Name", "NewName") self.assertEqual(utils.second_buffer_line(self.output), "RENAMEEXPORT-FAILURE Key") def TestRenameexport_WithoutExport(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("RENAMEEXPORT Key NewName")) + self.master.Listen(io.StringIO("RENAMEEXPORT Key NewName")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Export request without prior EXPORT") def TestRenameexport_MissingNewName(self): with self.assertRaises(SystemExit): - self.annex.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key")) + self.master.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key")) self.assertEqual(utils.last_buffer_line(self.output), "ERROR Expected TRANSFER STORE Key File") def TestRenameexport_SpaceInNewName(self): - self.annex.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key NewName with spaces")) + self.master.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key NewName with spaces")) self.remote.renameexport.assert_called_once_with("Key", "Name", "NewName with spaces") class TestUnsupportedRequests(utils.MinimalTestCase): def TestUnsupportedRequest(self): - self.annex.Listen(io.StringIO("Not a request")) + self.master.Listen(io.StringIO("Not a request")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestGetcostUnsupportedRequest(self): - self.annex.Listen(io.StringIO("GETCOST")) + self.master.Listen(io.StringIO("GETCOST")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestGetavailabilityUnsupportedRequest(self): - self.annex.Listen(io.StringIO("GETAVAILABILITY")) + self.master.Listen(io.StringIO("GETAVAILABILITY")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestClaimurlUnsupportedRequest(self): - self.annex.Listen(io.StringIO("CLAIMURL Url")) + self.master.Listen(io.StringIO("CLAIMURL Url")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestCheckurlUnsupportedRequest(self): - self.annex.Listen(io.StringIO("CHECKURL Url")) + self.master.Listen(io.StringIO("CHECKURL Url")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestWhereisUnsupportedRequest(self): - self.annex.Listen(io.StringIO("WHEREIS Key")) + self.master.Listen(io.StringIO("WHEREIS Key")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestTransferexportStoreUnsupportedRequest(self): - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key File")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT STORE Key File")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestTransferexportRetrieveUnsupportedRequest(self): - self.annex.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key File")) + self.master.Listen(io.StringIO("EXPORT Name\nTRANSFEREXPORT RETRIEVE Key File")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestCheckpresentexportUnsupportedRequest(self): - self.annex.Listen(io.StringIO("EXPORT Name\nCHECKPRESENTEXPORT Key")) + self.master.Listen(io.StringIO("EXPORT Name\nCHECKPRESENTEXPORT Key")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestRemoveexportUnsupportedRequest(self): - self.annex.Listen(io.StringIO("EXPORT Name\nREMOVEEXPORT Key")) + self.master.Listen(io.StringIO("EXPORT Name\nREMOVEEXPORT Key")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestRemoveexportdirectoryUnsupportedRequest(self): - self.annex.Listen(io.StringIO("REMOVEEXPORTDIRECTORY Directory")) + self.master.Listen(io.StringIO("REMOVEEXPORTDIRECTORY Directory")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestRenameexportUnsupportedRequest(self): - self.annex.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key NewName")) + self.master.Listen(io.StringIO("EXPORT Name\nRENAMEEXPORT Key NewName")) self.assertEqual(utils.second_buffer_line(self.output), "UNSUPPORTED-REQUEST") def TestListconfigsEmpty(self): - self.annex.Listen(io.StringIO("LISTCONFIGS")) + self.master.Listen(io.StringIO("LISTCONFIGS")) self.assertEqual(utils.second_buffer_line(self.output), "CONFIGEND") @@ -517,13 +517,13 @@ def prepare(self): class TestLogging(utils.GitAnnexTestCase): def setUp(self): super().setUp() - self.remote = LoggingRemote(self.annex) + self.remote = LoggingRemote(self.master) - self.annex.LinkRemote(self.remote) + self.master.LinkRemote(self.remote) def TestLogging(self): - self.annex.Listen(io.StringIO("PREPARE")) + self.master.Listen(io.StringIO("PREPARE")) buffer_lines = utils.buffer_lines(self.output) diff --git a/tests/test_SpecialRemoteMessages.py b/tests/test_SpecialRemoteMessages.py index 14f3692..df73583 100644 --- a/tests/test_SpecialRemoteMessages.py +++ b/tests/test_SpecialRemoteMessages.py @@ -13,7 +13,7 @@ class TestSpecialRemoteMessages(utils.GitAnnexTestCase): def _perform_test(self, function_to_call, function_parameters, expected_output, annex_reply=None, function_result=None, skip_assertion=False): - self.annex.input = io.StringIO(annex_reply) + self.master.input = io.StringIO(annex_reply) result = function_to_call(*function_parameters) self.assertEqual(result, function_result) if not skip_assertion: @@ -21,24 +21,24 @@ def _perform_test(self, function_to_call, function_parameters, expected_output, def TestVersion(self): - self.annex.Listen(self.input) + self.master.Listen(self.input) self.assertEqual(self.output.getvalue(), "VERSION 1\n") def TestProgress(self): - function_to_call = self.annex.progress + function_to_call = self.remote.annex.progress function_parameters = (2048,) expected_output = "PROGRESS 2048" self._perform_test(function_to_call, function_parameters, expected_output) def TestProgressNotANumber(self): - function_to_call = self.annex.progress + function_to_call = self.remote.annex.progress function_parameters = ("NaN",) with self.assertRaises(ValueError): self._perform_test(function_to_call, function_parameters, "") def TestDirhash(self): - function_to_call = self.annex.dirhash + function_to_call = self.remote.annex.dirhash function_parameters = ("Key",) expected_output = "DIRHASH Key" annex_reply = "VALUE aB/Cd" @@ -48,7 +48,7 @@ def TestDirhash(self): annex_reply, function_result) def TestDirhashLower(self): - function_to_call = self.annex.dirhash_lower + function_to_call = self.remote.annex.dirhash_lower function_parameters = ("Key",) expected_output = "DIRHASH-LOWER Key" annex_reply = "VALUE abc/def" @@ -58,7 +58,7 @@ def TestDirhashLower(self): annex_reply, function_result) def TestSetconfig(self): - function_to_call = self.annex.setconfig + function_to_call = self.remote.annex.setconfig function_parameters = ("Setting", "Value") expected_output = "SETCONFIG Setting Value" @@ -68,14 +68,14 @@ def TestSetconfig_SpaceInValue(self): """ The last parameter may contain spaces. """ - function_to_call = self.annex.setconfig + function_to_call = self.remote.annex.setconfig function_parameters = ("Setting", "Value with spaces") expected_output = "SETCONFIG Setting Value with spaces" self._perform_test(function_to_call, function_parameters, expected_output) def TestGetconfig(self): - function_to_call = self.annex.getconfig + function_to_call = self.remote.annex.getconfig function_parameters = ("Setting",) expected_output = "GETCONFIG Setting" annex_reply = "VALUE Value" @@ -85,7 +85,7 @@ def TestGetconfig(self): annex_reply, function_result) def TestGetconfig_SpaceInValue(self): - function_to_call = self.annex.getconfig + function_to_call = self.remote.annex.getconfig function_parameters = ("Setting",) expected_output = "GETCONFIG Setting" annex_reply = "VALUE Value with spaces" @@ -95,20 +95,20 @@ def TestGetconfig_SpaceInValue(self): annex_reply, function_result) def TestSetcreds(self): - function_to_call = self.annex.setcreds + function_to_call = self.remote.annex.setcreds function_parameters = ("Setting", "User", "Password") expected_output = "SETCREDS Setting User Password" self._perform_test(function_to_call, function_parameters, expected_output) def TestSetcreds_SpaceInPassword(self): - function_to_call = self.annex.setcreds + function_to_call = self.remote.annex.setcreds function_parameters = ("Setting", "User", "Password with spaces") expected_output = "SETCREDS Setting User Password with spaces" self._perform_test(function_to_call, function_parameters, expected_output) def TestSetcreds_NoPassword(self): - function_to_call = self.annex.setcreds + function_to_call = self.remote.annex.setcreds function_parameters = ("Setting", "User", "") expected_output = "SETCREDS Setting User" @@ -118,14 +118,14 @@ def TestSetcreds_NoUser(self): """ Parameters may be empty, but the separating spaces are still required in that case. """ - function_to_call = self.annex.setcreds + function_to_call = self.remote.annex.setcreds function_parameters = ("Setting", "", "Password") expected_output = "SETCREDS Setting Password" self._perform_test(function_to_call, function_parameters, expected_output) def TestGetcreds(self): - function_to_call = self.annex.getcreds + function_to_call = self.remote.annex.getcreds function_parameters = ("Setting",) expected_output = "GETCREDS Setting" annex_reply = "CREDS User Password" @@ -135,7 +135,7 @@ def TestGetcreds(self): annex_reply, function_result) def TestGetcreds_SpaceInPassword(self): - function_to_call = self.annex.getcreds + function_to_call = self.remote.annex.getcreds function_parameters = ("Setting",) expected_output = "GETCREDS Setting" annex_reply = "CREDS User Password with spaces" @@ -145,7 +145,7 @@ def TestGetcreds_SpaceInPassword(self): annex_reply, function_result) def TestGetcreds_NoPassword(self): - function_to_call = self.annex.getcreds + function_to_call = self.remote.annex.getcreds function_parameters = ("Setting",) expected_output = "GETCREDS Setting" annex_reply = "CREDS User" @@ -155,7 +155,7 @@ def TestGetcreds_NoPassword(self): annex_reply, function_result) def TestGetcreds_NoUser(self): - function_to_call = self.annex.getcreds + function_to_call = self.remote.annex.getcreds function_parameters = ("Setting",) expected_output = "GETCREDS Setting" annex_reply = "CREDS Password" @@ -165,7 +165,7 @@ def TestGetcreds_NoUser(self): annex_reply, function_result) def TestGetuuid(self): - function_to_call = self.annex.getuuid + function_to_call = self.remote.annex.getuuid function_parameters = () expected_output = "GETUUID" annex_reply = "VALUE uuid" @@ -175,7 +175,7 @@ def TestGetuuid(self): annex_reply, function_result) def TestGetgitdir(self): - function_to_call = self.annex.getgitdir + function_to_call = self.remote.annex.getgitdir function_parameters = () expected_output = "GETGITDIR" annex_reply = "VALUE /path/to/gitdir" @@ -185,7 +185,7 @@ def TestGetgitdir(self): annex_reply, function_result) def TestGetgitdir_SpaceInPath(self): - function_to_call = self.annex.getgitdir + function_to_call = self.remote.annex.getgitdir function_parameters = () expected_output = "GETGITDIR" annex_reply = "VALUE /path/to/gitdir with spaces/" @@ -194,14 +194,14 @@ def TestGetgitdir_SpaceInPath(self): self._perform_test(function_to_call, function_parameters, expected_output, annex_reply, function_result) def TestSetwanted(self): - function_to_call = self.annex.setwanted + function_to_call = self.remote.annex.setwanted function_parameters = ("Preferred Content Expression",) expected_output = "SETWANTED Preferred Content Expression" self._perform_test(function_to_call, function_parameters, expected_output) def TestGetwanted(self): - function_to_call = self.annex.getwanted + function_to_call = self.remote.annex.getwanted function_parameters = () expected_output = "GETWANTED" annex_reply = "VALUE Preferred Content Expression" @@ -211,28 +211,28 @@ def TestGetwanted(self): annex_reply, function_result) def TestSetstate(self): - function_to_call = self.annex.setstate + function_to_call = self.remote.annex.setstate function_parameters = ("Key", "Value") expected_output = "SETSTATE Key Value" self._perform_test(function_to_call, function_parameters, expected_output) def TestSetstate_SpaceInValue(self): - function_to_call = self.annex.setstate + function_to_call = self.remote.annex.setstate function_parameters = ("Key", "Value with spaces") expected_output = "SETSTATE Key Value with spaces" self._perform_test(function_to_call, function_parameters, expected_output) def TestSetstate_NoValue(self): - function_to_call = self.annex.setstate + function_to_call = self.remote.annex.setstate function_parameters = ("Key", "") expected_output = "SETSTATE Key" self._perform_test(function_to_call, function_parameters, expected_output) def TestGetstate(self): - function_to_call = self.annex.getstate + function_to_call = self.remote.annex.getstate function_parameters = ("Key",) expected_output = "GETSTATE Key" annex_reply = "VALUE State" @@ -242,7 +242,7 @@ def TestGetstate(self): annex_reply, function_result) def TestGetstate_SpaceInValue(self): - function_to_call = self.annex.getstate + function_to_call = self.remote.annex.getstate function_parameters = ("Key",) expected_output = "GETSTATE Key" annex_reply = "VALUE State with spaces" @@ -252,7 +252,7 @@ def TestGetstate_SpaceInValue(self): annex_reply, function_result) def TestGetstate_NoValue(self): - function_to_call = self.annex.getstate + function_to_call = self.remote.annex.getstate function_parameters = ("Key",) expected_output = "GETSTATE Key" annex_reply = "VALUE" @@ -262,35 +262,35 @@ def TestGetstate_NoValue(self): annex_reply, function_result) def TestSeturlpresent(self): - function_to_call = self.annex.seturlpresent + function_to_call = self.remote.annex.seturlpresent function_parameters = ("Key", "Url") expected_output = "SETURLPRESENT Key Url" self._perform_test(function_to_call, function_parameters, expected_output) def TestSeturlmissing(self): - function_to_call = self.annex.seturlmissing + function_to_call = self.remote.annex.seturlmissing function_parameters = ("Key", "Url") expected_output = "SETURLMISSING Key Url" self._perform_test(function_to_call, function_parameters, expected_output) def TestSeturipresent(self): - function_to_call = self.annex.seturipresent + function_to_call = self.remote.annex.seturipresent function_parameters = ("Key", "Uri") expected_output = "SETURIPRESENT Key Uri" self._perform_test(function_to_call, function_parameters, expected_output) def TestSeturimissing(self): - function_to_call = self.annex.seturimissing + function_to_call = self.remote.annex.seturimissing function_parameters = ("Key", "Uri") expected_output = "SETURIMISSING Key Uri" self._perform_test(function_to_call, function_parameters, expected_output) def TestGeturls_0(self): - function_to_call = self.annex.geturls + function_to_call = self.remote.annex.geturls function_parameters = ("Key", "Prefix") expected_output = "GETURLS Key Prefix" annex_reply = "VALUE" @@ -300,7 +300,7 @@ def TestGeturls_0(self): annex_reply, function_result) def TestGeturls_1(self): - function_to_call = self.annex.geturls + function_to_call = self.remote.annex.geturls function_parameters = ("Key", "Prefix") expected_output = "GETURLS Key Prefix" annex_reply = "VALUE State1\nVALUE" @@ -310,7 +310,7 @@ def TestGeturls_1(self): annex_reply, function_result) def TestGeturls_2(self): - function_to_call = self.annex.geturls + function_to_call = self.remote.annex.geturls function_parameters = ("Key", "Prefix") expected_output = "GETURLS Key Prefix" annex_reply = "VALUE State1\nVALUE State2\nVALUE" @@ -320,7 +320,7 @@ def TestGeturls_2(self): annex_reply, function_result) def TestGeturls_2_empty_prefix(self): - function_to_call = self.annex.geturls + function_to_call = self.remote.annex.geturls function_parameters = ("Key", "") expected_output = "GETURLS Key" annex_reply = "VALUE State1\nVALUE State2\nVALUE" @@ -330,14 +330,14 @@ def TestGeturls_2_empty_prefix(self): annex_reply, function_result) def TestDebug(self): - function_to_call = self.annex.debug + function_to_call = self.remote.annex.debug function_parameters = ("message",) expected_output = "DEBUG message" self._perform_test(function_to_call, function_parameters, expected_output) def TestError(self): - function_to_call = self.annex.error + function_to_call = self.remote.annex.error function_parameters = ("ErrorMsg",) expected_output = "ERROR ErrorMsg" @@ -348,7 +348,7 @@ class TestSpecialRemoteMessages_Extensions(utils.GitAnnexTestCase): def _perform_test(self, function_to_call, function_parameters, expected_output, annex_reply=None, function_result=None): - self.annex.input = io.StringIO(annex_reply) + self.master.input = io.StringIO(annex_reply) result = function_to_call(*function_parameters) self.assertEqual(result, function_result) @@ -356,8 +356,8 @@ def _perform_test(self, function_to_call, function_parameters, expected_output, self.assertEqual(utils.buffer_lines(self.output)[2].rstrip(), expected_output) def TestInfo(self): - self.annex.Listen(io.StringIO("EXTENSIONS INFO")) - function_to_call = self.annex.info + self.master.Listen(io.StringIO("EXTENSIONS INFO")) + function_to_call = self.remote.annex.info function_parameters = ("message",) expected_output = "INFO message" @@ -365,14 +365,14 @@ def TestInfo(self): def TestInfo_Unannounced(self): - function_to_call = self.annex.info + function_to_call = self.remote.annex.info function_parameters = ("message",) with self.assertRaises(ProtocolError): self._perform_test(function_to_call, function_parameters, "") def TestGetgitremotename(self): - self.annex.Listen(io.StringIO("EXTENSIONS GETGITREMOTENAME")) - function_to_call = self.annex.getgitremotename + self.master.Listen(io.StringIO("EXTENSIONS GETGITREMOTENAME")) + function_to_call = self.remote.annex.getgitremotename function_parameters = () expected_output = "GETGITREMOTENAME" annex_reply = "VALUE nameofremote" @@ -383,7 +383,7 @@ def TestGetgitremotename(self): def TestGetgitremotename_Unannounced(self): - function_to_call = self.annex.getgitremotename + function_to_call = self.remote.annex.getgitremotename function_parameters = () with self.assertRaises(ProtocolError): self._perform_test(function_to_call, function_parameters, "") diff --git a/tests/utils.py b/tests/utils.py index c677003..55a96e3 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -15,10 +15,10 @@ def setUp(self): self.output = io.StringIO() self.input = io.StringIO() - self.annex = annexremote.Master(self.output) - self.remote = mock.MagicMock(wraps=DummyRemote(self.annex)) + self.master = annexremote.Master(self.output) + self.remote = mock.MagicMock(wraps=DummyRemote(self.master)) - self.annex.LinkRemote(self.remote) + self.master.LinkRemote(self.remote) class MinimalTestCase(unittest.TestCase): def setUp(self): @@ -27,10 +27,10 @@ def setUp(self): self.output = io.StringIO() self.input = io.StringIO() - self.annex = annexremote.Master(self.output) - self.remote = MinimalRemote(self.annex) + self.master = annexremote.Master(self.output) + self.remote = MinimalRemote(self.master) - self.annex.LinkRemote(self.remote) + self.master.LinkRemote(self.remote) def first_buffer_line(buf): return buffer_lines(buf)[0] From 601a6195214eb6212927e2d8ade5af475e52128a Mon Sep 17 00:00:00 2001 From: Silvio Ankermann Date: Fri, 29 Jan 2021 14:32:53 +0100 Subject: [PATCH 2/2] (WIP) Begin async --- annexremote/annexremote.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/annexremote/annexremote.py b/annexremote/annexremote.py index 59838b9..f4eb631 100644 --- a/annexremote/annexremote.py +++ b/annexremote/annexremote.py @@ -522,7 +522,14 @@ def renameexport(self, key, filename, new_filename): """ raise UnsupportedRequest() -class Protocol(object): +class AsyncRemote: + def __init__(self): + self.async_supported = True + + def getRemoteJob(self, job_number): + raise NotImplementedError + +class Protocol: """ Helper class handling the receiving part of the protocol (git-annex to remote) It parses the requests coming from git-annex and calls the respective @@ -538,6 +545,7 @@ def __init__(self, remote, master): self.version = "VERSION 1" self.exporting = False self.extensions = list() + self.jobs = {} def command(self, line): line = line.strip() @@ -564,6 +572,12 @@ def command(self, line): def lookupMethod(self, command): return getattr(self.request_messages, 'do_' + command.upper(), self.request_messages.do_UNKNOWN) + + def get_job(self, job_number: int) -> "Protocol": + if job_number not in self.jobs: + self.jobs[job_number] = Protocol(self.remote.getRemoteJob(job_number)) + return self.jobs[job_number] + def error(self, *args): self._send("ERROR", *args) @@ -624,8 +638,19 @@ def do_INITREMOTE(self): def do_EXTENSIONS(self, param): self.protocol.extensions = param.split(" ") - return "EXTENSIONS" + remote_extensions = [] + if hasattr(self.remote, "async_support") and \ + self.remote.async_support == True: + remote_extensions.append("ASYNC") + return ' '.join(["EXTENSIONS"] + remote_extensions) + def do_J(self, param): + try: + (job_number, command) = param.split(" ", 1) + except ValueError: + raise SyntaxError("Expected Jobnumber Command") + return self.protocol.get_job(job_number).command(command) + def do_PREPARE(self): try: self.remote.prepare()