Tox + Integration testing

This commit implements a VNF Descriptor-driven integration
test framework, which will lead to integration tests being able
to run via jenkins, and more robust testing in general.

N2VC:

- Allow the use of an event loop passed when instantiating N2VC
- Refactor the execution of the initial-config-primitive so that it can
be easily re-run, such as the case of when a proxy charm is deployed
before the VNF's VM is created.
- Refactor GetPrimitiveStatus, to return the status (queued, running,
complete, failed) of a primitive.
- Add GetPrimitiveOutput, to return the output of a completed primitive
- Fix model disconnection when executing a primitive (it was happening
in the wrong scope)
- Fix wait_for_application, which was previously unused and broken
- Add support for parameter's 'data-type' field
- Add support for better SSH key management, allowing for a proxy charm
to be deployed before the VNF, so that it's public SSH key can be
injected when the VNF's VM is created.

Integration Tests:

The integration tests are intended to exercise the expected
functionality of a VNF/charm: deploy the charm, configure it as required
(i.e., ssh credentials), and execute the VNF's
initial-config-primitives.

- test_native_charm: deploy a native charm to a juju-managed machine and
verify primitive execution works
- test_proxy_charm: deploy a proxy charm, configured to talk to a remote
machine, and verify primitive execution works
- test_metrics_native: deploy a native charm and collect a metric
- test_metrics_proxy: deploy a proxy charm and collect a metric from the
vnf
- test_no_initial-config-primitive: deploy a vnf without an
initial-config-primitive
- test_non-string_parameter: deploy a vnf with a non-string parameter in
initial-config-primitive
- test_no_parameter: deploy a vnf with a primitive with no parameters

General:
- Add a build target to tox.ini so that a .deb is built via Jenkins

TODO (in a follow-up commit):
- test multi-vdu, multi-charm
- test deploying a native charm to a manually-provisioned machine
- Update inline pydoc
- Add more integration tests
- Add global per-test timeout to catch stalled tests

Signed-off-by: Adam Israel <adam.israel@canonical.com>
Change-Id: Id322b45d65c44714e8051fc5764f8c20b76d846c
diff --git a/tests/charms/layers/metrics-proxy-ci/README.ex b/tests/charms/layers/metrics-proxy-ci/README.ex
new file mode 100644
index 0000000..b6816b2
--- /dev/null
+++ b/tests/charms/layers/metrics-proxy-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-proxy-ci/config.yaml b/tests/charms/layers/metrics-proxy-ci/config.yaml
new file mode 100644
index 0000000..51f2ce4
--- /dev/null
+++ b/tests/charms/layers/metrics-proxy-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-proxy-ci/layer.yaml b/tests/charms/layers/metrics-proxy-ci/layer.yaml
new file mode 100644
index 0000000..790dee6
--- /dev/null
+++ b/tests/charms/layers/metrics-proxy-ci/layer.yaml
@@ -0,0 +1,4 @@
+includes:
+    - 'layer:basic'
+    - 'layer:vnfproxy'
+    - 'layer:sshproxy'
diff --git a/tests/charms/layers/metrics-proxy-ci/metadata.yaml b/tests/charms/layers/metrics-proxy-ci/metadata.yaml
new file mode 100644
index 0000000..ae42434
--- /dev/null
+++ b/tests/charms/layers/metrics-proxy-ci/metadata.yaml
@@ -0,0 +1,12 @@
+name: metrics-proxy-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-proxy-ci/metrics.yaml b/tests/charms/layers/metrics-proxy-ci/metrics.yaml
new file mode 100644
index 0000000..dae092f
--- /dev/null
+++ b/tests/charms/layers/metrics-proxy-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-proxy-ci/reactive/metrics_ci.py b/tests/charms/layers/metrics-proxy-ci/reactive/metrics_ci.py
new file mode 100644
index 0000000..51ce49e
--- /dev/null
+++ b/tests/charms/layers/metrics-proxy-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('blocked', "Waiting for SSH credentials.")
+    set_flag('metrics-ci.installed')
diff --git a/tests/charms/layers/metrics-proxy-ci/tests/00-setup b/tests/charms/layers/metrics-proxy-ci/tests/00-setup
new file mode 100644
index 0000000..f0616a5
--- /dev/null
+++ b/tests/charms/layers/metrics-proxy-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-proxy-ci/tests/10-deploy b/tests/charms/layers/metrics-proxy-ci/tests/10-deploy
new file mode 100644
index 0000000..7595ecf
--- /dev/null
+++ b/tests/charms/layers/metrics-proxy-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()