Add tests, improve connection handling

- improve logging during connection handling
- add testing of the connection handler
This commit is contained in:
Devananda van der Veen
2015-03-28 23:35:20 -07:00
parent cfd5e47ee4
commit 24cb8c2458
2 changed files with 93 additions and 19 deletions

View File

@@ -115,19 +115,23 @@ Clients should always be prepared for:
"""
import ssl
import urllib2
from urlparse import urlparse
import httplib
import base64
import json
import hashlib
import gzip
import hashlib
import httplib
import json
import logging
import ssl
import StringIO
import sys
import urllib2
from urlparse import urlparse
LOG = logging.getLogger(__name__)
LOG.setLevel(logging.DEBUG)
class RedfishConnection(object):
"""Implements basic connection handling for Redfish APIs."""
@@ -138,12 +142,14 @@ class RedfishConnection(object):
self.user_name = user_name
self.password = password
self.auth_token = auth_token
self.enforse_SSL = enforse_SSL
self.enforce_SSL = enforce_SSL
# TODO: cache the token returned by this call
auth_dict = {'Password': self.password, 'UserName': self.user_name}
self.rest_post(self.host, '/rest/v1/sessions', None,
json.dumps(auth_dict), self.user_name, self.password)
self.rest_post('/rest/v1/sessions', None, json.dumps(auth_dict))
# TODO: do some schema discovery here and cache the result
LOG.debug('Connection established to host %s.', self.host)
def _op(self, operation, suburi, request_headers=None, request_body=None):
"""
@@ -155,7 +161,10 @@ class RedfishConnection(object):
:param request_body: optional JSON body
"""
url = urlparse('https://' + self.host + suburi)
# If the http schema wasn't specified, default to HTTPS
if self.host[0:4] != 'http':
self.host = 'https://' + self.host
url = urlparse(self.host + suburi)
if not isinstance(request_headers, dict): request_headers = dict()
@@ -178,7 +187,7 @@ class RedfishConnection(object):
if( sys.version_info.major == 2 and
sys.version_info.minor == 7 and
sys.version_info.micro >= 9 and
enforce_SSL == False):
self.enforce_SSL == False):
cont=ssl.SSLContext(ssl.PROTOCOL_TLSv1)
cont.verify_mode = ssl.CERT_NONE
conn = httplib.HTTPSConnection(host=url.netloc, strict=True, context=cont)
@@ -187,10 +196,7 @@ class RedfishConnection(object):
elif url.scheme == 'http':
conn = httplib.HTTPConnection(host=url.netloc, strict=True)
else:
assert(False)
conn.request(operation, url.path, headers=request_headers, body=json.dumps(request_body))
resp = conn.getresponse()
body = resp.read()
raise RedfishException(message='Unknown connection schema')
# NOTE: Do not assume every HTTP operation will return a JSON body.
# For example, ExtendedError structures are only required for HTTP 400
@@ -198,6 +204,9 @@ class RedfishConnection(object):
# of the other HTTP status code. In particular, 200 OK responses
# should not have to return any body.
conn.request(operation, url.path, headers=request_headers, body=json.dumps(request_body))
resp = conn.getresponse()
body = resp.read()
# NOTE: this makes sure the headers names are all lower cases because
# HTTP says they are case insensitive
headers = dict((x.lower(), y) for x, y in resp.getheaders())

View File

@@ -19,10 +19,75 @@ test_redfish
Tests for `redfish` module.
"""
import fixtures
import httplib
import mock
import ssl
from redfish.tests import base
from redfish import connection
class TestRedfish(base.TestCase):
def get_fake_params(host=None, user=None, pword=None):
if not host:
host = 'https://127.0.0.1'
if not user:
user = 'admin'
if not pword:
pword = 'password'
return (host, user, pword)
def test_something(self):
pass
def get_response():
class _response(object):
status = 200
def read(self):
return "{'foo': 'bar'}"
def getheaders(self):
return [('Fake-Header', 'fake value')]
return _response()
class TestException(Exception):
pass
class TestRedfishConnection(base.TestCase):
def setUp(self):
super(TestRedfishConnection, self).setUp()
self.log_fixture = self.useFixture(fixtures.FakeLogger())
self.con_mock = mock.MagicMock()
self.con_mock.getresponse = get_response
self.http_mock = mock.patch.object(httplib, 'HTTPConnection').start()
self.http_mock.return_value = self.con_mock
self.https_mock = mock.patch.object(httplib, 'HTTPSConnection').start()
self.https_mock.return_value = self.con_mock
self.addCleanup(self.http_mock.stop)
self.addCleanup(self.https_mock.stop)
def test_create_ok(self):
con = connection.RedfishConnection(*get_fake_params())
self.assertEqual(1, self.https_mock.call_count)
self.assertEqual(0, self.http_mock.call_count)
def test_create_calls_https_connect(self):
self.https_mock.side_effect = TestException()
self.assertRaises(TestException,
connection.RedfishConnection,
*get_fake_params(host='https://fake'))
def test_create_calls_http_connect(self):
self.http_mock.side_effect = TestException()
self.assertRaises(TestException,
connection.RedfishConnection,
*get_fake_params(host='http://fake'))
# FIXME: ssl module has no attribute 'SSLContext'
# NOTE: skip this test if sys.version_info (major, minor) != (2, 7) and micro < 9
# @mock.patch.object(ssl, 'SSLContext')
# def test_insecure_ssl(self, ssl_mock):
# ssl_mock.return_value = mock.Mock()
# con = connection.RedfishConnection(*get_fake_params)
# ssl_mock.assert_called_once_with(ssl.PROTOCOL_TLSv1)