Merge lp:~mbruzek/charms/precise/memcached/trunk into lp:charms/memcached

Proposed by Matt Bruzek
Status: Merged
Merged at revision: 60
Proposed branch: lp:~mbruzek/charms/precise/memcached/trunk
Merge into: lp:charms/memcached
Diff against target: 175 lines (+165/-0)
2 files modified
tests/ (+19/-0)
tests/ (+146/-0)
To merge this branch: bzr merge lp:~mbruzek/charms/precise/memcached/trunk
Reviewer Review Type Date Requested Status
Marco Ceppi (community) Approve
Review via email:

Description of the change

Added Juju Amulet tests for memcached charm.

Added a deploy test, testing memcached with telnet, and configuration test.

To post a comment you must log in.
Revision history for this message
Matt Bruzek (mbruzek) wrote :

Please take a look.

Revision history for this message
Matt Bruzek (mbruzek) wrote :


Please take a look.

Added Juju Amulet tests for memcached charm.

Added a deploy test, testing memcached with telnet, and configuration

(do not edit description out of merge proposal)

Please review this at

Affected files (+154, -0 lines):
   A [revision details]
   A tests/
   A tests/

Revision history for this message
Charles Butler (lazypower) wrote :

Matt, Thank you for your work on this charm test suite, it looks
comprehensive enough to be comfortable, the only issue I found was in
the setup script there were missing dependencies.

Correct those issues and you get a +1 from me
File tests/ (right):
tests/ sudo apt-get install -y amulet
This is missing python3, and any associated python3 libraries to
complete the test run. The assumption is we are running this test on a
machine with nothing more than juju-core on it.
File tests/ (right):
tests/ try:
I like how you did this test. +1
tests/ message = 'The memcached charm passed the
deply tests!'
Typo on Deploy

61. By Matt Bruzek <email address hidden>

Making changes based on lazyPower's code review comments.

Revision history for this message
Matt Bruzek (mbruzek) wrote :
Revision history for this message
Matt Bruzek (mbruzek) wrote :

I updated the code to respond to lazypower's code review comments.

Revision history for this message
Marco Ceppi (marcoceppi) wrote :

This looks good as a test, needs some additional robustness, see inline
File tests/ (right):
tests/ except:
It would be nice if you used

except Exception as e:

which would allow you to use the e to detail which of the areas failed
in the test. So for your message you could add a third option, str(e) to
get the message of the error which caused the exception. This should
help show authors why the charm is failing if it fails
tests/ relation = mediawiki_unit.relation('cache',
The cache relation for memcache sends host, port, and udp-port with the
last two being configurable. You should set these to non-standard ports
in the initial configuration and test that the values are sent on the
wire properly.

62. By Matt Bruzek <email address hidden>

Addressed code review comments.

Revision history for this message
Matt Bruzek (mbruzek) wrote :
Revision history for this message
Marco Ceppi (marcoceppi) wrote :

LGTM, with one minor fix below
File tests/ (right):
tests/ port_string =['open-ports'][0]
It'd be better to use configuration['tcp-port'] for this, instead of
querying the data.

63. By Matt Bruzek <email address hidden>

Addressing the tcp-port review comment.

Revision history for this message
Matt Bruzek (mbruzek) wrote :
Revision history for this message
Marco Ceppi (marcoceppi) wrote :


review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'tests'
2=== added file 'tests/'
3--- tests/ 1970-01-01 00:00:00 +0000
4+++ tests/ 2014-02-06 18:10:42 +0000
5@@ -0,0 +1,19 @@
8+# The script installs amulet and other tools needed for the amulet tests.
10+set -x
12+# Get the status of the amulet package, this returns 0 of package is installed.
13+dpkg -s amulet
14+if [ $? -ne 0 ]; then
15+ # Install the Amulet testing harness.
16+ sudo add-apt-repository -y ppa:juju/stable
17+ sudo apt-get update
18+ sudo apt-get install -y amulet juju-core charm-tools
20+dpkg -s python3
21+if [ $? -ne 0 ]; then
22+ # Install the Python3 libraries.
23+ sudo apt-get install -y python3
26=== added file 'tests/'
27--- tests/ 1970-01-01 00:00:00 +0000
28+++ tests/ 2014-02-06 18:10:42 +0000
29@@ -0,0 +1,146 @@
32+## This Amulet test deploys memcached.
34+import amulet
35+import telnetlib
36+import time
38+# The number of seconds to wait for the environment to setup.
39+seconds = 1200
41+d = amulet.Deployment()
42+# Add the memcached charm to the deployment.
44+# Add the mediawiki charm to the deployment.
46+# Create a relation from memcached to mediawiki
47+d.relate('memcached:cache', 'mediawiki:cache')
49+# Create a configuration dictionary for custom memcached values.
50+configuration = {'size': 512, 'connection-limit': 128, 'factor': 1.10,
51+ 'tcp-port': 11212, 'udp-port': 11213}
52+d.configure('memcached', configuration)
53+# Expose memcached so it is visible to the tests.
57+ # Execute the deployer with the current mapping.
58+ d.setup(timeout=seconds)
59+ # Wait for the relation to finish the translations.
60+ d.sentry.wait(seconds)
61+except amulet.helpers.TimeoutError:
62+ message = 'The environment did not setup in %d seconds.' % seconds
63+ # The SKIP status enables skip or fail the test based on configuration.
64+ amulet.raise_status(amulet.SKIP, msg=message)
66+ raise
68+# Get the sentry for memcached.
69+memcached_unit = d.sentry.unit['memcached/0']
71+## Test if the memcached service is running.
73+# Run the command that checks if the memcached server instance is running.
74+command = 'service memcached status'
75+# Execute the command on the deployed service.
76+output, code =
78+if code != 0:
79+ message = 'The ' + command + ' returned %d.' % code
80+ print(output)
81+ amulet.raise_status(amulet.FAIL, msg=message)
83+ message = 'The memcached service is running.'
84+ print(output)
85+ print(message)
87+## Test memcached using telnet commands.
89+# Get the public address for memcached instance.
90+memcached_address =['public-address']
91+# Get the port for memcached instance.
92+memcached_port = configuration['tcp-port']
95+ # Connect to memcached via telnet.
96+ tn = telnetlib.Telnet(memcached_address, memcached_port)
97+ date_time = time.strftime("%F %r")
98+ # Write the command that gets the current greeting.
99+ tn.write(b'get greeting\r\n')
100+ # Read the current greeting.
101+ response = tn.read_until(b'END', 2)
102+ # Create a string with date and time for this test.
103+ string = 'memcached test %s' % date_time
104+ command = 'set greeting 1 0 %d' % len(string)
105+ # Write the command that sets the new greeting.
106+ tn.write(command.encode() + b'\r\n')
107+ tn.write(string.encode() + b'\r\n')
108+ # Read the response
109+ response = tn.read_until(b'STORED', 2)
110+ # Write the command that gets the greeting.
111+ tn.write(b'get greeting\r\n')
112+ # Get the new greeting in memcached.
113+ response = tn.read_until(b'END', 2)
114+ response = response.decode()
115+ print('get greeting response:')
116+ print(response)
117+ # Look for the string in the response.
118+ index = response.find(string)
119+ if index != -1:
120+ print('Found %s in the greeting response.' % string)
121+ else:
122+ print(response)
123+ message = 'Did not find %s in the greeting from memcached.' % string
124+ amulet.raise_status(amulet.FAIL, msg=message)
125+ tn.write(b'quit\n')
126+except Exception as e:
127+ message = 'An error occurred communicating with memcached over telnet ' \
128+ '{0}:{1} {3}'.format(memcached_address, memcached_port, str(e))
129+ amulet.raise_status(amulet.FAIL, msg=message)
131+ tn.close()
133+## Test if the memcached service is configured properly.
135+# Get the contents of the memcached configuration file.
136+config_string = memcached_unit.file_contents('/etc/memcached.conf')
137+# Parse the configuration file for the values sent in the deployment.
138+for line in config_string.splitlines():
139+ if line.startswith('-m '):
140+ size = line.split()[1]
141+ elif line.startswith('-c '):
142+ limit = line.split()[1]
143+ elif line.startswith('-f '):
144+ factor = line.split()[1]
146+# Check for the configured values.
147+if (configuration['size'] != int(size) or
148+ configuration['connection-limit'] != int(limit) or
149+ configuration['factor'] != float(factor)):
150+ message = 'The memcached deployment was not configured correctly, size: ' \
151+ '{0} limit: {1} factor: {2}'.format(size, limit, factor)
152+ amulet.raise_status(amulet.FAIL, msg=message)
154+ message = 'The memcached deployment was configured correctly.'
155+ print(message)
157+## Test if the relation is complete and data was exchanged properly.
159+memcached_unit = d.sentry.unit['memcached/0']
160+# Get the relation from memcached to mediawiki.
161+relation = memcached_unit.relation('cache', 'mediawiki:cache')
163+# Make sure the relation got the port information set by the configuration.
164+if (configuration['tcp-port'] != int(relation['port']) or
165+ configuration['udp-port'] != int(relation['udp-port'])):
166+ message = 'The memcached relation was not configured correctly, port: ' \
167+ '{0} udp-port: {1}'.format(relation['port'], relation['udp-port'])
168+ amulet.raise_status(amulet.FAIL, msg=message)
170+ message = 'The memcached relation was configured correctly.'
171+ print(message)
173+# Print a message indicating the charm passed all the tests.
174+message = 'The memcached charm passed the deploy tests!'


People subscribed via source and target branches

to all changes: