Merge "Use betamax hooks to mask fixture results"
This commit is contained in:
commit
fe4a9ca120
56
keystoneauth1/fixture/hooks.py
Normal file
56
keystoneauth1/fixture/hooks.py
Normal file
@ -0,0 +1,56 @@
|
||||
# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""Custom hooks for betamax and keystoneauth.
|
||||
|
||||
Module providing a set of hooks specially designed for
|
||||
interacting with clouds and keystone authentication.
|
||||
|
||||
:author: Yolanda Robla
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def mask_credentials(content):
|
||||
"""it will mask all credentials for a given content."""
|
||||
content = re.sub(r'"tenantName": "(.*?)"',
|
||||
'"tenantName": "dummy"', content)
|
||||
content = re.sub(r'"username": "(.*?)"',
|
||||
'"username": "dummy"', content)
|
||||
content = re.sub(r'"password": "(.*?)"',
|
||||
'"password": "********"', content)
|
||||
return content
|
||||
|
||||
|
||||
def update_expiration(content):
|
||||
"""it will set token expiration in the long future."""
|
||||
content = re.sub(r'"expires": "(.*?)"',
|
||||
'"expires": "9999-12-31T23:59:59Z"', content)
|
||||
return content
|
||||
|
||||
|
||||
def pre_record_hook(interaction, cassette):
|
||||
"""Hook to mask saved data.
|
||||
|
||||
This hook will be triggered before saving the interaction, and
|
||||
will perform two tasks:
|
||||
- mask user, project and password in the saved data
|
||||
- set token expiration time to an inifinite time.
|
||||
"""
|
||||
request_body = interaction.data['request']['body']
|
||||
request_body['string'] = mask_credentials(
|
||||
request_body['string'])
|
||||
response_body = interaction.data['response']['body']
|
||||
response_body['string'] = update_expiration(mask_credentials(
|
||||
response_body['string']))
|
@ -19,19 +19,22 @@ import fixtures
|
||||
import mock
|
||||
import requests
|
||||
|
||||
from keystoneauth1.fixture import hooks
|
||||
from keystoneauth1 import session
|
||||
|
||||
|
||||
class BetamaxFixture(fixtures.Fixture):
|
||||
|
||||
def __init__(self, cassette_name, cassette_library_dir=None,
|
||||
serializer=None, record=False):
|
||||
serializer=None, record=False,
|
||||
pre_record_hook=hooks.pre_record_hook):
|
||||
self.cassette_library_dir = cassette_library_dir
|
||||
self.serializer = serializer
|
||||
self.record = record
|
||||
self.cassette_name = cassette_name
|
||||
if serializer:
|
||||
betamax.Betamax.register_serializer(serializer)
|
||||
self.pre_record_hook = pre_record_hook
|
||||
|
||||
def setUp(self):
|
||||
super(BetamaxFixture, self).setUp()
|
||||
@ -53,6 +56,9 @@ def _construct_session_with_betamax(fixture, session_obj=None):
|
||||
# Use TCPKeepAliveAdapter to fix bug 1323862
|
||||
for scheme in list(session_obj.adapters.keys()):
|
||||
session_obj.mount(scheme, session.TCPKeepAliveAdapter())
|
||||
|
||||
with betamax.Betamax.configure() as config:
|
||||
config.before_record(callback=fixture.pre_record_hook)
|
||||
fixture.recorder = betamax.Betamax(
|
||||
session_obj, cassette_library_dir=fixture.cassette_library_dir)
|
||||
|
||||
|
116
keystoneauth1/tests/unit/test_betamax_hooks.py
Normal file
116
keystoneauth1/tests/unit/test_betamax_hooks.py
Normal file
@ -0,0 +1,116 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import betamax
|
||||
import json
|
||||
from requests import models
|
||||
import testtools
|
||||
|
||||
try:
|
||||
from requests.packages.urllib3._collections import HTTPHeaderDict
|
||||
except ImportError:
|
||||
from betamax.headers import HTTPHeaderDict
|
||||
|
||||
from keystoneauth1.fixture import hooks
|
||||
|
||||
|
||||
class TestBetamaxHooks(testtools.TestCase):
|
||||
|
||||
def test_pre_record_hook(self):
|
||||
with betamax.Betamax.configure() as config:
|
||||
config.before_record(callback=hooks.pre_record_hook)
|
||||
|
||||
cassette = betamax.cassette.Cassette(
|
||||
'test_pre_record_hook', 'json', record_mode=None,
|
||||
cassette_library_dir='keystoneauth1/tests/unit/data')
|
||||
|
||||
# Create a new object to serialize
|
||||
r = models.Response()
|
||||
r.status_code = 200
|
||||
r.reason = 'OK'
|
||||
r.encoding = 'utf-8'
|
||||
r.headers = {}
|
||||
r.url = 'http://192.168.0.19:35357/'
|
||||
|
||||
body_content = {
|
||||
'auth': {
|
||||
'passwordCredentials': {
|
||||
'username': 'user',
|
||||
'password': 'password'
|
||||
},
|
||||
'tenantName': 'dummy',
|
||||
},
|
||||
'access': {
|
||||
'token': {
|
||||
'expires': '2001-01-01T00:00:00Z'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body_content = {
|
||||
'body': {
|
||||
'string': json.dumps(body_content),
|
||||
'encoding': 'utf-8',
|
||||
}
|
||||
}
|
||||
|
||||
betamax.util.add_urllib3_response(
|
||||
body_content, r,
|
||||
HTTPHeaderDict({'Accept': 'application/json'}))
|
||||
response = r
|
||||
|
||||
# Create an associated request
|
||||
r = models.Request()
|
||||
r.method = 'GET'
|
||||
r.url = 'http://192.168.0.19:35357/'
|
||||
r.headers = {}
|
||||
r.data = {}
|
||||
response.request = r.prepare()
|
||||
response.request.headers.update(
|
||||
{'User-Agent': 'betamax/test header'}
|
||||
)
|
||||
|
||||
response.request.body = json.dumps({
|
||||
'auth': {
|
||||
'passwordCredentials': {
|
||||
'username': 'user',
|
||||
'password': 'password'
|
||||
},
|
||||
'tenantName': 'dummy'
|
||||
}
|
||||
})
|
||||
|
||||
interaction = cassette.save_interaction(response, response.request)
|
||||
|
||||
# check that all values have been masked
|
||||
response_content = json.loads(
|
||||
interaction.data['response']['body']['string'])
|
||||
self.assertEqual(
|
||||
response_content['access']['token']['expires'],
|
||||
u'9999-12-31T23:59:59Z')
|
||||
self.assertEqual(response_content['auth']['tenantName'], u'dummy')
|
||||
self.assertEqual(
|
||||
response_content['auth']['passwordCredentials']['username'],
|
||||
u'dummy')
|
||||
self.assertEqual(
|
||||
response_content['auth']['passwordCredentials']['password'],
|
||||
u'********')
|
||||
|
||||
request_content = json.loads(
|
||||
interaction.data['response']['body']['string'])
|
||||
self.assertEqual(request_content['auth']['tenantName'], u'dummy')
|
||||
self.assertEqual(
|
||||
request_content['auth']['passwordCredentials']['username'],
|
||||
u'dummy')
|
||||
self.assertEqual(
|
||||
request_content['auth']['passwordCredentials']['password'],
|
||||
u'********')
|
Loading…
Reference in New Issue
Block a user