5
<title>Juju Documentation - Authoring Charms</title>
6
<link href="//fonts.googleapis.com/css?family=Ubuntu:400,400italic" rel="stylesheet" type="text/css"/>
7
<link href="//fonts.googleapis.com/css?family=Ubuntu+Mono:400" rel="stylesheet" type="text/css"/>
8
<link href="https://juju.ubuntu.com/wp-content/themes/juju-website/css/reset.css" rel="stylesheet" type="text/css"/>
9
<link href="https://juju.ubuntu.com/wp-content/themes/juju-website/css/960.css" rel="stylesheet" type="text/css"/>
10
<link href="https://juju.ubuntu.com/wp-content/themes/juju-website/css/base.css" rel="stylesheet" type="text/css"/>
11
<link href="https://juju.ubuntu.com/wp-content/themes/juju-website/css/resources.css" rel="stylesheet" type="text/css"/>
12
<link href="css/main.css" rel="stylesheet" type="text/css"/>
13
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
14
<script src="http://app.stacktack.com/jquery.stacktack.min.js"></script>
15
<script type="text/javascript">
16
$(document).ready(function() {
17
$(document).stacktack();
19
</script><!--[if lt IE 9]>
20
<script type="text/javascript" src="//html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
22
<body class="resources">
24
<div class="header-login">
29
<div class="header-navigation">
31
<nav role="navigation">
33
<li class="page_item"><a href="https://juju.ubuntu.com/">Home</a></li>
34
<li class="page_item current_page_item"><a href="https://juju.ubuntu.com/">Resources</a></li>
35
<li class="page_item"><a href="https://juju.ubuntu.com/">Community</a></li>
36
<li class="page_item"><a href="https://juju.ubuntu.com/">Charm Store</a></li>
37
<li class="page_item"><a href="https://juju.ubuntu.com/">Events</a></li>
38
<li class="page_item"><a href="https://juju.ubuntu.com/">Survey</a></li>
40
<form id="form-search" method="get" action="/">
42
<input id="input-search" type="text" name="s" value="Search">
47
</nav><a href="https://juju.ubuntu.com/" class="logo-ubuntu"><img src="https://juju.ubuntu.com/wp-content/themes/juju-website/img/logo-ubuntu.png"></a>
50
<div class="header-content">
51
<div class="clearfix"><img src="https://juju.ubuntu.com/wp-content/themes/juju-website/img/arrow-nav.png" width="9" height="5" style="left:894px; display: block;" class="arrow-nav">
52
<div class="header-navigation-secondary"></div>
53
<div class="header-image"></div>
55
<h2>A collection of some of the most important online references for Juju users and developers.</h2>
59
<section id="content" class="container-12">
60
<div class="grid-12 doc-container">
61
<div class="grid-3 doc-navigation">
62
<nav role="navigation">
65
<li class=""><a href="getting-started.html">Getting Started</a></li>
66
<li class=" sub"><a href="getting-started.html#intro">Introduction</a></li>
67
<li class=" sub"><a href="getting-started.html#install">Installation</a></li>
68
<li class=" sub"><a href="config-aws.html">AWS Configuration</a></li>
69
<li class=" sub"><a href="config-hpcloud.html">HP Cloud Configuration</a></li>
70
<li class=" sub"><a href="">OpenStack Configuration</a></li>
71
<li class=" sub"><a href="config-maas.html">MAAS Configuration</a></li>
72
<li class=" sub"><a href="getting-started.html#test">Testing your setup</a></li>
73
<li class=""><a href="charms.html">Using Charms</a></li>
74
<li class=" sub"><a href="charms.html#intro">What are Charms?</a></li>
75
<li class=" sub"><a href="charms-deploying.html">Deploying Services</a></li>
76
<li class=" sub"><a href="charms-constraints.html">Using constraints</a></li>
77
<li class=" sub"><a href="charms-config.html">Service Configuration</a></li>
78
<li class=" sub"><a href="charms-relations.html">Service Relationships</a></li>
79
<li class=" sub"><a href="charms-exposing.html">Exposing Services</a></li>
80
<li class=" sub"><a href="charms-scaling.html">Scaling Services</a></li>
81
<li class=" sub"><a href="charms-destroy.html">Destroying Services</a></li>
83
<h1>Charm Authors</h1>
85
<li class=""><a href="authors-charm-writing.html">Writing a charm</a></li>
86
<li class=" sub"><a href="authors-subordinate-services.html">Subordinate services</a></li>
87
<li class=" sub"><a href="authors-implicit-relations.html">Implicit Relations</a></li>
88
<li class=" sub"><a href="authors-testing.html">Charm Testing</a></li>
89
<li class=" sub"><a href="authors-hooks.html">Hook debugging</a></li>
90
<li class=""><a href="authors-charm-store.html">The Juju Charm Store</a></li>
91
<li class=" sub"><a href="authors-charm-policy.html">Charm store policy</a></li>
92
<li class=" sub"><a href="authors-charm-best-practice.html">Best practices</a></li>
93
<li class=" sub"><a href="authors-charm-quality.html">Charm Quality Rating</a></li>
96
<li class="sub"><a href="commands.html">Juju commands</a></li>
97
<li class="sub"><a href="glossary.html">Glossary</a></li>
98
<li class="sub"><a href="contributing.html">Contribute to the Docs!</a></li>
102
<div class="grid-9 doc-content">
104
<section id='authors-charm-testing'>
105
<h1>Charm Testing</h1>
106
<p>Juju has been designed from the start to foster a large collection of "charms". Charms are expected to number in the thousands, and be self contained, with well defined interfaces for defining their relationships to one another.</p>
107
<p>Because this is a large complex system, not unlike a Linux software distribution, there is a need to test the charms and how they interact with one another. This specification defines a plan for implementing a simple framework to help this happen.</p>
108
<p>Static tests have already been implemented in the <tt class="docutils literal"><span class="pre">charm</span> <span class="pre">proof</span></tt> command as part of <tt class="docutils literal"><span class="pre">charm-tools</span></tt>. Any static testing of charms is beyond the scope of this specification.</p>
111
<h2>Phase 1 - Generic tests</h2>
112
<p>All charms share some of the same characteristics. They all have a yaml file called <tt class="docutils literal"><span class="pre">metadata.yaml</span></tt>, and when deployed, juju will always attempt to progress the state of the service from install to config to started. Because of this, all charms can be tested using the following algorithm:</p>
114
while state != started
115
if timeout is reached, FAIL
116
if state == install_error, config_error, or start_error, FAIL
117
if state == started, PASS</pre>
119
<p>Other generic tests may be identified, so a collection of generic tests should be the focus of an implementation.</p>
120
<p>Note that this requirement is already satisfied by Mark Mims' jenkins tester: <a class="reference external" href="http://charmtests.markmims.com/">http://charmtests.markmims.com/</a></p>
122
<h2>Phase 2 - Charm Specific tests</h2>
123
<p>Charm authors will have the best insight into whether or not a charm is working properly.</p>
124
<p>A simple structure will be utilized to attach tests to charms. Under the charm root directory, a sub-directory named 'tests' will be scanned by a test runner for executable files matching the glob <tt class="docutils literal"><span class="pre">*.test</span></tt>. These will be run in lexical order by the test runner, with a predictible environment. The tests can make the following assumptions:</p>
126
<li>A minimal install of the release of Ubuntu which the charm is targetted at will be available.</li>
127
<li>A version of juju is installed and available in the system path.</li>
128
<li>A juju environment with no services deployed inside it is already bootstrapped, and will be the default for command line usage.</li>
129
<li>The CWD is the <tt class="docutils literal"><span class="pre">tests</span></tt> directory off the charm root.</li>
130
<li>Full network access to deployed nodes will be allowed.</li>
131
<li>the bare name of any charm in arguments to juju will be resolved to a charm url and/or repository arguments of the test runner's choice. This means that if you need mysql, you do not do <tt class="docutils literal"><span class="pre">juju</span> <span class="pre">deploy</span> <span class="pre">cs:mysql</span></tt> or <tt class="docutils literal"><span class="pre">juju</span> <span class="pre">deploy</span> <span class="pre">--repository</span> <span class="pre">~/charms</span> <span class="pre">local:mysql</span></tt>, but just <tt class="docutils literal"><span class="pre">juju</span> <span class="pre">deploy</span> <span class="pre">mysql</span></tt>. A wrapper will resolve this to the latest version of the given charm from the list of official charms.</li>
133
<p>The following restrictions may be enforced:</p>
135
<li>Internet access will be restricted from the testing host.</li>
137
<p>If present, tests/tests.yaml will be read to determine packages that need to be installed on the host running tests in order to facilitate the tests. The packages can <em>only</em> be installed from the official, default Ubuntu archive for the release which the charm is intended for, from any of the repositories enabled by default in said release. The format of tests.yaml is as such:</p>
138
<pre>packages: [ package1, package2, package3 ]</pre>
140
<p>If a tool is needed to perform a test and is not available in the Ubuntu archive, it can also be included in the <tt class="docutils literal"><span class="pre">tests/</span></tt> directory, as long as the file which contains it does not end in <tt class="docutils literal"><span class="pre">.test</span></tt>. Note that build tools cannot be assumed to be available on the testing system.</p>
141
<div class="section" id="purpose-of-tests">
142
<h3>Purpose of tests</h3>
143
<p>The purpose of these tests is to assert that the charm works well on the intended platform and performs the expected configuration steps. Examples of things to test in each charm beyond install/start is:</p>
145
<li>After install, expose, and adding of required relations, the service is listening on the intended ports and is functional.</li>
146
<li>Adding, removing, and re-adding a relation should work without error.</li>
147
<li>Setting config values should result in the config value reflected in the service's configuraion.</li>
148
<li>Adding multiple units to a web app charm and relating to a load balancer results in the same HTML on both units directly and the load balancer.</li>
152
<p>Upon exit, the test's exit code will be evaluated to mean the following:</p>
154
<li>0: Test passed</li>
155
<li>1: Failed test</li>
156
<li>100: Test is skipped because of incomplete environment</li>
160
<p>There is a general convention which output should follow, though it will not be interpreted by machine. On stdout, a message indicating the reason for the exit code should be printed, with a prefix string corresponding to the exit codes defined above. The correlation is:</p>
166
<p>Anything else intentional should be prefixed with the word 'INFO'. If the
167
contents of files are to be logged, the contents should be preceeded by
168
<tt class="docutils literal"><span class="pre">INFO:</span> <span class="pre">BEGIN</span> <span class="pre">filename</span></tt>, where filename is a logical name unique to
169
this run of the test, and then the file ended with <tt class="docutils literal"><span class="pre">INFO:</span> <span class="pre">END</span> <span class="pre">filename</span></tt>.</p>
171
<h3>Example Tests<</h3>
173
<h4>Deploy requirements and Poll</h4>
174
<p>The test below <a class="footnote-reference" href="#id2" id="id1">[*]</a> deploys mediawiki with mysql and memcached related to it,
175
and then tests to make sure it returns a page via http with "<title>"
176
somewhere in the content.:</p>
182
if [ -n "$datadir" ] ; then
183
if [ -f $datadir/passed ]; then
184
rm -r $datadir
185
else
186
echo INFO: $datadir preserved
187
if [ -f $datadir/wget.log ] ; then
188
echo INFO: BEGIN wget.log
189
cat $datadir/wget.log
190
echo INFO: END wget.log
191
fi
192
fi
193
fi
195
trap teardown EXIT
198
juju deploy mediawiki
199
juju deploy mysql
200
juju deploy memcached
201
juju add-relation mediawiki:db mysql:db
202
juju add-relation memcached mediawiki
203
juju expose mediawiki
205
for try in `seq 1 600` ; do
206
host=`juju status | tests/get-unit-info mediawiki public-address`
207
if [ -z "$host" ] ; then
208
sleep 1
209
else
210
break
211
fi
214
if [ -z "$host" ] ; then
215
echo FAIL: status timed out
216
exit 1
219
datadir=`mktemp -d ${TMPDIR:-/tmp}/wget.test.XXXXXXX`
220
echo INFO: datadir=$datadir
222
wget --tries=100 --timeout=6 http://$host/ -O - -a $datadir/wget.log | grep -q '<title>'
224
if [ $try -eq 600 ] ; then
225
echo FAIL: Timed out waiting.
226
exit 1
229
touch $datadir/passed
237
<h3>Test config settings</h4>
238
<p>The following example tests checks to see if the default_port change the admin asks for is actually respected post-deploy:</p>
241
if [ -z "`which nc`" ] ; then
242
echo "SKIP: cannot run tests without netcat"
243
exit 100
248
juju deploy mongodb
249
juju expose mongodb
251
for try in `seq 1 600` ; do
252
host=`juju status | tests/get-unit-info mongodb public-address`
253
if [ -z "$host" ] ; then
254
sleep 1
255
else
256
break
257
fi
260
if [ -z "$host" ] ; then
261
echo FAIL: status timed out
262
exit 1
265
assert_is_listening() {
266
local port=$1
267
listening=""
268
for try in `seq 1 10` ; do
269
if ! nc $host $port < /dev/null ; then
270
continue
271
fi
272
listening="$port"
273
break
274
done
276
if [ -z "$listening" ] ; then
277
echo "FAIL: not listening on port $port after 10 retries"
278
return 1
279
else
280
echo "PASS: listening on port $listening"
281
return 0
282
fi
285
assert_is_listening 27017
287
juju set mongodb default_port=55555
289
assert_is_listening 55555
290
echo PASS: config change tests passed.
293
<table class="docutils footnote" frame="void" id="id2" rules="none">
294
<colgroup><col class="label" /><col /></colgroup>
296
<tr><td class="label"><a class="fn-backref" href="#id1">[*]</a></td><td>get-unit-info
297
The example tests script uses a tool that is not widely available yet, <tt class="docutils literal"><span class="pre">get-unit-info</span></tt>. In the future enhancements should be made to juju core to allow such things to be made into plugins. Until then, it can be included in each test dir that uses it, or we can build a package of tools that are common to tests.</td></tr>
302
<p>A test runner will periodically poll the collection of charms for changes since the last test run. If there have been changes, the entire set of changes will be tested as one delta. This delta will be recorded in the test results in such a way where a developer can repeat the exact set of changes for debugging purposes.</p>
303
<p>All of the charms will be scanned for tests in lexical order by series, charm name, branch name. Non official charms which have not been reviewed by charmers will not have their tests run until the test runner's restrictions have been vetted for security, since we will be running potentially malicious code. It is left to the implementor to determine what mix of juju, client platform, and environment settings are appropriate, as all of these are variables that will affect the running charms, and so may affect the outcome.</p>
304
<p>If tests exit with services still in the environment, the test runner may clean them up, whether by destroying the environment or destroying the services explicitly, and the machines may be terminated as well. Any artifacts needed from the test machines should be retrieved and displayed before the test exits.</p>
310
<div class="shadow"></div>
313
<nav role="navigation" class="clearfix">
315
<li><a href="https://juju.ubuntu.com/get-started">Get started</a></li>
316
<li class="page_item"><a href="https://juju.ubuntu.com/get-started/local/">Local</a></li>
317
<li class="page_item"><a href="https://juju.ubuntu.com/get-started/amazon/">Amazon Web Services</a></li>
318
<li class="page_item"><a href="https://juju.ubuntu.com/get-started/hp-cloud/">HP Cloud</a></li>
319
<li class="page_item"><a href="https://juju.ubuntu.com/get-started/rackspace/">Rackspace</a></li>
320
<li class="page_item"><a href="https://juju.ubuntu.com/get-started/openstack/">Openstack</a></li>
321
<li class="page_item"><a href="https://juju.ubuntu.com/get-started/maas/">MAAS</a></li>
324
<li><a href="https://juju.ubuntu.com/resources">Resources</a></li>
325
<li><a href="https://juju.ubuntu.com/docs">Documentation</a></li>
326
<li><a href="https://juju.ubuntu.com/resources/videos">Videos</a></li>
327
<li><a href="http://uistage.jujucharms.com:8080/">Juju GUI Demo</a></li>
330
<li><a href="https://juju.ubuntu.com/community">Community</a></li>
331
<li class="page_item"><a href="https://juju.ubuntu.com/community/juju-blog/">Blog</a></li>
332
<li class="page_item"><a href="https://juju.ubuntu.com/community/weekly-charm-meeting/">Charm Meetings</a></li>
333
<li class="page_item"><a href="https://juju.ubuntu.com/community/charmers/">Charmers</a></li>
334
<li class="page_item"><a href="https://lists.ubuntu.com/mailman/listinfo/juju">Mailing List</a></li>
335
<li class="page_item"><a href="http://webchat.freenode.net/?channels=juju">Chat</a></li>
336
<li class="page_item"><a href="http://askubuntu.com/questions/tagged/juju?sort=faq&amp;pagesize=50">FAQ</a></li>
339
<li><a href="https://launchpad.net/juju">Code</a></li>
340
<li><a href="https://launchpad.net/juju-core">Juju Core</a></li>
341
<li><a href="https://launchpad.net/charms">Charms</a></li>
346
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
347
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.14/jquery-ui.min.js"></script>
348
<script type="text/javascript" src="js/main.js"></script>
b'\\ No newline at end of file'