Update keystoneauth fixture to support v3

Improved the hook to be more flexible, and support v3
request/response masking. Improved testing, adding full
json samples to be parsed.

Change-Id: I5e7e2bc9627f423abcaaaa1e3335a46ab5377ef8
This commit is contained in:
Yolanda Robla 2016-05-24 12:19:04 +02:00
parent 29aaac32e1
commit 797865c1d5
7 changed files with 196 additions and 56 deletions

View File

@ -19,25 +19,24 @@
:author: Yolanda Robla
"""
import re
import json
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 mask_fixture_values(nested, prev_key):
for key, value in nested.items():
if isinstance(value, dict):
mask_fixture_values(value, key)
else:
if key in ('tenantName', 'username'):
nested[key] = 'dummy'
elif prev_key in ('user', 'project', 'tenant') and key == 'name':
nested[key] = 'dummy'
elif prev_key == 'domain' and key == 'id':
nested[key] = 'dummy'
elif key == 'password':
nested[key] = '********'
elif prev_key == 'token' and key in ('expires', 'expires_at'):
nested[key] = '9999-12-31T23:59:59Z'
def pre_record_hook(interaction, cassette):
@ -49,8 +48,11 @@ def pre_record_hook(interaction, cassette):
- set token expiration time to an inifinite time.
"""
request_body = interaction.data['request']['body']
request_body['string'] = mask_credentials(
request_body['string'])
parsed_content = json.loads(request_body['string'])
mask_fixture_values(parsed_content, None)
request_body['string'] = json.dumps(parsed_content)
response_body = interaction.data['response']['body']
response_body['string'] = update_expiration(mask_credentials(
response_body['string']))
parsed_content = json.loads(response_body['string'])
mask_fixture_values(parsed_content, None)
response_body['string'] = json.dumps(parsed_content)

View File

@ -0,0 +1 @@
{"auth":{"tenantName": "customer-x", "passwordCredentials": {"username": "joeuser", "password": "secrete"}}}

View File

@ -0,0 +1,49 @@
{
"access":{
"token":{
"expires":"2012-02-05T00:00:00",
"id":"887665443383838",
"tenant":{
"id":"1",
"name":"customer-x"
}
},
"serviceCatalog":[
{
"endpoints":[
{
"adminURL":"http://swift.admin-nets.local:8080/",
"region":"RegionOne",
"internalURL":"http://127.0.0.1:8080/v1/AUTH_1",
"publicURL":"http://swift.publicinternets.com/v1/AUTH_1"
}
],
"type":"object-store",
"name":"swift"
},
{
"endpoints":[
{
"adminURL":"http://cdn.admin-nets.local/v1.1/1",
"region":"RegionOne",
"internalURL":"http://127.0.0.1:7777/v1.1/1",
"publicURL":"http://cdn.publicinternets.com/v1.1/1"
}
],
"type":"object-store",
"name":"cdn"
}
],
"user":{
"id":"1",
"roles":[
{
"tenantId":"1",
"id":"3",
"name":"Member"
}
],
"name":"joeuser"
}
}
}

View File

@ -0,0 +1,13 @@
{ "auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": { "id": "default" },
"password": "adminpwd"
}
}
}
}
}

View File

@ -0,0 +1,15 @@
{"token": {"methods": ["password"], "roles": [{"id":
"9fe2ff9ee4384b1894a90878d3e92bab", "name": "_member_"}, {"id":
"c703057be878458588961ce9a0ce686b", "name": "admin"}], "expires_at":
"2014-06-10T2:55:16.806001Z", "project": {"domain": {"id": "default", "name":
"Default"}, "id": "8538a3f13f9541b28c2620eb19065e45", "name": "admin"},
"catalog": [{"endpoints": [{"url": "http://localhost:3537/v2.0", "region":
"RegionOne", "interface": "admin", "id": "29beb2f1567642eb810b042b6719ea88"},
{"url": "http://localhost:5000/v2.0", "region": "RegionOne", "interface":
"internal", "id": "8707e3735d4415c97ae231b4841eb1c"}, {"url":
"http://localhost:5000/v2.0", "region": "RegionOne", "interface": "public",
"id": "ef303187fc8d41668f25199c298396a5"}], "type": "identity", "id":
"bd73972c0e14fb69bae8ff76e112a90", "name": "keystone"}], "extras": {},
"user": {"domain": {"id": "default", "name": "Default"}, "id":
"3ec3164f750146be97f21559ee4d9c51", "name": "admin"}, "audit_ids":
["yRt0UrxJSs6-WYJgwEMMmg"], "issued_at": "201406-10T20:55:16.806027Z"}}

View File

@ -25,13 +25,15 @@ from keystoneauth1.fixture import hooks
class TestBetamaxHooks(testtools.TestCase):
def test_pre_record_hook(self):
def test_pre_record_hook_v3(self):
fixtures_path = 'keystoneauth1/tests/unit/data'
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')
cassette_library_dir=fixtures_path)
# Create a new object to serialize
r = models.Response()
@ -39,26 +41,17 @@ class TestBetamaxHooks(testtools.TestCase):
r.reason = 'OK'
r.encoding = 'utf-8'
r.headers = {}
r.url = 'http://192.168.0.19:35357/'
r.url = 'http://localhost:35357/'
body_content = {
'auth': {
'passwordCredentials': {
'username': 'user',
'password': 'password'
},
'tenantName': 'dummy',
},
'access': {
'token': {
'expires': '2001-01-01T00:00:00Z'
}
}
}
# load request and response
with open('%s/keystone_v3_sample_response.json' % fixtures_path) as f:
response_content = json.loads(f.read())
with open('%s/keystone_v3_sample_request.json' % fixtures_path) as f:
request_content = json.loads(f.read())
body_content = {
'body': {
'string': json.dumps(body_content),
'string': json.dumps(response_content),
'encoding': 'utf-8',
}
}
@ -71,7 +64,7 @@ class TestBetamaxHooks(testtools.TestCase):
# Create an associated request
r = models.Request()
r.method = 'GET'
r.url = 'http://192.168.0.19:35357/'
r.url = 'http://localhost:35357/'
r.headers = {}
r.data = {}
response.request = r.prepare()
@ -79,15 +72,82 @@ class TestBetamaxHooks(testtools.TestCase):
{'User-Agent': 'betamax/test header'}
)
response.request.body = json.dumps({
'auth': {
'passwordCredentials': {
'username': 'user',
'password': 'password'
},
'tenantName': 'dummy'
response.request.body = json.dumps(request_content)
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['token']['expires_at'],
u'9999-12-31T23:59:59Z')
self.assertEqual(
response_content['token']['project']['domain']['id'],
u'dummy')
self.assertEqual(
response_content['token']['user']['domain']['id'],
u'dummy')
self.assertEqual(
response_content['token']['user']['name'], u'dummy')
request_content = json.loads(
interaction.data['request']['body']['string'])
self.assertEqual(
request_content['auth']['identity']['password']
['user']['domain']['id'], u'dummy')
self.assertEqual(
request_content['auth']['identity']['password']
['user']['password'], u'********')
def test_pre_record_hook_v2(self):
fixtures_path = 'keystoneauth1/tests/unit/data'
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=fixtures_path)
# 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://localhost:35357/'
# load request and response
with open('%s/keystone_v2_sample_response.json' % fixtures_path) as f:
response_content = json.loads(f.read())
with open('%s/keystone_v2_sample_request.json' % fixtures_path) as f:
request_content = json.loads(f.read())
body_content = {
'body': {
'string': json.dumps(response_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://localhost:35357/'
r.headers = {}
r.data = {}
response.request = r.prepare()
response.request.headers.update(
{'User-Agent': 'betamax/test header'}
)
response.request.body = json.dumps(request_content)
interaction = cassette.save_interaction(response, response.request)
@ -97,20 +157,20 @@ class TestBetamaxHooks(testtools.TestCase):
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'],
response_content['access']['token']['tenant']['name'],
u'dummy')
self.assertEqual(
response_content['auth']['passwordCredentials']['password'],
u'********')
response_content['access']['user']['name'],
u'dummy')
request_content = json.loads(
interaction.data['response']['body']['string'])
self.assertEqual(request_content['auth']['tenantName'], u'dummy')
interaction.data['request']['body']['string'])
self.assertEqual(
request_content['auth']['passwordCredentials']['password'],
u'********')
self.assertEqual(
request_content['auth']['passwordCredentials']['username'],
u'dummy')
self.assertEqual(
request_content['auth']['passwordCredentials']['password'],
u'********')
request_content['auth']['tenantName'], u'dummy')