Repository: pywbem/pywbemtools

Issue:
Pywbemcli connection list fails when data in ca-certs parameter
See pywbem issue #2322 for a description of the pywbem issue.  This revealed an issue in pywbemcli where were missing some validations, in particular in data restored from the connections file.


Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/32009013/badge)](https://coveralls.io/builds/32009013)

Coverage decreased (-0.1%) to 90.618% when pulling **896c1f37064f3595eb2ea877ca965e4f54896054 on ks/#663-connectfile-load-fail** into **0c1eef641be79e5b35369e6bb9d37e83038574d7 on master**.


Patch:
diff --git a/docs/changes.rst b/docs/changes.rst
index 2063359..b15b792 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -91,6 +91,12 @@ Released: not yet
   _cmd_class.py cmd_class_tree function to eliminate boundary conditions, and
   clarify code.
 
+* Extended parameter type testing in class PywbemServer so that all
+  constructor parameters are value tested.  This specifically fixes issue
+  where we were depending on WBEMConnection to test types of ca_certs
+  and invalid data types could get into the connections file. (See issue
+  #663).
+
 **Known issues:**
 
 * See `list of open issues`_.
diff --git a/docs/pywbemcli/cmdshelp.rst b/docs/pywbemcli/cmdshelp.rst
index 105bc0d..2fd64c5 100644
--- a/docs/pywbemcli/cmdshelp.rst
+++ b/docs/pywbemcli/cmdshelp.rst
@@ -70,13 +70,12 @@ Help text for ``pywbemcli``:
                                       during TLS/SSL handshake. If --no-verify client bypasses verification. Default: EnvVar
                                       PYWBEMCLI_VERIFY, or "--verify".
 
-      --ca-certs CACERTS              Certificates to be used for validating the certificate presented by the WBEM server
-                                      during TLS/SSL handshake: FILE: Use the certs in the specified PEM file; DIR: Use the
-                                      certs in the PEM files in the specified directory; "certifi" (pywbem 1.0 or later):
-                                      Use the certs provided by the certifi Python package; Default: EnvVar
-                                      PYWBEMCLI_CA_CERTS, or "certifi" (pywbem 1.0 or later), or the certs in the PEM files
-                                      in the first existing directory from from a list of system directories (pywbem before
-                                      1.0).
+      --ca-certs CACERTS              Certificates used to validate the certificate presented by the WBEM server during
+                                      TLS/SSL handshake: FILE: Use the certs in the specified PEM file; DIR: Use the certs
+                                      in the PEM files in the specified directory; "certifi" (pywbem 1.0 or later): Use the
+                                      certs provided by the certifi Python package; Default: EnvVar PYWBEMCLI_CA_CERTS, or
+                                      "certifi" (pywbem 1.0 or later), or the certs in the PEM files in the first existing
+                                      directory from from a system defined list of directories (pywbem before 1.0).
 
       -c, --certfile FILE             Path name of a PEM file containing a X.509 client certificate that is used to enable
                                       TLS/SSL 2-way authentication by presenting the certificate to the WBEM server during
diff --git a/pywbemtools/pywbemcli/_cmd_connection.py b/pywbemtools/pywbemcli/_cmd_connection.py
index 08bb05c..b41b4fa 100644
--- a/pywbemtools/pywbemcli/_cmd_connection.py
+++ b/pywbemtools/pywbemcli/_cmd_connection.py
@@ -769,5 +769,5 @@ def cmd_connection_list(context, options):
         headers,
         title='WBEM server connections({0}): ({1}: default, {2}: '
               'current)\nfile: {3}'.format(
-            table_type, dflt_sym, cur_sym, connections.connections_file),
+                  table_type, dflt_sym, cur_sym, connections.connections_file),
         table_format=output_format))
diff --git a/pywbemtools/pywbemcli/_connection_repository.py b/pywbemtools/pywbemcli/_connection_repository.py
index 68a826c..a1df3a4 100644
--- a/pywbemtools/pywbemcli/_connection_repository.py
+++ b/pywbemtools/pywbemcli/_connection_repository.py
@@ -25,8 +25,8 @@ from __future__ import absolute_import, print_function
 
 import os
 import yaml
-import yamlloader
 import six
+import yamlloader
 import click
 
 from ._pywbem_server import PywbemServer
@@ -221,8 +221,6 @@ class ConnectionRepository(object):
                     dict_ = yaml.safe_load(_fp)
                     # put all the connection definitions into a group
                     # in the connection file
-                    # TODO: on file created with touch this responds
-                    # TypeError: 'NoneType' object is not subscriptable
                     connections_dict = dict_[
                         ConnectionRepository.connections_group_name]
 
@@ -236,8 +234,14 @@ class ConnectionRepository(object):
                             self._loaded = True
                     except KeyError as ke:
                         raise KeyError("Items missing from record {0} in "
-                                       "connections file {1}".format
+                                       "connections file. Exception {1}".format
                                        (ke, self._connections_file))
+                    except TypeError as te:
+                        raise TypeError('Invalid object type in connections '
+                                        'file: "{0}"; server name: "{1}". '
+                                        'Item: {2}'.
+                                        format(self._connections_file, name,
+                                               te))
                 except ValueError as ve:
                     raise ValueError("Invalid YAML in connections file {0}. "
                                      "Exception {1}".format
diff --git a/pywbemtools/pywbemcli/_pywbem_server.py b/pywbemtools/pywbemcli/_pywbem_server.py
index 84d53f3..9db1165 100644
--- a/pywbemtools/pywbemcli/_pywbem_server.py
+++ b/pywbemtools/pywbemcli/_pywbem_server.py
@@ -21,6 +21,7 @@ from __future__ import absolute_import, print_function, unicode_literals
 
 import re
 from collections import OrderedDict
+import six
 import click
 
 import pywbem
@@ -35,7 +36,16 @@ WBEM_SERVER_OBJ = None
 PYWBEMCLI_LOG = 'pywbemcli.log'
 
 
-def _validate_server(server):
+def _raise_typeerror(name, value, rqd_type):
+    """
+    Generate a TypeError for a property in pywbem_server setter that has an
+    invalid type
+    """
+    raise TypeError('Property "{0}" value: {1} must be type: "{2}", not type: '
+                    '"{3}"'.format(name, value, rqd_type, type(value)))
+
+
+def _validate_server_url(server):
     """
     Validate  and possibly complete the wbemserver url provided.
 
@@ -58,6 +68,8 @@ def _validate_server(server):
     elif re.match(r"^https{0,1}://", server) is not None:
         url = server
 
+    # TODO Future: We are trying to make exceptions in these support classes
+    # independent of click so this should become ValueError
     elif re.match(r"^[a-zA-Z0-9]+://", server) is not None:
         raise click.ClickException('Invalid scheme on server argument. {}'
                                    ' Use "http" or "https"'.format(server))
@@ -166,7 +178,7 @@ class PywbemServer(object):
 
         # pylint: disable=attribute-defined-outside-init
         if server:
-            self._server = _validate_server(server)
+            self._server = _validate_server_url(server)
         else:
             self._server = server
 
@@ -180,7 +192,12 @@ class PywbemServer(object):
     @mock_server.setter
     def mock_server(self, mock_server):
         """Setter method; for a description see the getter method."""
-
+        if mock_server:
+            if not isinstance(mock_server, (list, six.string_types)):
+                _raise_typeerror("mock_server", mock_server, 'list, string')
+            for ms in mock_server:
+                if not isinstance(ms, six.string_types):
+                    _raise_typeerror("mock_server item", mock_server, 'string')
         # assure this is list type in yaml output
         if mock_server is None:
             mock_server = []
@@ -197,6 +214,9 @@ class PywbemServer(object):
     @name.setter
     def name(self, name):
         """Setter method; for a description see the getter method."""
+        if name:
+            if not isinstance(name, six.string_types):
+                _raise_typeerror("name", name, 'string')
 
         # pylint: disable=attribute-defined-outside-init
         self._name = name
@@ -212,6 +232,9 @@ class PywbemServer(object):
     def user(self, user):
         """Setter method; for a description see the getter method."""
 
+        if user and not isinstance(user, six.string_types):
+            _raise_typeerror("user", user, 'string')
+
         # pylint: disable=attribute-defined-outside-init
         self._user = user
 
@@ -225,7 +248,8 @@ class PywbemServer(object):
     @password.setter
     def password(self, password):
         """Setter method; for a description see the getter method."""
-
+        if password and not isinstance(password, six.string_types):
+            _raise_typeerror("password", password, 'string')
         # pylint: disable=attribute-defined-outside-init
         self._password = password
 
@@ -239,7 +263,9 @@ class PywbemServer(object):
     @default_namespace.setter
     def default_namespace(self, default_namespace):
         """Setter method; for a description see the getter method."""
-
+        if default_namespace and not isinstance(default_namespace,
+                                                six.string_types):
+            _raise_typeerror("default-namespace", default_namespace, 'string')
         # pylint: disable=attribute-defined-outside-init
         self._default_namespace = default_namespace
 
@@ -248,17 +274,20 @@ class PywbemServer(object):
         """
         :term:`int`: Connection timeout to be used on requests in seconds
         """
+        if self._timeout:
+            assert isinstance(self._timeout, int)
         return self._timeout
 
     @timeout.setter
     def timeout(self, timeout):
         """Setter method; for a description see the getter method."""
-
         if timeout is None:   # disallow None
-            ValueError('Timout of None not allowed')
-        if timeout < 0 or timeout > MAX_TIMEOUT:
-            ValueError('Timeout option({}) out of range {} to {} sec'
-                       .format(timeout, 0, MAX_TIMEOUT))
+            raise ValueError('timeout option of None not allowed')
+        if not isinstance(timeout, int):
+            _raise_typeerror("timeout", timeout, 'integer')
+        if not 0 < timeout <= MAX_TIMEOUT:
+            raise ValueError('Timeout option "{0}" out of range {1} to {2} sec'
+                             .format(timeout, 0, MAX_TIMEOUT))
         # pylint: disable=attribute-defined-outside-init
         self._timeout = timeout
 
@@ -274,10 +303,10 @@ class PywbemServer(object):
         """Setter method; for a description see the getter method."""
 
         if use_pull is None or isinstance(use_pull, bool):
+            # pylint: disable=attribute-defined-outside-init
             self._use_pull = use_pull
         else:
-            ValueError("use_pull must be boolean, not {}.".
-                       format(type(use_pull)))
+            _raise_typeerror("use-pull", use_pull, 'boolean')
 
     @property
     def verify(self):
@@ -290,22 +319,26 @@ class PywbemServer(object):
     @verify.setter
     def verify(self, verify):
         """Setter method; for a description see the getter method."""
-
+        if verify and not isinstance(verify, bool):
+            _raise_typeerror("verify", verify, 'boolean')
         # pylint: disable=attribute-defined-outside-init
         self._verify = verify
 
     @property
     def certfile(self):
         """
-        :term:`string`: certtificate for server or None if parameter not
+        :term:`string`: certificate for server or None if parameter not
         provided on input
         """
+        if self._certfile:
+            assert isinstance(self._certfile, six.string_types)
         return self._certfile
 
     @certfile.setter
     def certfile(self, certfile):
         """Setter method; for a description see the getter method."""
-
+        if certfile and not isinstance(certfile, six.string_types):
+            _raise_typeerror("certfile", certfile, 'string')
         # pylint: disable=attribute-defined-outside-init
         self._certfile = certfile
 
@@ -314,11 +347,15 @@ class PywbemServer(object):
         """
         :term:`string`: keyfile or None if no keyfile parameter input
         """
+        if self._keyfile:
+            assert isinstance(self._keyfile, six.string_types)
         return self._keyfile
 
     @keyfile.setter
     def keyfile(self, keyfile):
         """Setter method; for a description see the getter method."""
+        if keyfile and not isinstance(keyfile, six.string_types):
+            _raise_typeerror("keyfile", keyfile, 'string')
 
         # pylint: disable=attribute-defined-outside-init
         self._keyfile = keyfile
@@ -326,14 +363,17 @@ class PywbemServer(object):
     @property
     def ca_certs(self):
         """
-        list of :term:`string`: List of ca_certs if provided on cmd line
+        :term:`string`: String that defines certs for server validation"
         """
+        if self._ca_certs:
+            assert isinstance(self._ca_certs, six.string_types)
         return self._ca_certs
 
     @ca_certs.setter
     def ca_certs(self, ca_certs):
         """Setter method; for a description see the getter method."""
-
+        if ca_certs and not isinstance(ca_certs, six.string_types):
+            _raise_typeerror("ca_certs", ca_certs, 'string')
         # pylint: disable=attribute-defined-outside-init
         self._ca_certs = ca_certs
 
@@ -365,8 +405,9 @@ class PywbemServer(object):
                 confirmation_prompt=False, type=str, err=True)
             ctx.spinner_start()
             # pylint: disable=attribute-defined-outside-init
-            self._password = password
+            self.password = password
         else:
+            # TODO: Again we want to isolate the click excpetions in future
             raise click.ClickException("{cmd} requires user/password, but "
                                        "no password provided."
                                        .format(cmd=ctx.invoked_subcommand))
diff --git a/pywbemtools/pywbemcli/pywbemcli.py b/pywbemtools/pywbemcli/pywbemcli.py
index 5fe4c0f..d7ea48f 100644
--- a/pywbemtools/pywbemcli/pywbemcli.py
+++ b/pywbemtools/pywbemcli/pywbemcli.py
@@ -149,8 +149,8 @@ def validate_connections_file(connections_repo):
 @click.option('--ca-certs', type=str, metavar="CACERTS",
               default=None,  # defaulted in code
               envvar=PywbemServer.ca_certs_envvar,
-              help='Certificates to be used for validating the certificate '
-                   'presented by the WBEM server during TLS/SSL handshake: '
+              help='Certificates used to validate the certificate presented '
+                   'by the WBEM server during TLS/SSL handshake: '
                    'FILE: Use the certs in the specified PEM file; '
                    'DIR: Use the certs in the PEM files in the specified '
                    'directory; '
@@ -158,7 +158,7 @@ def validate_connections_file(connections_repo):
                    'the certifi Python package; '
                    'Default: EnvVar {ev}, or "certifi" (pywbem 1.0 or later), '
                    'or the certs in the PEM files in the first existing '
-                   'directory from from a list of system directories '
+                   'directory from from a system defined list of directories '
                    '(pywbem before 1.0).'.
                    format(ev=PywbemServer.ca_certs_envvar))
 @click.option('-c', '--certfile', type=str, metavar="FILE",
@@ -426,6 +426,8 @@ def cli(ctx, server, connection_name, default_namespace, user, password,
     resolved_default_namespace = default_namespace or DEFAULT_NAMESPACE
     resolved_timestats = timestats or DEFAULT_TIMESTATS
     resolved_verify = DEFAULT_VERIFY if verify is None else verify
+
+    # There is no default ca_certs
     resolved_ca_certs = ca_certs  # None should be passed on
 
     # Create the connections repository object that will be included in the
@@ -651,7 +653,7 @@ def cli(ctx, server, connection_name, default_namespace, user, password,
                               display_attrs=True)
 
     _python_nm = sys.version_info[0:2]
-    if _python_nm == (2, 7) or _python_nm == (3, 4):
+    if _python_nm in ((2, 7), (3, 4)):
         deprecation_warning(
             "Deprecation: Pywbemcli support for Python {}.{} is deprecated "
             "and will be removed in a future version".


Test patch:
diff --git a/tests/unit/test_context_obj.py b/tests/unit/test_context_obj.py
index 028239b..c324c09 100755
--- a/tests/unit/test_context_obj.py
+++ b/tests/unit/test_context_obj.py
@@ -47,6 +47,8 @@ class ContextObjTests(unittest.TestCase):
         log = 'all'
         verbose = True
         pdb = False
+        deprecation_warnings = False
+        connections_repo = None
 
         ctxobj = ContextObj(
             pywbem_server=svr,
@@ -56,7 +58,9 @@ class ContextObjTests(unittest.TestCase):
             timestats=timestats,
             log=log,
             verbose=verbose,
-            pdb=pdb)
+            pdb=pdb,
+            deprecation_warnings=deprecation_warnings,
+            connections_repo=connections_repo)
 
         self.assertEqual(ctxobj.pywbem_server, svr)
 
diff --git a/tests/unit/test_general_options.py b/tests/unit/test_general_options.py
index cef1be8..2644f7c 100644
--- a/tests/unit/test_general_options.py
+++ b/tests/unit/test_general_options.py
@@ -114,17 +114,17 @@ General Options:
                                   client bypasses verification. Default: EnvVar
                                   PYWBEMCLI_VERIFY, or "--verify".
 
-  --ca-certs CACERTS              Certificates to be used for validating the
-                                  certificate presented by the WBEM server
-                                  during TLS/SSL handshake: FILE: Use the certs
-                                  in the specified PEM file; DIR: Use the certs
-                                  in the PEM files in the specified directory;
+  --ca-certs CACERTS              Certificates used to validate the certificate
+                                  presented by the WBEM server during TLS/SSL
+                                  handshake: FILE: Use the certs in the
+                                  specified PEM file; DIR: Use the certs in the
+                                  PEM files in the specified directory;
                                   "certifi" (pywbem 1.0 or later): Use the certs
                                   provided by the certifi Python package;
                                   Default: EnvVar PYWBEMCLI_CA_CERTS, or
                                   "certifi" (pywbem 1.0 or later), or the certs
                                   in the PEM files in the first existing
-                                  directory from from a list of system
+                                  directory from from a system defined list of
                                   directories (pywbem before 1.0).
 
   -c, --certfile FILE             Path name of a PEM file containing a X.509
@@ -563,21 +563,22 @@ TEST_CASES = [
     #  Test errors with --name option, --mock-server option
     #
 
-    ['Verify -n option with non-existend connection file fails',
-     {'general': ['-n', 'fred', '--connections-file', './blah.yaml'],
+    ['Verify -n option with non-existent connection file fails',
+     {'general': ['-n', 'fred', '--connections-file', './filenotfound.yaml'],
       'cmdgrp': 'connection',
       'args': ['show']},
-     {'stderr': ['Connections file: "./blah.yaml" does not exist.',
+     {'stderr': ['Connections file: "./filenotfound.yaml" does not exist.',
                  'Aborted!'],
       'rc': 1,
       'test': 'innows'},
      None, OK],
 
     ['Verify --name with non-existend connection file fails',
-     {'general': ['--name', 'fred', '--connections-file', './blah.yaml'],
+     {'general': ['--name', 'fred', '--connections-file',
+                  './filenotfound.yaml'],
       'cmdgrp': 'connection',
       'args': ['show']},
-     {'stderr': ['Connections file: "./blah.yaml" does not exist.',
+     {'stderr': ['Connections file: "./filenotfound.yaml" does not exist.',
                  'Aborted!'],
       'rc': 1,
       'test': 'innows'},
diff --git a/tests/unit/test_pywbem_server.py b/tests/unit/test_pywbem_server.py
index f363de3..4be7197 100755
--- a/tests/unit/test_pywbem_server.py
+++ b/tests/unit/test_pywbem_server.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
 # (C) Copyright 2017 IBM Corp.
 # (C) Copyright 2017 Inova Development Inc.
 # All Rights Reserved
@@ -22,12 +20,25 @@ Unit tests for PywbemServer class methods.
 
 from __future__ import absolute_import, print_function
 
+import os
 import pytest
 
 from pywbemtools.pywbemcli._pywbem_server import PywbemServer
 
 from tests.unit.pytest_extensions import simplified_test_function
 
+OK = True
+RUN = True
+FAIL = False
+PDB = "pdb"
+
+# This is needed by the connect test. Just the file name
+# created is required for WBEMConnection constructor with
+# cert and key files.
+SCRIPT_DIR = os.path.dirname(__file__)
+FAKE_PEM = 'test.pem'
+FAKE_PEM_PATH = os.path.join(SCRIPT_DIR, FAKE_PEM)
+
 
 TESTCASES_INITIALIZE = [
     # TESTCASES for pywbem_server intitalize
@@ -37,13 +48,12 @@ TESTCASES_INITIALIZE = [
     # * kwargs: Keyword arguments for the test function and response:
     #   * init_kwargs: __init__ kwargs.
     #   * exp_attrs: Dict of expected attributes of resulting object.
-    #   * exp_repr: string
     # * exp_exc_types: Expected exception type(s), or None.
     # * exp_warn_types: Expected warning type(s), or None.
     # * condition: Boolean condition for testcase to run, or 'pdb' for debugger
 
     (
-        "Verify url arg only",
+        "1. Verify url arg only",
         dict(
             init_args=[],
             init_kwargs=dict(
@@ -52,41 +62,49 @@ TESTCASES_INITIALIZE = [
             exp_attrs=dict(
                 server=u'http://localhost',
                 default_namespace='root/cimv2',
+                name='default',
                 user=None,
                 password=None,
+                timeout=30,
                 verify=None,
+                use_pull=None,
                 certfile=None,
                 keyfile=None,
+                ca_certs=None,
                 mock_server=[]
             )
         ),
-        None, None, True
+        None, None, OK
     ),
     (
-        "Verify multiple arguments",
+        "2. Verify server, default_namespace, user, password",
         dict(
             init_args=[],
             init_kwargs=dict(
                 server='http://localhost',
-                default_namespace='root/cimv2',
+                default_namespace='interop',
                 user='fred',
                 password='blah',
             ),
             exp_attrs=dict(
                 server=u'http://localhost',
-                default_namespace='root/cimv2',
+                default_namespace='interop',
+                name='default',
                 user='fred',
                 password='blah',
+                timeout=30,
                 verify=None,
+                use_pull=True,
                 certfile=None,
                 keyfile=None,
+                ca_certs=None,
                 mock_server=[]
             )
         ),
-        None, None, True
+        None, None, OK
     ),
     (
-        "Verify url arg only",
+        "3. Verify url plus all allowed other arguments",
         dict(
             init_args=[],
             init_kwargs=dict(
@@ -94,25 +112,32 @@ TESTCASES_INITIALIZE = [
                 default_namespace='root/cimv3',
                 user='fred',
                 password='blah',
-                verify=True,
+                timeout=50,
+                use_pull=True,
+                verify=False,
                 certfile='mycert.pem',
-                keyfile='mykey.pem'
+                keyfile='mykey.pem',
+                ca_certs='blah'
             ),
             exp_attrs=dict(
                 server=u'http://localhost',
                 default_namespace='root/cimv3',
+                name='default',
                 user='fred',
                 password='blah',
-                verify=True,
+                timeout=50,
+                verify=False,
+                use_pull=True,
                 certfile='mycert.pem',
                 keyfile='mykey.pem',
+                ca_certs='blah',
                 mock_server=[]
             )
         ),
-        None, None, True
+        None, None, OK
     ),
     (
-        "Verify mockfile",
+        "4. Verify mockfile",
         dict(
             init_args=[],
             init_kwargs=dict(
@@ -121,15 +146,293 @@ TESTCASES_INITIALIZE = [
             exp_attrs=dict(
                 server=None,
                 default_namespace='root/cimv2',
+                name='default',
                 user=None,
                 password=None,
+                timeout=30,
                 verify=None,
+                use_pull=None,
                 certfile=None,
                 keyfile=None,
+                ca_certs=None,
                 mock_server='testmock.mof'
             )
         ),
-        None, None, True
+        None, None, OK
+    ),
+    (
+        "5. Verify mockfile, list",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                mock_server=['testmock.mof'],
+            ),
+            exp_attrs=dict(
+                server=None,
+                default_namespace='root/cimv2',
+                name='default',
+                user=None,
+                password=None,
+                timeout=30,
+                verify=None,
+                use_pull=None,
+                certfile=None,
+                keyfile=None,
+                ca_certs=None,
+                mock_server=['testmock.mof']
+            )
+        ),
+        None, None, OK
+    ),
+    (
+        "6. Verify mockfile, list with multiple and timeout 0",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                timeout=100,
+                mock_server=['testmock.mof', 'test.py'],
+            ),
+            exp_attrs=dict(
+                server=None,
+                default_namespace='root/cimv2',
+                name='default',
+                user=None,
+                password=None,
+                timeout=100,
+                verify=None,
+                use_pull=None,
+                certfile=None,
+                keyfile=None,
+                ca_certs=None,
+                mock_server=['testmock.mof', 'test.py']
+            )
+        ),
+        None, None, OK
+    ),
+
+    # verify type errors
+    (
+        "E1. Verify mockfile, list with multiple and timeout 0",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                timeout=0,
+                mock_server=3,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+
+    (
+        "E2. Verify server TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                server=['fred'],
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E3. Verify name TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                name=['fred'],
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E4. Verify name TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                name=1.3456,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+
+    (
+        "E5. Verify default-namespace TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                default_namespace=3,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E6. Verify name TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                name=3,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E7. Verify user TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                user=3,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E8. Verify password TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                password=3,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E9. Verify timeout TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                timeout='3',
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E10. Verify verify TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                verify='3',
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E11. Verify use-pull TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                use_pull='blah',
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E12. Verify certfile TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                certfile=True,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E13. Verify keyfile TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                keyfile=True,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E14. Verify ca_certs TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                ca_certs=True,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E15. Verify ca_certs TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                ca_certs=True,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E15. Verify mock_server TypeError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                mock_server=True,
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E15. Verify mock_server TypeError with array",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                mock_server=["blah.mof", 3],
+            ),
+        ),
+        TypeError, None, OK
+    ),
+    (
+        "E16. Verify timeout None valueError",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                timeout=None,
+            ),
+            exp_attrs=dict(),
+        ),
+        ValueError, None, OK
+    ),
+
+    # ValueError tests
+
+    (
+        "E17. Simultaneous server and mock server not allowed",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                server="http://blay",
+                mock_server="blah.mof"
+            ),
+            exp_attrs=dict(),
+        ),
+        ValueError, None, OK
+    ),
+    (
+        "E18. Verify timeout < 0 ValueError ",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                server='http://blah',
+                timeout=-3,
+            ),
+            exp_attrs=dict(),
+        ),
+        ValueError, None, OK
+    ),
+    (
+        "E19. Verify timeout < 0 ValueError ",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                server='http://blah',
+                timeout=99999,
+            ),
+            exp_attrs=dict(),
+        ),
+        ValueError, None, OK
     ),
 ]
 
@@ -152,13 +455,17 @@ def test_initialize(testcase, init_args, init_kwargs, exp_attrs):
     assert svr.default_namespace == exp_attrs['default_namespace']
     assert svr.user == exp_attrs['user']
     assert svr.password == exp_attrs['password']
+    assert svr.timeout == exp_attrs['timeout']
     assert svr.verify == exp_attrs['verify']
     assert svr.certfile == exp_attrs['certfile']
     assert svr.keyfile == exp_attrs['keyfile']
+    assert svr.ca_certs == exp_attrs['ca_certs']
     assert svr.mock_server == exp_attrs['mock_server']
 
-    # assert '{0}'.format(svr) == \
-    #                 "PywbemServer(url=http://localhost name=default)"
+    repr_str = repr(svr)
+    if exp_attrs['server']:
+        assert "server=" in repr_str
+        assert exp_attrs['server'] in repr_str
 
 
 TESTCASES_CONNECT = [
@@ -193,7 +500,33 @@ TESTCASES_CONNECT = [
                 mock_server=None
             )
         ),
-        None, None, True
+        None, None, OK
+    ),
+    (
+        "Verify with security params",
+        dict(
+            init_args=[],
+            init_kwargs=dict(
+                server='http://localhost',
+                user='fred',
+                password='blah',
+                verify=True,
+                certfile=FAKE_PEM_PATH,
+                keyfile=FAKE_PEM_PATH,
+            ),
+            exp_attrs=dict(
+                server=u'http://localhost',
+                default_namespace='root/cimv2',
+                user='fred',
+                password='blah',
+                verify=True,
+                certfile=FAKE_PEM_PATH,
+                keyfile=FAKE_PEM_PATH,
+                ca_certs=None,
+                mock_server=None
+            )
+        ),
+        None, None, OK
     ),
 ]
 
@@ -208,8 +541,19 @@ def test_connect(testcase, init_args, init_kwargs, exp_attrs):
     """
     svr = PywbemServer(*init_args, **init_kwargs)
 
-    # connect and test connection results
-    svr.create_connection(False)
+    # Create temp fake file.
+    # NOTE: We cannot use fixtures because we are using simplified_test_function
+    open(FAKE_PEM_PATH, 'a').close()
+
+    # connect and test connection results. Try block insures finally is
+    # called.
+    try:
+        svr.create_connection(False)
+    except Exception:
+        pass  # pass all exceptions
+    finally:
+        # remove the PEM file
+        os.remove(FAKE_PEM_PATH)
 
     # Ensure that exceptions raised in the remainder of this function
     # are not mistaken as expected exceptions
@@ -223,9 +567,4 @@ def test_connect(testcase, init_args, init_kwargs, exp_attrs):
     assert svr.certfile == exp_attrs['certfile']
     assert svr.keyfile == exp_attrs['keyfile']
 
-
-# TODO test name setter
-# TODO password setter
-# TODO invalid timeout value
-# TODO password prompt (get_password)
-# TODO str and repr strings
+# TODO: Add test for get_password.