Integration test for metrics + bug fix

This commit:
- adds the beginnings of an integration testing framework
- adds an integration test to exercise metric collection
- adds a test charm with metrics collection
- fixes a potential bug that can cause N2VC to fail if no
initial-config-primitive is specified in the VNF descriptor

Signed-off-by: Adam Israel <adam.israel@canonical.com>
diff --git a/tests/charms/layers/metrics-ci/README.ex b/tests/charms/layers/metrics-ci/README.ex
new file mode 100755
index 0000000..b6816b2
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/README.ex
@@ -0,0 +1,65 @@
+# Overview
+
+Describe the intended usage of this charm and anything unique about how this
+charm relates to others here.
+
+This README will be displayed in the Charm Store, it should be either Markdown
+or RST. Ideal READMEs include instructions on how to use the charm, expected
+usage, and charm features that your audience might be interested in. For an
+example of a well written README check out Hadoop:
+http://jujucharms.com/charms/precise/hadoop
+
+Use this as a Markdown reference if you need help with the formatting of this
+README: http://askubuntu.com/editing-help
+
+This charm provides [service][]. Add a description here of what the service
+itself actually does.
+
+Also remember to check the [icon guidelines][] so that your charm looks good
+in the Juju GUI.
+
+# Usage
+
+Step by step instructions on using the charm:
+
+juju deploy servicename
+
+and so on. If you're providing a web service or something that the end user
+needs to go to, tell them here, especially if you're deploying a service that
+might listen to a non-default port.
+
+You can then browse to http://ip-address to configure the service.
+
+## Scale out Usage
+
+If the charm has any recommendations for running at scale, outline them in
+examples here. For example if you have a memcached relation that improves
+performance, mention it here.
+
+## Known Limitations and Issues
+
+This not only helps users but gives people a place to start if they want to help
+you add features to your charm.
+
+# Configuration
+
+The configuration options will be listed on the charm store, however If you're
+making assumptions or opinionated decisions in the charm (like setting a default
+administrator password), you should detail that here so the user knows how to
+change it immediately, etc.
+
+# Contact Information
+
+Though this will be listed in the charm store itself don't assume a user will
+know that, so include that information here:
+
+## Upstream Project Name
+
+  - Upstream website
+  - Upstream bug tracker
+  - Upstream mailing list or contact information
+  - Feel free to add things if it's useful for users
+
+
+[service]: http://example.com
+[icon guidelines]: https://jujucharms.com/docs/stable/authors-charm-icon
diff --git a/tests/charms/layers/metrics-ci/config.yaml b/tests/charms/layers/metrics-ci/config.yaml
new file mode 100755
index 0000000..51f2ce4
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/config.yaml
@@ -0,0 +1,14 @@
+options:
+  string-option:
+    type: string
+    default: "Default Value"
+    description: "A short description of the configuration option"
+  boolean-option:
+    type: boolean
+    default: False
+    description: "A short description of the configuration option"
+  int-option:
+    type: int
+    default: 9001
+    description: "A short description of the configuration option"
+
diff --git a/tests/charms/layers/metrics-ci/deps/layer/basic b/tests/charms/layers/metrics-ci/deps/layer/basic
new file mode 160000
index 0000000..d59d361
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/deps/layer/basic
@@ -0,0 +1 @@
+Subproject commit d59d3613006a5afe1b9322aed9d77b5945b44356
diff --git a/tests/charms/layers/metrics-ci/deps/layer/metrics b/tests/charms/layers/metrics-ci/deps/layer/metrics
new file mode 160000
index 0000000..6861ce3
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/deps/layer/metrics
@@ -0,0 +1 @@
+Subproject commit 6861ce384f0dcf4e3eb1eaddf421143f4f76e64e
diff --git a/tests/charms/layers/metrics-ci/deps/layer/options b/tests/charms/layers/metrics-ci/deps/layer/options
new file mode 160000
index 0000000..fcdcea4
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/deps/layer/options
@@ -0,0 +1 @@
+Subproject commit fcdcea4e5de3e1556c24e6704607862d0ba00a56
diff --git a/tests/charms/layers/metrics-ci/icon.svg b/tests/charms/layers/metrics-ci/icon.svg
new file mode 100755
index 0000000..e092eef
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/icon.svg
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>

+<!-- Created with Inkscape (http://www.inkscape.org/) -->

+

+<svg

+   xmlns:dc="http://purl.org/dc/elements/1.1/"

+   xmlns:cc="http://creativecommons.org/ns#"

+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"

+   xmlns:svg="http://www.w3.org/2000/svg"

+   xmlns="http://www.w3.org/2000/svg"

+   xmlns:xlink="http://www.w3.org/1999/xlink"

+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"

+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"

+   width="96"

+   height="96"

+   id="svg6517"

+   version="1.1"

+   inkscape:version="0.48+devel r12274"

+   sodipodi:docname="Juju_charm_icon_template.svg">

+  <defs

+     id="defs6519">

+    <linearGradient

+       inkscape:collect="always"

+       xlink:href="#Background"

+       id="linearGradient6461"

+       gradientUnits="userSpaceOnUse"

+       x1="0"

+       y1="970.29498"

+       x2="144"

+       y2="970.29498"

+       gradientTransform="matrix(0,-0.66666669,0.6660448,0,-866.25992,731.29077)" />

+    <linearGradient

+       id="Background">

+      <stop

+         id="stop4178"

+         offset="0"

+         style="stop-color:#b8b8b8;stop-opacity:1" />

+      <stop

+         id="stop4180"

+         offset="1"

+         style="stop-color:#c9c9c9;stop-opacity:1" />

+    </linearGradient>

+    <filter

+       style="color-interpolation-filters:sRGB;"

+       inkscape:label="Inner Shadow"

+       id="filter1121">

+      <feFlood

+         flood-opacity="0.59999999999999998"

+         flood-color="rgb(0,0,0)"

+         result="flood"

+         id="feFlood1123" />

+      <feComposite

+         in="flood"

+         in2="SourceGraphic"

+         operator="out"

+         result="composite1"

+         id="feComposite1125" />

+      <feGaussianBlur

+         in="composite1"

+         stdDeviation="1"

+         result="blur"

+         id="feGaussianBlur1127" />

+      <feOffset

+         dx="0"

+         dy="2"

+         result="offset"

+         id="feOffset1129" />

+      <feComposite

+         in="offset"

+         in2="SourceGraphic"

+         operator="atop"

+         result="composite2"

+         id="feComposite1131" />

+    </filter>

+    <filter

+       style="color-interpolation-filters:sRGB;"

+       inkscape:label="Drop Shadow"

+       id="filter950">

+      <feFlood

+         flood-opacity="0.25"

+         flood-color="rgb(0,0,0)"

+         result="flood"

+         id="feFlood952" />

+      <feComposite

+         in="flood"

+         in2="SourceGraphic"

+         operator="in"

+         result="composite1"

+         id="feComposite954" />

+      <feGaussianBlur

+         in="composite1"

+         stdDeviation="1"

+         result="blur"

+         id="feGaussianBlur956" />

+      <feOffset

+         dx="0"

+         dy="1"

+         result="offset"

+         id="feOffset958" />

+      <feComposite

+         in="SourceGraphic"

+         in2="offset"

+         operator="over"

+         result="composite2"

+         id="feComposite960" />

+    </filter>

+    <clipPath

+       clipPathUnits="userSpaceOnUse"

+       id="clipPath873">

+      <g

+         transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)"

+         id="g875"

+         inkscape:label="Layer 1"

+         style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline">

+        <path

+           style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"

+           d="m 46.702703,898.22775 50.594594,0 C 138.16216,898.22775 144,904.06497 144,944.92583 l 0,50.73846 c 0,40.86071 -5.83784,46.69791 -46.702703,46.69791 l -50.594594,0 C 5.8378378,1042.3622 0,1036.525 0,995.66429 L 0,944.92583 C 0,904.06497 5.8378378,898.22775 46.702703,898.22775 Z"

+           id="path877"

+           inkscape:connector-curvature="0"

+           sodipodi:nodetypes="sssssssss" />

+      </g>

+    </clipPath>

+    <filter

+       inkscape:collect="always"

+       id="filter891"

+       inkscape:label="Badge Shadow">

+      <feGaussianBlur

+         inkscape:collect="always"

+         stdDeviation="0.71999962"

+         id="feGaussianBlur893" />

+    </filter>

+  </defs>

+  <sodipodi:namedview

+     id="base"

+     pagecolor="#ffffff"

+     bordercolor="#666666"

+     borderopacity="1.0"

+     inkscape:pageopacity="0.0"

+     inkscape:pageshadow="2"

+     inkscape:zoom="4.0745362"

+     inkscape:cx="18.514671"

+     inkscape:cy="49.018169"

+     inkscape:document-units="px"

+     inkscape:current-layer="layer1"

+     showgrid="true"

+     fit-margin-top="0"

+     fit-margin-left="0"

+     fit-margin-right="0"

+     fit-margin-bottom="0"

+     inkscape:window-width="1920"

+     inkscape:window-height="1029"

+     inkscape:window-x="0"

+     inkscape:window-y="24"

+     inkscape:window-maximized="1"

+     showborder="true"

+     showguides="true"

+     inkscape:guide-bbox="true"

+     inkscape:showpageshadow="false">

+    <inkscape:grid

+       type="xygrid"

+       id="grid821" />

+    <sodipodi:guide

+       orientation="1,0"

+       position="16,48"

+       id="guide823" />

+    <sodipodi:guide

+       orientation="0,1"

+       position="64,80"

+       id="guide825" />

+    <sodipodi:guide

+       orientation="1,0"

+       position="80,40"

+       id="guide827" />

+    <sodipodi:guide

+       orientation="0,1"

+       position="64,16"

+       id="guide829" />

+  </sodipodi:namedview>

+  <metadata

+     id="metadata6522">

+    <rdf:RDF>

+      <cc:Work

+         rdf:about="">

+        <dc:format>image/svg+xml</dc:format>

+        <dc:type

+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />

+        <dc:title></dc:title>

+      </cc:Work>

+    </rdf:RDF>

+  </metadata>

+  <g

+     inkscape:label="BACKGROUND"

+     inkscape:groupmode="layer"

+     id="layer1"

+     transform="translate(268,-635.29076)"

+     style="display:inline">

+    <path

+       style="fill:url(#linearGradient6461);fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)"

+       d="m -268,700.15563 0,-33.72973 c 0,-27.24324 3.88785,-31.13513 31.10302,-31.13513 l 33.79408,0 c 27.21507,0 31.1029,3.89189 31.1029,31.13513 l 0,33.72973 c 0,27.24325 -3.88783,31.13514 -31.1029,31.13514 l -33.79408,0 C -264.11215,731.29077 -268,727.39888 -268,700.15563 Z"

+       id="path6455"

+       inkscape:connector-curvature="0"

+       sodipodi:nodetypes="sssssssss" />

+  </g>

+  <g

+     inkscape:groupmode="layer"

+     id="layer3"

+     inkscape:label="PLACE YOUR PICTOGRAM HERE"

+     style="display:inline" />

+  <g

+     inkscape:groupmode="layer"

+     id="layer2"

+     inkscape:label="BADGE"

+     style="display:none"

+     sodipodi:insensitive="true">

+    <g

+       style="display:inline"

+       transform="translate(-340.00001,-581)"

+       id="g4394"

+       clip-path="none">

+      <g

+         id="g855">

+        <g

+           inkscape:groupmode="maskhelper"

+           id="g870"

+           clip-path="url(#clipPath873)"

+           style="opacity:0.6;filter:url(#filter891)">

+          <path

+             transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)"

+             d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z"

+             sodipodi:ry="12"

+             sodipodi:rx="12"

+             sodipodi:cy="552.36218"

+             sodipodi:cx="252"

+             id="path844"

+             style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"

+             sodipodi:type="arc" />

+        </g>

+        <g

+           id="g862">

+          <path

+             sodipodi:type="arc"

+             style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"

+             id="path4398"

+             sodipodi:cx="252"

+             sodipodi:cy="552.36218"

+             sodipodi:rx="12"

+             sodipodi:ry="12"

+             d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z"

+             transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" />

+          <path

+             transform="matrix(1.25,0,0,1.25,33,-100.45273)"

+             d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z"

+             sodipodi:ry="12"

+             sodipodi:rx="12"

+             sodipodi:cy="552.36218"

+             sodipodi:cx="252"

+             id="path4400"

+             style="color:#000000;fill:#dd4814;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"

+             sodipodi:type="arc" />

+          <path

+             sodipodi:type="star"

+             style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"

+             id="path4459"

+             sodipodi:sides="5"

+             sodipodi:cx="666.19574"

+             sodipodi:cy="589.50385"

+             sodipodi:r1="7.2431178"

+             sodipodi:r2="4.3458705"

+             sodipodi:arg1="1.0471976"

+             sodipodi:arg2="1.6755161"

+             inkscape:flatsided="false"

+             inkscape:rounded="0.1"

+             inkscape:randomized="0"

+             d="m 669.8173,595.77657 c -0.39132,0.22593 -3.62645,-1.90343 -4.07583,-1.95066 -0.44938,-0.0472 -4.05653,1.36297 -4.39232,1.06062 -0.3358,-0.30235 0.68963,-4.03715 0.59569,-4.47913 -0.0939,-0.44198 -2.5498,-3.43681 -2.36602,-3.8496 0.18379,-0.41279 4.05267,-0.59166 4.44398,-0.81759 0.39132,-0.22593 2.48067,-3.48704 2.93005,-3.4398 0.44938,0.0472 1.81505,3.67147 2.15084,3.97382 0.3358,0.30236 4.08294,1.2817 4.17689,1.72369 0.0939,0.44198 -2.9309,2.86076 -3.11469,3.27355 C 669.9821,591.68426 670.20862,595.55064 669.8173,595.77657 Z"

+             transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" />

+        </g>

+      </g>

+    </g>

+  </g>

+</svg>

diff --git a/tests/charms/layers/metrics-ci/layer.yaml b/tests/charms/layers/metrics-ci/layer.yaml
new file mode 100755
index 0000000..bd3a2b9
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/layer.yaml
@@ -0,0 +1 @@
+includes: ['layer:basic', 'layer:metrics']  # if you use any interfaces, add them here
diff --git a/tests/charms/layers/metrics-ci/metadata.yaml b/tests/charms/layers/metrics-ci/metadata.yaml
new file mode 100755
index 0000000..060274d
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/metadata.yaml
@@ -0,0 +1,12 @@
+name: metrics-ci
+summary: <Fill in summary here>
+maintainer: Adam Israel <Adam.Israel@ronin>
+description: |
+  <Multi-line description here>
+tags:
+  # Replace "misc" with one or more whitelisted tags from this list:
+  # https://jujucharms.com/docs/stable/authors-charm-metadata
+  - misc
+subordinate: false
+series:
+  - xenial
diff --git a/tests/charms/layers/metrics-ci/metrics.yaml b/tests/charms/layers/metrics-ci/metrics.yaml
new file mode 100755
index 0000000..dae092f
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/metrics.yaml
@@ -0,0 +1,9 @@
+metrics:
+  users:
+    type: gauge
+    description: "# of users"
+    command: who|wc -l
+  load:
+    type: gauge
+    description: "5 minute load average"
+    command: cat /proc/loadavg |awk '{print $1}'
diff --git a/tests/charms/layers/metrics-ci/reactive/metrics_ci.py b/tests/charms/layers/metrics-ci/reactive/metrics_ci.py
new file mode 100755
index 0000000..9217be4
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/reactive/metrics_ci.py
@@ -0,0 +1,13 @@
+from charmhelpers.core.hookenv import (
+    status_set,
+)
+from charms.reactive import (
+    set_flag,
+    when_not,
+)
+
+
+@when_not('metrics-ci.installed')
+def install_metrics_ci():
+    status_set('active', "Ready!")
+    set_flag('metrics-ci.installed')
diff --git a/tests/charms/layers/metrics-ci/tests/00-setup b/tests/charms/layers/metrics-ci/tests/00-setup
new file mode 100755
index 0000000..f0616a5
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/tests/00-setup
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+sudo add-apt-repository ppa:juju/stable -y
+sudo apt-get update
+sudo apt-get install amulet python-requests -y
diff --git a/tests/charms/layers/metrics-ci/tests/10-deploy b/tests/charms/layers/metrics-ci/tests/10-deploy
new file mode 100755
index 0000000..7595ecf
--- /dev/null
+++ b/tests/charms/layers/metrics-ci/tests/10-deploy
@@ -0,0 +1,35 @@
+#!/usr/bin/python3
+
+import amulet
+import requests
+import unittest
+
+
+class TestCharm(unittest.TestCase):
+    def setUp(self):
+        self.d = amulet.Deployment()
+
+        self.d.add('metrics-demo')
+        self.d.expose('metrics-demo')
+
+        self.d.setup(timeout=900)
+        self.d.sentry.wait()
+
+        self.unit = self.d.sentry['metrics-demo'][0]
+
+    def test_service(self):
+        # test we can access over http
+        page = requests.get('http://{}'.format(self.unit.info['public-address']))
+        self.assertEqual(page.status_code, 200)
+        # Now you can use self.d.sentry[SERVICE][UNIT] to address each of the units and perform
+        # more in-depth steps. Each self.d.sentry[SERVICE][UNIT] has the following methods:
+        # - .info - An array of the information of that unit from Juju
+        # - .file(PATH) - Get the details of a file on that unit
+        # - .file_contents(PATH) - Get plain text output of PATH file from that unit
+        # - .directory(PATH) - Get details of directory
+        # - .directory_contents(PATH) - List files and folders in PATH on that unit
+        # - .relation(relation, service:rel) - Get relation data from return service
+
+        
+if __name__ == '__main__':
+    unittest.main()