Merge ~woutervb/various/+git/snapstore-proxy-charm:status_action_test_refactor into ~woutervb/various/+git/snapstore-proxy-charm:main

Proposed by Wouter van Bommel
Status: Merged
Merged at revision: c78345aa91fe7b80e2d935ec334eaeb5409d8a9e
Proposed branch: ~woutervb/various/+git/snapstore-proxy-charm:status_action_test_refactor
Merge into: ~woutervb/various/+git/snapstore-proxy-charm:main
Prerequisite: ~woutervb/various/+git/snapstore-proxy-charm:freeze_after_registration
Diff against target: 219 lines (+78/-6)
7 files modified
Makefile (+1/-1)
README.md (+5/-1)
actions.yaml (+4/-1)
src/charm.py (+11/-0)
src/resource_helpers.py (+7/-0)
tests/test_charm.py (+32/-2)
tests/test_resource_helpers.py (+18/-1)
Reviewer Review Type Date Requested Status
Przemysław Suliga (community) Approve
Wouter van Bommel Pending
Review via email: mp+412990@code.launchpad.net

Commit message

Added status action and refactored test

Refactored test of the charm in logical subsets, to ease expansion and
keep grouped tests together.

Added an status action, that will return the result of the proxy status
command.

To post a comment you must log in.
Revision history for this message
Przemysław Suliga (suligap) wrote :

One comment

Revision history for this message
Wouter van Bommel (woutervb) wrote :

Added a reply.
Again, did a rebase etc to things make sense

Revision history for this message
Przemysław Suliga (suligap) wrote :

Thanks, +1 with a reply to the comment.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/Makefile b/Makefile
2index 24a72d4..bcd2827 100644
3--- a/Makefile
4+++ b/Makefile
5@@ -8,7 +8,7 @@ CHARMCRAFT = $(shell which charmcraft)
6 # Releases should match the run-on section in charmcraft.yaml in the same order
7 RELEASES = 20.04 18.04
8 CHARM_FILENAME = $(CHARM_NAME)$(subst $(noop) $(noop),,$(addsuffix -amd64, $(addprefix _ubuntu-, $(RELEASES)))).charm
9-DEPS = $(shell find src -name '*.py') requirements.txt
10+DEPS = $(shell find src -name '*.py') requirements.txt actions.yaml config.yaml
11
12 .PHONY: charm
13 charm: $(CHARM_FILENAME)
14diff --git a/README.md b/README.md
15index d3157fb..7881848 100644
16--- a/README.md
17+++ b/README.md
18@@ -6,11 +6,15 @@ This charm will allow the installation and management of the snapstore proxy cha
19
20 ## Usage
21
22-Minimal items that have to be set are an username / password, on ubuntu onethat correspond to an account that does not have 2fa enabled, and has accepted the developer agreement on snapstore.io.
23+Minimal items that have to be set are the domain this proxy runs on, and a username / password, on ubuntu one that correspond to an account that does not have 2fa enabled, and has accepted the developer agreement on snapstore.io.
24
25
26 ## Relations
27
28 This charm depends on a postgresql database, so this charm should relate to a porgresql database, before anything else can be done.
29
30+## Actions
31
32+The charm supports the following actions:
33+
34+ * status - Get the status result of the proxy, use like; `juju run-action snapstore-proxy/leader status --wait`
35diff --git a/actions.yaml b/actions.yaml
36index 1e74ed1..d97efbd 100644
37--- a/actions.yaml
38+++ b/actions.yaml
39@@ -2,5 +2,8 @@
40 # See LICENSE file for licensing details.
41 #
42 # Learn more about actions at: https://juju.is/docs/sdk/actions
43-
44+status:
45+ description: |
46+ Get the status of the proxy services, ie
47+ juju run-action snapstore-proxy/leader status --wait
48
49diff --git a/src/charm.py b/src/charm.py
50index b82eac9..419643a 100755
51--- a/src/charm.py
52+++ b/src/charm.py
53@@ -20,6 +20,7 @@ from helpers import all_config_options, configure_proxy, default_values
54 from optionvalidation import OptionValidation
55 from resource_helpers import (
56 create_database,
57+ get_status,
58 install_from_the_charmstore,
59 register_store,
60 snap_details,
61@@ -58,6 +59,9 @@ class SnapstoreProxyCharm(CharmBase):
62 self.db.on.database_relation_broken, self._on_database_relation_broken
63 )
64
65+ # Actions
66+ self.framework.observe(self.on.status_action, self._on_status_action)
67+
68 def _on_config_changed(self, event):
69 """Handle update on the configuration of the proxy.
70
71@@ -303,6 +307,13 @@ class SnapstoreProxyCharm(CharmBase):
72
73 self.evaluate_status()
74
75+ def _on_status_action(self, event):
76+ output, exitcode = get_status()
77+ if exitcode == 0:
78+ event.set_results({"result": output})
79+ else:
80+ event.fail(f"Failed to get status, errorcode {exitcode}\n, result {output}")
81+
82
83 if __name__ == "__main__":
84 main(SnapstoreProxyCharm)
85diff --git a/src/resource_helpers.py b/src/resource_helpers.py
86index 09cddc9..e5e9e76 100644
87--- a/src/resource_helpers.py
88+++ b/src/resource_helpers.py
89@@ -45,3 +45,10 @@ def register_store(username, password):
90 def create_database(uri):
91 """Let the proxy configure the database."""
92 run(["/snap/bin/snap-store-proxy", "create-database", uri])
93+
94+
95+def get_status():
96+ """Return the status result and exitcode"""
97+ result = run(["/snap/bin/snap-store-proxy", "status"], capture_output=True)
98+
99+ return result.stdout.decode("utf-8"), result.returncode
100diff --git a/tests/test_charm.py b/tests/test_charm.py
101index 6f58424..f89e6a0 100644
102--- a/tests/test_charm.py
103+++ b/tests/test_charm.py
104@@ -18,7 +18,7 @@ import exceptions
105 from charm import DATABASE_NAME, SnapstoreProxyCharm
106
107
108-class TestCharm:
109+class CharmTest:
110 def setup_method(self):
111 self.harness = Harness(SnapstoreProxyCharm)
112 self.harness.begin()
113@@ -32,6 +32,8 @@ class TestCharm:
114 def teardown_method(self):
115 self.harness.cleanup()
116
117+
118+class TestConfig(CharmTest):
119 def test_default_config_values(self):
120 # Our implicit requirement is that the database uri has been set.
121 self.harness.charm._stored.db_uri = "postgresql://fake/database"
122@@ -156,6 +158,8 @@ class TestCharm:
123 assert patched_proxy.called
124 patched_proxy.assert_called_once_with(None)
125
126+
127+class TestStatus(CharmTest):
128 def test_status_missing_db_uri(self):
129 self.harness.charm._stored.db_uri = None
130
131@@ -211,6 +215,8 @@ class TestCharm:
132
133 assert self.harness.charm.unit.status.message == ""
134
135+
136+class TestEvents(CharmTest):
137 def test_on_update_status(self):
138 self.harness.disable_hooks()
139 self.harness.set_leader(True)
140@@ -304,6 +310,28 @@ class TestCharm:
141 assert self.harness.charm._stored.db_uri is None
142 patched_evaluate_status.assert_called_once_with()
143
144+ def test_on_status_action_succeeds(self):
145+ event = MagicMock()
146+ with patch("charm.get_status") as patched_get_status:
147+ patched_get_status.return_value = ("String", 0)
148+ self.harness.charm._on_status_action(event)
149+
150+ patched_get_status.assert_called_once_with()
151+ event.set_results.assert_called_once_with({"result": "String"})
152+
153+ def test_on_status_action_fails(self):
154+ event = MagicMock()
155+ with patch("charm.get_status") as patched_get_status:
156+ patched_get_status.return_value = ("String", 1)
157+ self.harness.charm._on_status_action(event)
158+
159+ patched_get_status.assert_called_once_with()
160+ event.fail.assert_called_once_with(
161+ "Failed to get status, result String, errorcode 1"
162+ )
163+
164+
165+class TestRegistration(CharmTest):
166 def test_handle_registration_no_database(self, caplog):
167 caplog.clear()
168 caplog.set_level(logging.INFO)
169@@ -397,6 +425,8 @@ class TestCharm:
170 == "Failed to register, check logging to find the reason"
171 )
172
173+
174+class TestSanity(CharmTest):
175 def test_empty_username_after_registration_and_active_status(self):
176 self.harness.charm._stored.registered = True
177 self.harness.charm._stored.username = "Some value"
178@@ -409,7 +439,7 @@ class TestCharm:
179 assert self.harness.charm._stored.username == "Some value"
180 assert self.harness.charm.unit.status == ActiveStatus("")
181
182- def test_empty_password(self):
183+ def test_empty_password_after_registration_and_active_status(self):
184 self.harness.charm._stored.registered = True
185 self.harness.charm._stored.password = "Some value"
186 self.harness.charm._stored.db_uri = "postgresql://user@host/database"
187diff --git a/tests/test_resource_helpers.py b/tests/test_resource_helpers.py
188index eaf5b22..1db2005 100644
189--- a/tests/test_resource_helpers.py
190+++ b/tests/test_resource_helpers.py
191@@ -1,6 +1,6 @@
192 import logging
193 from subprocess import PIPE, CalledProcessError
194-from unittest.mock import patch
195+from unittest.mock import MagicMock, patch
196
197 import resource_helpers
198
199@@ -82,3 +82,20 @@ def test_create_database():
200 patched_run.assert_called_once_with(
201 ["/snap/bin/snap-store-proxy", "create-database", test_dsn]
202 )
203+
204+
205+def test_get_status():
206+ result = MagicMock()
207+ result.returncode = 10
208+ result.stdout = "My magic result".encode("utf-8")
209+
210+ with patch("resource_helpers.run") as patched_run:
211+ patched_run.return_value = result
212+ output, exitcode = resource_helpers.get_status()
213+
214+ assert patched_run.called
215+ patched_run.assert_called_once_with(
216+ ["/snap/bin/snap-store-proxy", "status"], capture_output=True
217+ )
218+ assert exitcode == 10
219+ assert output == "My magic result"

Subscribers

People subscribed via source and target branches

to all changes: