Merge "Use betamax hooks to mask fixture results"

This commit is contained in:
Jenkins 2016-05-24 02:04:11 +00:00 committed by Gerrit Code Review
commit fe4a9ca120
3 changed files with 179 additions and 1 deletions

View 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']))

View File

@ -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)

View 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'********')