Merge lp:~stub/charms/precise/postgresql/charm-helpers into lp:charms/postgresql

Proposed by Stuart Bishop
Status: Merged
Merged at revision: 69
Proposed branch: lp:~stub/charms/precise/postgresql/charm-helpers
Merge into: lp:charms/postgresql
Diff against target: 217 lines (+1/-197)
3 files modified
charm-helpers.yaml (+1/-2)
hooks/charmhelpers/testing/__init__.py (+0/-1)
hooks/charmhelpers/testing/jujufixture.py (+0/-194)
To merge this branch: bzr merge lp:~stub/charms/precise/postgresql/charm-helpers
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Review via email: mp+190077@code.launchpad.net

Description of the change

To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) wrote :
70. By Stuart Bishop on 2013-10-10

Revert to trunk charm-helpers

Revision history for this message
Stuart Bishop (stub) wrote :

Reverted to trunk

Revision history for this message
Stuart Bishop (stub) :
review: Approve
71. By Stuart Bishop on 2013-10-10

Merged postgresql into charm-helpers.

72. By Stuart Bishop on 2013-10-10

Remove old testing package

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charm-helpers.yaml'
2--- charm-helpers.yaml 2013-09-24 11:09:35 +0000
3+++ charm-helpers.yaml 2013-10-10 19:35:20 +0000
4@@ -1,6 +1,5 @@
5 destination: hooks/charmhelpers
6-branch: lp:~stub/charm-helpers/test-harness
7+branch: lp:charm-helpers
8 include:
9 - core
10- - testing
11 - fetch
12
13=== removed directory 'hooks/charmhelpers/testing'
14=== removed file 'hooks/charmhelpers/testing/__init__.py'
15--- hooks/charmhelpers/testing/__init__.py 2013-09-24 11:09:35 +0000
16+++ hooks/charmhelpers/testing/__init__.py 1970-01-01 00:00:00 +0000
17@@ -1,1 +0,0 @@
18-from jujufixture import *
19
20=== removed file 'hooks/charmhelpers/testing/jujufixture.py'
21--- hooks/charmhelpers/testing/jujufixture.py 2013-09-24 11:09:35 +0000
22+++ hooks/charmhelpers/testing/jujufixture.py 1970-01-01 00:00:00 +0000
23@@ -1,194 +0,0 @@
24-import json
25-import subprocess
26-import time
27-
28-import fixtures
29-from testtools.content import text_content
30-
31-
32-__all__ = ['JujuFixture', 'run']
33-
34-
35-class JujuFixture(fixtures.Fixture):
36- """Interact with juju.
37-
38- Assumes juju environment is bootstrapped.
39- """
40-
41- def __init__(self, reuse_machines=False, do_teardown=True):
42- super(JujuFixture, self).__init__()
43-
44- self._deployed_charms = set()
45-
46- self.reuse_machines = reuse_machines
47-
48- # Optionally, don't teardown services and machines after running
49- # a test. If a subsequent test is run, they will be torn down at
50- # that point. This option is only useful when running a single
51- # test, or when the test harness is set to abort after the first
52- # failed test.
53- self.do_teardown = do_teardown
54-
55- self._deployed_services = set()
56-
57- def do(self, cmd):
58- cmd = ['juju'] + cmd
59- run(self, cmd)
60-
61- def get_result(self, cmd):
62- cmd = ['juju'] + cmd + ['--format=json']
63- out = run(self, cmd)
64- if out:
65- return json.loads(out)
66- return None
67-
68- def deploy(self, charm, name=None, num_units=1):
69- # The first time we deploy a local: charm in the test run, it
70- # needs to deploy with --update to ensure we are testing the
71- # desired revision of the charm. Subsequent deploys we do not
72- # use --update to avoid overhead and needless incrementing of the
73- # revision number.
74- if not charm.startswith('local:') or charm in self._deployed_charms:
75- cmd = ['deploy']
76- else:
77- cmd = ['deploy', '-u']
78- self._deployed_charms.add(charm)
79-
80- cmd.append(charm)
81-
82- if name is None:
83- name = charm.split(':', 1)[-1]
84-
85- cmd.append(name)
86- self._deployed_services.add(name)
87-
88- if self.reuse_machines and self._free_machines:
89- cmd.extend(['--to', str(self._free_machines.pop())])
90- self.do(cmd)
91- if num_units > 1:
92- self.add_unit(charm, name, num_units - 1)
93- else:
94- cmd.extend(['-n', str(num_units)])
95- self.do(cmd)
96-
97- def add_unit(self, charm, name=None, num_units = 1):
98- if name is None:
99- name = charm.split(':', 1)[-1]
100-
101- num_units_spawned = 0
102- while self.reuse_machines and self._free_machines:
103- cmd = ['add-unit', '--to', str(self._free_machines.pop()), name]
104- self.do(cmd)
105- num_units_spawned += 1
106- if num_units_spawned == num_units:
107- return
108-
109- cmd = ['add-unit', '-n', str(num_units - num_units_spawned), name]
110- self.do(cmd)
111-
112- # The most recent environment status, updated by refresh_status()
113- status = None
114-
115- def refresh_status(self):
116- self.status = self.get_result(['status'])
117-
118- self._free_machines = set(
119- int(k) for k in self.status['machines'].keys()
120- if k != '0')
121- for service in self.status.get('services', {}).values():
122- for unit in service.get('units', []):
123- if 'machine' in unit:
124- self._free_machines.remove(int(unit['machine']))
125-
126- return self.status
127-
128- def wait_until_ready(self, extra=45):
129- ready = False
130- while not ready:
131- self.refresh_status()
132- ready = True
133- for service in self.status['services']:
134- if self.status['services'][service].get('life', '') == 'dying':
135- ready = False
136- units = self.status['services'][service].get('units', {})
137- for unit in units.keys():
138- agent_state = units[unit].get('agent-state', '')
139- if agent_state == 'error':
140- raise RuntimeError('{} error: {}'.format(
141- unit, units[unit].get('agent-state-info','')))
142- if agent_state != 'started':
143- ready = False
144- time.sleep(1)
145- # Unfortunately, there is no way to tell when a system is
146- # actually ready for us to test. Juju only tells us that a
147- # relation has started being setup, and that no errors have been
148- # encountered yet. It utterly fails to inform us when the
149- # cascade of hooks this triggers has finished and the
150- # environment is in a stable and actually testable state.
151- # So as a work around for Bug #1200267, we need to sleep long
152- # enough that our system is probably stable. This means we have
153- # extremely slow and flaky tests, but that is possibly better
154- # than no tests.
155- time.sleep(extra)
156-
157- def setUp(self):
158- super(JujuFixture, self).setUp()
159- self.reset()
160- if self.do_teardown:
161- self.addCleanup(self.reset)
162-
163- def reset(self):
164- # Tear down any services left running that we know we spawned.
165- while True:
166- found_services = False
167- self.refresh_status()
168-
169- # Kill any services started by the deploy() method.
170- for service_name, service in self.status.get(
171- 'services', {}).items():
172- if service_name in self._deployed_services:
173- found_services = True
174- if service.get('life', '') != 'dying':
175- self.do(['destroy-service', service_name])
176- # If any units have failed hooks, unstick them.
177- for unit_name, unit in service.get('units', {}).items():
178- if unit.get('agent-state', None) == 'error':
179- self.do(['resolved', unit_name])
180- if not found_services:
181- break
182- time.sleep(1)
183-
184- self._deployed_services = set()
185-
186- # We need to wait for dying services
187- # to die before we can continue.
188- if found_services:
189- self.wait_until_ready(0)
190-
191- # We shouldn't reuse machines, as we have no guarantee they are
192- # still in a usable state, so tear them down too. Per
193- # Bug #1190492 (INVALID), in the future this will be much nicer
194- # when we can use containers for isolation and can happily reuse
195- # machines.
196- if not self.reuse_machines:
197- self.do(['terminate-machine'] + list(self._free_machines))
198-
199-
200-def run(detail_collector, cmd, input=''):
201- try:
202- proc = subprocess.Popen(
203- cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
204- stderr=subprocess.PIPE)
205- except subprocess.CalledProcessError, x:
206- raise
207-
208- (out, err) = proc.communicate(input)
209- if out:
210- detail_collector.addDetail('stdout', text_content(out))
211- if err:
212- detail_collector.addDetail('stderr', text_content(err))
213- if proc.returncode != 0:
214- raise subprocess.CalledProcessError(
215- proc.returncode, cmd, err)
216- return out
217-

Subscribers

People subscribed via source and target branches