Merge lp:~bjornt/landscape-charm/leader-destroyed-integration-tests into lp:~landscape/landscape-charm/trunk

Proposed by Björn Tillenius
Status: Merged
Approved by: Björn Tillenius
Approved revision: 322
Merged at revision: 311
Proposed branch: lp:~bjornt/landscape-charm/leader-destroyed-integration-tests
Merge into: lp:~landscape/landscape-charm/trunk
Prerequisite: lp:~bjornt/landscape-charm/integration-tests-no-hardcode-unit
Diff against target: 170 lines (+96/-17)
4 files modified
tests/basic/test_ha.py (+1/-1)
tests/basic/test_leader.py (+47/-0)
tests/helpers.py (+32/-15)
tests/layers.py (+16/-1)
To merge this branch: bzr merge lp:~bjornt/landscape-charm/leader-destroyed-integration-tests
Reviewer Review Type Date Requested Status
Free Ekanayaka (community) Approve
Adam Collard (community) Approve
🤖 Landscape Builder test results Approve
Review via email: mp+261702@code.launchpad.net

Commit message

Add integration tests for when the landscape-server leader dies.

I added tests to ensuring that all services are up and running,
including package-upload which runs only on the leader.

Description of the change

Add integration tests for when the landscape-server leader dies.

I added tests to ensuring that all services are up and running,
including package-upload which runs only on the leader.

To post a comment you must log in.
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :
review: Approve (test results)
Revision history for this message
Adam Collard (adam-collard) wrote :

Running the tests locally causes my machine to die in a pit of swappiness and despair.

Code looks good though, and I'm happy to +1 on the assumption that they pass for you and the other reviewer.

review: Approve
Revision history for this message
Free Ekanayaka (free.ekanayaka) wrote :

+1 works as advertised

review: Approve
322. By Björn Tillenius

Typo.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'tests/basic/test_ha.py'
2--- tests/basic/test_ha.py 2015-06-09 09:52:44 +0000
3+++ tests/basic/test_ha.py 2015-06-11 15:59:45 +0000
4@@ -15,7 +15,7 @@
5 def setUp(self):
6 super(LandscapeHATest, self).setUp()
7 self.leader = self.layer.leader
8- self.non_leader = self.layer.non_leader
9+ [self.non_leader] = self.layer.non_leaders
10
11 def test_app_leader_down(self):
12 """
13
14=== added file 'tests/basic/test_leader.py'
15--- tests/basic/test_leader.py 1970-01-01 00:00:00 +0000
16+++ tests/basic/test_leader.py 2015-06-11 15:59:45 +0000
17@@ -0,0 +1,47 @@
18+from helpers import IntegrationTest
19+from layers import LandscapeLeaderDestroyedLayer
20+
21+
22+class LandscapeLeaderDestroyedTest(IntegrationTest):
23+ """Test what happens when the landscape-server leader gets destroyed.
24+
25+ The tests in here are intended to test that the newly elected leader
26+ takes over correctly.
27+ """
28+
29+ layer = LandscapeLeaderDestroyedLayer
30+
31+ def test_app(self):
32+ """
33+ Verify that the APP service is up after the leader unit is destroyed.
34+ """
35+ self.environment.check_service("appserver")
36+
37+ def test_msg(self):
38+ """
39+ Verify that the MSG service is up after the leader unit is destroyed.
40+ """
41+ self.environment.check_service("msgserver")
42+
43+ def test_ping(self):
44+ """
45+ Verify that the PING service is up after the leader unit is destroyed.
46+ """
47+ self.environment.check_service("pingserver")
48+
49+ def test_api(self):
50+ """
51+ Verify that the API service is up after the leader unit is destroyed.
52+ """
53+ self.environment.check_service("api")
54+
55+ def test_package_upload_new_leader(self):
56+ """
57+ Verify that the package upload service is now running on the new
58+ leader.
59+
60+ package-upload is running only on the leader unit, and if a
61+ leader unit gets destroyed, the package-upload service is
62+ transferred to the new leader.
63+ """
64+ self.environment.check_service("package-upload")
65
66=== modified file 'tests/helpers.py'
67--- tests/helpers.py 2015-06-11 09:56:29 +0000
68+++ tests/helpers.py 2015-06-11 15:59:45 +0000
69@@ -10,6 +10,7 @@
70 import tempfile
71 import shutil
72 import json
73+import time
74
75 from os import getenv
76 from time import sleep
77@@ -268,12 +269,7 @@
78 """Start the given Landscape service on the given unit."""
79 self._deployment.configure(
80 "landscape-server", {"ssl-cert": cert, "ssl-key": key})
81- # Wait for initial landscape-server hooks to fire
82- self._deployment.sentry.wait()
83- # Wait for haproxy hooks to fire
84- self._deployment.sentry.wait()
85- # Wait for landscape-server hooks triggered by the haproxy ones to fire
86- self._deployment.sentry.wait()
87+ self._wait_for_deployment_change_hooks()
88
89 def set_unit_count(self, service, new_count):
90 """Change the service to have the given number of units.
91@@ -296,10 +292,23 @@
92 while current_count > new_count:
93 self._deployment.destroy_unit(existing_units.pop())
94 current_count -= 1
95- # Wait for all the hooks to finish firing.
96- self._deployment.sentry.wait()
97- self._deployment.sentry.wait()
98- self._deployment.sentry.wait()
99+ self._wait_for_deployment_change_hooks()
100+
101+ def destroy_landscape_leader(self):
102+ """Destroy the landscape-server leader
103+
104+ This method will wait at most 60 seconds for a new leader to
105+ elected before returning.
106+ """
107+ leader, _ = self.get_unit_ids("landscape-server")
108+ self._deployment.destroy_unit("landscape-server/{}".format(leader))
109+ self._wait_for_deployment_change_hooks()
110+ for _ in range(60):
111+ leader, _ = self.get_unit_ids("landscape-server")
112+ if leader is not None:
113+ break
114+ time.sleep(1)
115+ assert leader is not None, "No new leader was elected."
116
117 def get_unit_ids(self, service):
118 """Return the numerical id parts for the units of the given service.
119@@ -320,12 +329,20 @@
120 result, code = unit.run("is-leader --format=json")
121 if json.loads(result):
122 assert leader is None, "Multiple leaders found."
123- leader = unit_number
124+ leader = int(unit_number)
125 else:
126- non_leaders.append(unit_number)
127-
128- return int(leader), sorted(
129- int(unit_number) for unit_number in non_leaders)
130+ non_leaders.append(int(unit_number))
131+
132+ return leader, sorted(non_leaders)
133+
134+ def _wait_for_deployment_change_hooks(self):
135+ """Wait for hooks to finish firing after a change in the deployment."""
136+ # Wait for initial landscape-server hooks to fire
137+ self._deployment.sentry.wait()
138+ # Wait for haproxy hooks to fire
139+ self._deployment.sentry.wait()
140+ # Wait for landscape-server hooks triggered by the haproxy ones to fire
141+ self._deployment.sentry.wait()
142
143 def _run(self, command, unit):
144 """Run a command on the given unit.
145
146=== modified file 'tests/layers.py'
147--- tests/layers.py 2015-06-11 07:49:02 +0000
148+++ tests/layers.py 2015-06-11 15:59:45 +0000
149@@ -66,5 +66,20 @@
150 @classmethod
151 def setUp(cls):
152 cls.environment.set_unit_count("landscape-server", 2)
153- cls.leader, [cls.non_leader] = cls.environment.get_unit_ids(
154+ cls.leader, cls.non_leaders = cls.environment.get_unit_ids(
155+ "landscape-server")
156+
157+
158+class LandscapeLeaderDestroyedLayer(TwoLandscapeUnitsLayer):
159+ """Layer for tests meant to run when the leader has been destroyed.
160+
161+ After setting up this layer, a new leader will have been elected.
162+
163+ Note that this layer is destructive and reduces the deployment to 1 unit.
164+ """
165+
166+ @classmethod
167+ def setUp(cls):
168+ cls.environment.destroy_landscape_leader()
169+ cls.leader, cls.non_leaders = cls.environment.get_unit_ids(
170 "landscape-server")

Subscribers

People subscribed via source and target branches