Add tests, improve connection handling
- improve logging during connection handling - add testing of the connection handler
This commit is contained in:
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user