Add unit testing to cbs docker client

Issue-ID: DCAEGEN2-60
Change-Id: I4e376ed2b417aceb2927997ff9be8e502829fd86
Signed-off-by: Tommy Carpenter <tommy@research.att.com>
diff --git a/onap-dcae-cbs-docker-client/.coveragerc b/onap-dcae-cbs-docker-client/.coveragerc
new file mode 100644
index 0000000..38c506c
--- /dev/null
+++ b/onap-dcae-cbs-docker-client/.coveragerc
@@ -0,0 +1,28 @@
+# .coveragerc to control coverage.py
+[run]
+branch = True
+cover_pylib = False
+include = */onap_dcae_cbs_docker_client/*.py
+
+[report]
+# Regexes for lines to exclude from consideration
+exclude_lines =
+    # Have to re-enable the standard pragma
+    pragma: no cover
+
+    # Don't complain about missing debug-only code:
+    def __repr__
+    if self\.debug
+
+    # Don't complain if tests don't hit defensive assertion code:
+    raise AssertionError
+    raise NotImplementedError
+
+    # Don't complain if non-runnable code isn't run:
+    if 0:
+    if __name__ == .__main__.:
+
+[xml]
+output = coverage-reports/coverage-configbinding.xml
+
+
diff --git a/onap-dcae-cbs-docker-client/.gitignore b/onap-dcae-cbs-docker-client/.gitignore
index 31c3000..c86ccf6 100644
--- a/onap-dcae-cbs-docker-client/.gitignore
+++ b/onap-dcae-cbs-docker-client/.gitignore
@@ -1,4 +1,96 @@
-dist/
+xunit-results.xml
 .DS_Store
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
 *.egg-info/
-*.pyc
+.installed.cfg
+*.egg
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+venv-tox/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*,cover
+.hypothesis/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# IPython Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# dotenv
+.env
+
+# virtualenv
+venv/
+ENV/
+
+# Spyder project settings
+.spyderproject
+
+# Rope project settings
+.ropeproject
+
+# Test report
+xunit-reports
+coverage-reports
diff --git a/onap-dcae-cbs-docker-client/Changelog.md b/onap-dcae-cbs-docker-client/Changelog.md
new file mode 100644
index 0000000..5027203
--- /dev/null
+++ b/onap-dcae-cbs-docker-client/Changelog.md
@@ -0,0 +1,10 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/) 
+and this project adheres to [Semantic Versioning](http://semver.org/).
+
+## [0.0.3]
+* Changelog started
+* Unit test suite created
+* Current test coverage = 82%
diff --git a/onap-dcae-cbs-docker-client/README.md b/onap-dcae-cbs-docker-client/README.md
index b5ddd04..1e622a7 100644
--- a/onap-dcae-cbs-docker-client/README.md
+++ b/onap-dcae-cbs-docker-client/README.md
@@ -19,13 +19,11 @@
 
 ## Via pip
 ```
-pip install --extra-index-url https://YOUR_NEXUS_PYPI_SERVER/simple cbs-docker-client
+pip install onap-dcae-cbs-docker-client
 ```
 
-## Via requirements.txt
-Add the following to your requirements.txt file
+# Testing
 ```
---extra-index-url https://YOUR_NEXUS_PYPI_SERVER/simple
-onap-dcae-cbs-docker-client==[version]
+tox -c tox-local.ini
 ```
 
diff --git a/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/client.py b/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/client.py
index 4423995..ce9ac74 100644
--- a/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/client.py
+++ b/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/client.py
@@ -41,7 +41,7 @@
         logger.error("Exception occured when querying Consul: either could not hit {0} or no service registered. Error code: {1}, Error Text: {2}".format(url, res.status_code, res.text))
         return None
 
-def _get_envs(): 
+def _get_envs():
     """
     Returns HOSTNAME, CONSUL_HOST, CONFIG_BINDING_SERVICE or crashes for caller to deal with
     """
@@ -53,15 +53,15 @@
 def get_config():
     """
     This call does not raise an exception if Consul or the CBS cannot complete the request.
-    It logs an error and returns {} if the config is not bindable. 
-    It could be a temporary network outage. Call me again later. 
+    It logs an error and returns {} if the config is not bindable.
+    It could be a temporary network outage. Call me again later.
 
-    It will raise an exception if the necessary env parameters were not set because that is irrecoverable. 
+    It will raise an exception if the necessary env parameters were not set because that is irrecoverable.
     This function is called in my /heatlhcheck, so this will be caught early.
     """
-    
+
     config = {}
- 
+
     HOSTNAME, CONSUL_HOST = _get_envs()
 
     #not sure how I as the component developer is supposed to know consul port
diff --git a/onap-dcae-cbs-docker-client/pom.xml b/onap-dcae-cbs-docker-client/pom.xml
index f1b267e..e42d529 100644
--- a/onap-dcae-cbs-docker-client/pom.xml
+++ b/onap-dcae-cbs-docker-client/pom.xml
@@ -33,21 +33,20 @@
 
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <!--sonar.skip>false</sonar.skip-->
+    <!-- Sonar -->
+    <sonar.skip>false</sonar.skip>
     <sonar.sources>.</sonar.sources>
-    <!-- customize the SONARQUBE URL -->
-    <!-- sonar.host.url>http://localhost:9000</sonar.host.url -->
-    <!-- below are language dependent -->
-    <!-- for Python -->
+    <sonar.junit.reportsPath>xunit-results.xml</sonar.junit.reportsPath>
+    <!-- 
+         <sonar.python.coverage.reportPath>coverage.xml</sonar.python.coverage.reportPath>
+         see https://docs.sonarqube.org/display/PLUG/Python+Coverage+Results+Import
+         Ant pattern describing the path to coverage reports, relative to projects root. Leave unset to use the default ("coverage-reports/coverage-*.xml").
+    -->
     <sonar.language>py</sonar.language>
     <sonar.pluginName>Python</sonar.pluginName>
     <sonar.inclusions>**/*.py</sonar.inclusions>
-    <!-- for JavaScaript -->
-    <!--
-    <sonar.language>js</sonar.language>
-    <sonar.pluginName>JS</sonar.pluginName>
-    <sonar.inclusions>**/*.js</sonar.inclusions>
-    -->
+    <sonar.exclusions>tests/*</sonar.exclusions>
+    <sonar.host.url>http://135.205.228.63:9000</sonar.host.url>
   </properties>
   <build>
     <finalName>${project.artifactId}-${project.version}</finalName>
diff --git a/onap-dcae-cbs-docker-client/setup.py b/onap-dcae-cbs-docker-client/setup.py
index 2f6a76a..9f23048 100644
--- a/onap-dcae-cbs-docker-client/setup.py
+++ b/onap-dcae-cbs-docker-client/setup.py
@@ -28,7 +28,7 @@
 setup(
     name = "onap_dcae_cbs_docker_client",
     description = "very lightweight client for a DCAE dockerized component to get it's config from the CBS",
-    version = "0.0.2",
+    version = "0.0.3",
     packages=find_packages(),
     author = "Tommy Carpenter",
     author_email = "tommy@research.att.com",
diff --git a/onap-dcae-cbs-docker-client/tests/test_client.py b/onap-dcae-cbs-docker-client/tests/test_client.py
new file mode 100644
index 0000000..6c9062b
--- /dev/null
+++ b/onap-dcae-cbs-docker-client/tests/test_client.py
@@ -0,0 +1,36 @@
+from onap_dcae_cbs_docker_client.client import get_config
+import requests
+
+class FakeResponse:
+    def __init__(self, status_code, thejson):
+        self.status_code = status_code
+        self.thejson = thejson
+    def raise_for_status(self):
+        pass
+    def json(self):
+        return self.thejson
+
+def test_client(monkeypatch):
+
+    def monkeyed_requests_get(url):
+        #mock all the get calls for existent and non-existent
+        if url == "http://consuldotcom:8500/v1/catalog/service/config_binding_service":
+            return FakeResponse(
+                       status_code = 200,
+                       thejson = [
+                           {"ServiceAddress" : "666.666.666.666",
+                            "ServicePort" : 8888
+                           }]
+                )
+        elif url == "http://666.666.666.666:8888/service_component/mybestfrienddotcom":
+            return FakeResponse(
+                       status_code = 200,
+                       thejson = {"key_to_your_heart" : 666})
+
+
+    monkeypatch.setattr('requests.get', monkeyed_requests_get)
+    assert(get_config() == {"key_to_your_heart" : 666})
+
+
+
+
diff --git a/onap-dcae-cbs-docker-client/tox-local.ini b/onap-dcae-cbs-docker-client/tox-local.ini
new file mode 100644
index 0000000..a5991a9
--- /dev/null
+++ b/onap-dcae-cbs-docker-client/tox-local.ini
@@ -0,0 +1,15 @@
+[tox]
+envlist = py27,py36
+
+[testenv]
+deps=
+    -rrequirements.txt
+    pytest
+    coverage
+    pytest-cov
+setenv = 
+    CONSUL_HOST = consuldotcom
+    HOSTNAME = mybestfrienddotcom
+commands=pytest --cov {envsitepackagesdir}/onap_dcae_cbs_docker_client  --cov-report html
+
+
diff --git a/onap-dcae-cbs-docker-client/tox.ini b/onap-dcae-cbs-docker-client/tox.ini
index 987b009..9e57fc0 100644
--- a/onap-dcae-cbs-docker-client/tox.ini
+++ b/onap-dcae-cbs-docker-client/tox.ini
@@ -8,4 +8,8 @@
     pytest
     coverage
     pytest-cov
-commands=pytest --junitxml xunit-results.xml --cov {envsitepackagesdir} --cov-report=xml
+setenv =
+    CONSUL_HOST = consuldotcom
+    HOSTNAME = mybestfrienddotcom
+
+commands=pytest --junitxml xunit-results.xml --cov {envsitepackagesdir}/onap_dcae_cbs_docker_client --cov-report=xml