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


People subscribed via source and target branches

to all changes: