[geary/mjog/imap-connection-fixes: 1/4] Geary.Imap.Command: Add throw_on_error method



commit 3c15004871f8b54cd2bad88f1d441600d4fe1b99
Author: Michael Gratton <mike vee net>
Date:   Thu Mar 26 22:20:45 2020 +1100

    Geary.Imap.Command: Add throw_on_error method
    
    Add method that checks the command's status response and throws an
    appropriate error if it indicates that something we care about is
    wrong.

 src/engine/imap/command/imap-command.vala       | 102 ++++++++++++++++++++++++
 test/engine/imap/command/imap-command-test.vala |  88 ++++++++++++++++++++
 test/meson.build                                |   1 +
 test/test-engine.vala                           |   1 +
 4 files changed, 192 insertions(+)
---
diff --git a/src/engine/imap/command/imap-command.vala b/src/engine/imap/command/imap-command.vala
index 58163671..322b18d2 100644
--- a/src/engine/imap/command/imap-command.vala
+++ b/src/engine/imap/command/imap-command.vala
@@ -271,6 +271,108 @@ public abstract class Geary.Imap.Command : BaseObject {
         }
     }
 
+    /**
+     * Throws an error if this command's status response is NO or BAD.
+     *
+     * If the response is NO, an ImapError.OPERATIONAL_ERROR is
+     * thrown. If the response is BAD, an ImapError.SERVER_ERROR is
+     * thrown. If a specific response code is set, another more
+     * appropriate exception may be thrown. The given command is used
+     * to provide additional context information in case an error is
+     * thrown.
+     */
+    public void throw_on_error() throws ImapError {
+        StatusResponse? response = this.status;
+        if (response != null && response.status in new Status[] { BAD, NO }) {
+            ResponseCode? code = response.response_code;
+            if (code != null) {
+                ResponseCodeType code_type = code.get_response_code_type();
+                switch (code_type.value) {
+                case ResponseCodeType.ALREADYEXISTS:
+                    throw new ImapError.SERVER_ERROR(
+                        "%s: Already exists: %s",
+                        to_brief_string(),
+                        response.to_string()
+                    );
+
+                case ResponseCodeType.AUTHENTICATIONFAILED:
+                    throw new ImapError.UNAUTHENTICATED(
+                        "%s: Bad credentials: %s",
+                        to_brief_string(),
+                        response.to_string()
+                    );
+
+                case ResponseCodeType.AUTHORIZATIONFAILED:
+                    throw new ImapError.SERVER_ERROR(
+                        "%s: Not authorised: %s",
+                        to_brief_string(),
+                        response.to_string()
+                    );
+
+                case ResponseCodeType.CANNOT:
+                    throw new ImapError.SERVER_ERROR(
+                        "%s: Cannot be performed: %s",
+                        to_brief_string(),
+                        response.to_string()
+                    );
+
+                case ResponseCodeType.LIMIT:
+                    throw new ImapError.SERVER_ERROR(
+                        "%s: Hit limit: %s",
+                        to_brief_string(),
+                        response.to_string()
+                    );
+
+                case ResponseCodeType.NOPERM:
+                    throw new ImapError.SERVER_ERROR(
+                        "%s: Not permitted by ACL: %s",
+                        to_brief_string(),
+                        response.to_string()
+                    );
+
+                case ResponseCodeType.NONEXISTENT:
+                    throw new ImapError.SERVER_ERROR(
+                        "%s: Does not exist: %s",
+                        to_brief_string(),
+                        response.to_string()
+                    );
+
+                case ResponseCodeType.OVERQUOTA:
+                    throw new ImapError.SERVER_ERROR(
+                        "%s: Over quota: %s",
+                        to_brief_string(),
+                        response.to_string()
+                    );
+
+                case ResponseCodeType.UNAVAILABLE:
+                    throw new ImapError.UNAVAILABLE(
+                        "%s: Server is unavailable: %s",
+                        to_brief_string(),
+                        response.to_string()
+                    );
+                }
+            }
+
+            // No interesting response code, so just throw a generic
+            // error
+            switch (response.status) {
+            case Status.NO:
+                throw new ImapError.OPERATIONAL_ERROR(
+                    "%s: Operational server error: %s",
+                    to_brief_string(),
+                    response.to_string()
+                );
+
+            case Status.BAD:
+                throw new ImapError.SERVER_ERROR(
+                    "%s: Fatal server error: %s",
+                    to_brief_string(),
+                    response.to_string()
+                );
+            }
+        }
+    }
+
     public virtual string to_string() {
         string args = this.args.to_string();
         return (Geary.String.is_empty(args))
diff --git a/test/engine/imap/command/imap-command-test.vala b/test/engine/imap/command/imap-command-test.vala
new file mode 100644
index 00000000..68705b1c
--- /dev/null
+++ b/test/engine/imap/command/imap-command-test.vala
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2020 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+class Geary.Imap.CommandTest : TestCase {
+
+
+    private class TestCommand : Command {
+
+        public TestCommand() {
+            base("TEST");
+        }
+
+    }
+
+
+    public CommandTest() {
+        base("Geary.Imap.CommandTest");
+        add_test("throw_on_error", throw_on_error);
+    }
+
+    public void throw_on_error() throws GLib.Error {
+        var test_article = newCompleteTestCommand(OK, null);
+        test_article.throw_on_error();
+
+        test_article = newCompleteTestCommand(NO, null);
+        try {
+            test_article.throw_on_error();
+            assert_not_reached();
+        } catch (ImapError.OPERATIONAL_ERROR err) {
+            // expected
+        }
+
+        test_article = newCompleteTestCommand(BAD, null);
+        try {
+            test_article.throw_on_error();
+            assert_not_reached();
+        } catch (ImapError.SERVER_ERROR err) {
+            // expected
+        }
+
+        test_article = newCompleteTestCommand(
+            NO, ResponseCodeType.AUTHENTICATIONFAILED
+        );
+        try {
+            test_article.throw_on_error();
+            assert_not_reached();
+        } catch (ImapError.UNAUTHENTICATED err) {
+            // expected
+        }
+
+        test_article = newCompleteTestCommand(
+            NO, ResponseCodeType.UNAVAILABLE
+        );
+        try {
+            test_article.throw_on_error();
+            assert_not_reached();
+        } catch (ImapError.UNAVAILABLE err) {
+            // expected
+        }
+    }
+
+    private Command newCompleteTestCommand(Status status,
+                                           string? response_code)
+        throws GLib.Error {
+        var command = new TestCommand();
+        command.assign_tag(new Tag("t001"));
+
+        ResponseCode? code = null;
+        if (response_code != null) {
+            code = new ResponseCode();
+            code.add(new AtomParameter(response_code));
+        }
+
+        try {
+            command.completed(new StatusResponse(command.tag, status, code));
+        } catch (ImapError.SERVER_ERROR err) {
+            if (status != BAD) {
+                throw err;
+            }
+        }
+        return command;
+    }
+
+}
diff --git a/test/meson.build b/test/meson.build
index 9cd4717f..86d7782d 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -36,6 +36,7 @@ geary_test_engine_sources = [
   'engine/common/common-contact-harvester-test.vala',
   'engine/db/db-database-test.vala',
   'engine/db/db-versioned-database-test.vala',
+  'engine/imap/command/imap-command-test.vala',
   'engine/imap/command/imap-create-command-test.vala',
   'engine/imap/command/imap-fetch-command-test.vala',
   'engine/imap/message/imap-data-format-test.vala',
diff --git a/test/test-engine.vala b/test/test-engine.vala
index a70cb11c..1826609f 100644
--- a/test/test-engine.vala
+++ b/test/test-engine.vala
@@ -50,6 +50,7 @@ int main(string[] args) {
     // Other IMAP tests rely on these working, so test them first
     engine.add_suite(new Geary.Imap.DataFormatTest().get_suite());
 
+    engine.add_suite(new Geary.Imap.CommandTest().get_suite());
     engine.add_suite(new Geary.Imap.CreateCommandTest().get_suite());
     engine.add_suite(new Geary.Imap.FetchCommandTest().get_suite());
     engine.add_suite(new Geary.Imap.ListParameterTest().get_suite());


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]