Show URL to test results page
User gets url to test results page after successfull upload. Added 'list' command. It allows user to retrieve links on last uploaded test results. Change-Id: Id3a33179ad551cf95640d4c9fde147048592a1a4
This commit is contained in:
@@ -27,10 +27,10 @@ Tempest configuration file.
|
||||
import argparse
|
||||
import binascii
|
||||
import ConfigParser
|
||||
import itertools
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import requests
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
@@ -38,6 +38,9 @@ from Crypto.Hash import SHA256
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Signature import PKCS1_v1_5
|
||||
from keystoneclient.v2_0 import client as ksclient
|
||||
import requests
|
||||
import requests.exceptions
|
||||
import six.moves
|
||||
from subunit_processor import SubunitProcessor
|
||||
|
||||
|
||||
@@ -197,6 +200,10 @@ class RefstackClient:
|
||||
self.logger.exception(e)
|
||||
return
|
||||
|
||||
if response.status_code == 201:
|
||||
resp = response.json()
|
||||
print 'Test results uploaded!\nURL: %s' % resp.get('url', '')
|
||||
|
||||
def test(self):
|
||||
'''Execute Tempest test against the cloud.'''
|
||||
self._prep_test()
|
||||
@@ -274,6 +281,41 @@ class RefstackClient:
|
||||
self.post_results(self.args.url, json_data,
|
||||
sign_with=self.args.priv_key)
|
||||
|
||||
def yield_results(self, url, start_page=1,
|
||||
start_date='', end_date='', cpid=''):
|
||||
endpoint = '%s/v1/results/' % url
|
||||
headers = {'Content-type': 'application/json'}
|
||||
for page in itertools.count(start_page):
|
||||
params = {'page': page}
|
||||
for param in ('start_date', 'end_date', 'cpid'):
|
||||
if locals()[param]:
|
||||
params.update({param: locals()[param]})
|
||||
try:
|
||||
resp = requests.get(endpoint, headers=headers, params=params)
|
||||
resp.raise_for_status()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
self.logger.info('Failed to list %s - %s ' % (endpoint, e))
|
||||
raise StopIteration
|
||||
else:
|
||||
resp = resp.json()
|
||||
results = resp.get('results', [])
|
||||
yield results
|
||||
if resp['pagination']['total_pages'] == page:
|
||||
raise StopIteration
|
||||
|
||||
def list(self):
|
||||
"""Retrieve list with last test results from Refstack."""
|
||||
results = self.yield_results(self.args.url,
|
||||
start_date=self.args.start_date,
|
||||
end_date=self.args.end_date)
|
||||
for page_of_results in results:
|
||||
for r in page_of_results:
|
||||
print('%s - %s' % (r['created_at'], r['url']))
|
||||
try:
|
||||
six.moves.input('Press Enter to go to next page...')
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
|
||||
|
||||
def parse_cli_args(args=None):
|
||||
|
||||
@@ -359,4 +401,24 @@ def parse_cli_args(args=None):
|
||||
'or the server specified by --url.')
|
||||
parser_test.set_defaults(func="test")
|
||||
|
||||
# List command
|
||||
parser_list = subparsers.add_parser(
|
||||
'list', parents=[shared_args],
|
||||
help='List last results from Refstack')
|
||||
parser_list.add_argument('--start-date',
|
||||
required=False,
|
||||
dest='start_date',
|
||||
type=str,
|
||||
help='Specify a date for start listing of '
|
||||
'test results '
|
||||
'(e.g. --start-date "2015-04-24 01:23:56").')
|
||||
parser_list.add_argument('--end-date',
|
||||
required=False,
|
||||
dest='end_date',
|
||||
type=str,
|
||||
help='Specify a date for end listing of '
|
||||
'test results '
|
||||
'(e.g. --end-date "2015-04-24 01:23:56").')
|
||||
parser_list.set_defaults(func='list')
|
||||
|
||||
return parser.parse_args(args=args)
|
||||
|
||||
@@ -14,11 +14,10 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
import logging
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
import subprocess
|
||||
|
||||
import httmock
|
||||
import mock
|
||||
@@ -45,23 +44,25 @@ class TestRefstackClient(unittest.TestCase):
|
||||
self.addCleanup(patcher.stop)
|
||||
return thing
|
||||
|
||||
def mock_argv(self, conf_file_name=None, verbose=None, priv_key=None):
|
||||
def mock_argv(self, command='test', **kwargs):
|
||||
"""
|
||||
Build argv for test.
|
||||
:param conf_file_name: Configuration file name
|
||||
:param verbose: verbosity level
|
||||
:return: argv
|
||||
"""
|
||||
if conf_file_name is None:
|
||||
conf_file_name = self.conf_file_name
|
||||
argv = ['test',
|
||||
'-c', conf_file_name,
|
||||
'--test-cases', 'tempest.api.compute',
|
||||
argv = [command,
|
||||
'--url', 'http://127.0.0.1']
|
||||
if priv_key:
|
||||
argv.extend(('-i', priv_key))
|
||||
if verbose:
|
||||
argv.append(verbose)
|
||||
if command == 'test':
|
||||
argv.extend(
|
||||
('-c', kwargs.get('conf_file_name', self.conf_file_name)))
|
||||
if kwargs.get('test_cases', None):
|
||||
argv.extend(('--test-cases', kwargs.get('test_cases', None)))
|
||||
|
||||
if kwargs.get('priv_key', None):
|
||||
argv.extend(('-i', kwargs.get('priv_key', None)))
|
||||
if kwargs.get('verbose', None):
|
||||
argv.append(kwargs.get('verbose', None))
|
||||
return argv
|
||||
|
||||
def mock_keystone(self):
|
||||
@@ -280,7 +281,8 @@ class TestRefstackClient(unittest.TestCase):
|
||||
Test that the test command will run the tempest script using the
|
||||
default configuration.
|
||||
"""
|
||||
args = rc.parse_cli_args(self.mock_argv(verbose='-vv'))
|
||||
args = rc.parse_cli_args(
|
||||
self.mock_argv(verbose='-vv', test_cases='tempest.api.compute'))
|
||||
client = rc.RefstackClient(args)
|
||||
client.tempest_dir = self.test_path
|
||||
mock_popen = self.patch(
|
||||
@@ -307,7 +309,8 @@ class TestRefstackClient(unittest.TestCase):
|
||||
Test that the test command will run the tempest script and call
|
||||
post_results when the --upload argument is passed in.
|
||||
"""
|
||||
argv = self.mock_argv(verbose='-vv')
|
||||
argv = self.mock_argv(verbose='-vv',
|
||||
test_cases='tempest.api.compute')
|
||||
argv.append('--upload')
|
||||
args = rc.parse_cli_args(argv)
|
||||
client = rc.RefstackClient(args)
|
||||
@@ -334,7 +337,8 @@ class TestRefstackClient(unittest.TestCase):
|
||||
Test that the test command will run the tempest script and call
|
||||
post_results when the --upload argument is passed in.
|
||||
"""
|
||||
argv = self.mock_argv(verbose='-vv', priv_key='rsa_key')
|
||||
argv = self.mock_argv(verbose='-vv', priv_key='rsa_key',
|
||||
test_cases='tempest.api.compute')
|
||||
argv.append('--upload')
|
||||
args = rc.parse_cli_args(argv)
|
||||
client = rc.RefstackClient(args)
|
||||
@@ -385,7 +389,8 @@ class TestRefstackClient(unittest.TestCase):
|
||||
Check that the result JSON file is renamed with the result file tag
|
||||
when the --result-file-tag argument is passed in.
|
||||
"""
|
||||
argv = self.mock_argv(verbose='-vv')
|
||||
argv = self.mock_argv(verbose='-vv',
|
||||
test_cases='tempest.api.compute')
|
||||
argv.extend(['--result-file-tag', 'my-test'])
|
||||
args = rc.parse_cli_args(argv)
|
||||
client = rc.RefstackClient(args)
|
||||
@@ -459,62 +464,55 @@ class TestRefstackClient(unittest.TestCase):
|
||||
client = rc.RefstackClient(args)
|
||||
self.assertRaises(SystemExit, client.upload)
|
||||
|
||||
def _set_mocks_for_setup(self):
|
||||
def test_yeild_results(self):
|
||||
"""
|
||||
Setup mocks for testing setup command in positive case
|
||||
Test the post_results method, ensuring a requests call is made.
|
||||
"""
|
||||
env = dict()
|
||||
env['args'] = rc.parse_cli_args(['setup', '-r', 'havana-eol',
|
||||
'--tempest-dir', '/tmp/tempest'])
|
||||
env['raw_input'] = self.patch(
|
||||
'refstack_client.refstack_client.get_input',
|
||||
return_value='yes'
|
||||
)
|
||||
env['exists'] = self.patch(
|
||||
'refstack_client.refstack_client.os.path.exists',
|
||||
return_value=True
|
||||
)
|
||||
env['rmtree'] = self.patch(
|
||||
'refstack_client.refstack_client.shutil.rmtree',
|
||||
return_value=True
|
||||
)
|
||||
env['test_commit_sha'] = '42'
|
||||
env['tag'] = MagicMock(
|
||||
**{'commit.hexsha': env['test_commit_sha']}
|
||||
)
|
||||
env['tag'].configure_mock(name='havana-eol')
|
||||
env['git.reset'] = MagicMock()
|
||||
env['repo'] = MagicMock(
|
||||
tags=[env['tag']],
|
||||
**{'git.reset': env['git.reset']}
|
||||
)
|
||||
self.patch(
|
||||
'refstack_client.refstack_client.git.Repo.clone_from',
|
||||
return_value=env['repo']
|
||||
)
|
||||
env['os.chdir'] = self.patch(
|
||||
'refstack_client.refstack_client.os.chdir'
|
||||
)
|
||||
env['subprocess.check_output'] = self.patch(
|
||||
'refstack_client.refstack_client.subprocess.check_output',
|
||||
return_value='Ok!'
|
||||
)
|
||||
return env
|
||||
args = rc.parse_cli_args(self.mock_argv(command='list'))
|
||||
client = rc.RefstackClient(args)
|
||||
expected_response = {
|
||||
"pagination": {
|
||||
"current_page": 1,
|
||||
"total_pages": 1
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"cpid": "42",
|
||||
"created_at": "2015-04-28 13:57:05",
|
||||
"test_id": "1",
|
||||
"url": "http://127.0.0.1:8000/output.html?test_id=1"
|
||||
},
|
||||
{
|
||||
"cpid": "42",
|
||||
"created_at": "2015-04-28 13:57:05",
|
||||
"test_id": "2",
|
||||
"url": "http://127.0.0.1:8000/output.html?test_id=2"
|
||||
}]}
|
||||
|
||||
def _check_mocks_for_setup(self, env):
|
||||
"""
|
||||
Check mocks after successful run 'setup' command
|
||||
"""
|
||||
env['exists'].assert_called_once_with('/tmp/tempest')
|
||||
env['rmtree'].assert_called_once_with('/tmp/tempest')
|
||||
env['git.reset'].assert_called_once_with(
|
||||
env['test_commit_sha'], hard=True
|
||||
)
|
||||
env['os.chdir'].assert_has_calls([mock.call('/tmp/tempest'),
|
||||
mock.call(os.getcwd())])
|
||||
env['subprocess.check_output'].assert_has_calls([
|
||||
mock.call(['virtualenv', '.venv'],
|
||||
stderr=subprocess.STDOUT),
|
||||
mock.call(['.venv//bin//pip', 'install', '-r', 'requirements.txt'],
|
||||
stderr=subprocess.STDOUT)
|
||||
])
|
||||
@httmock.urlmatch(netloc=r'(.*\.)?127.0.0.1$', path='/v1/results/')
|
||||
def refstack_api_mock(url, request):
|
||||
return json.dumps(expected_response)
|
||||
|
||||
with httmock.HTTMock(refstack_api_mock):
|
||||
results = client.yield_results("http://127.0.0.1")
|
||||
self.assertEqual(expected_response['results'], next(results))
|
||||
self.assertRaises(StopIteration, next, results)
|
||||
|
||||
@mock.patch('six.moves.input', side_effect=KeyboardInterrupt)
|
||||
@mock.patch('sys.stdout', new_callable=MagicMock)
|
||||
def test_list(self, mock_stdout, mock_input):
|
||||
args = rc.parse_cli_args(self.mock_argv(command='list'))
|
||||
client = rc.RefstackClient(args)
|
||||
results = [[{"cpid": "42",
|
||||
"created_at": "2015-04-28 13:57:05",
|
||||
"test_id": "1",
|
||||
"url": "http://127.0.0.1:8000/output.html?test_id=1"},
|
||||
{"cpid": "42",
|
||||
"created_at": "2015-04-28 13:57:05",
|
||||
"test_id": "2",
|
||||
"url": "http://127.0.0.1:8000/output.html?test_id=2"}]]
|
||||
mock_results = MagicMock()
|
||||
mock_results.__iter__.return_value = results
|
||||
client.yield_results = MagicMock(return_value=mock_results)
|
||||
client.list()
|
||||
self.assertTrue(mock_stdout.write.called)
|
||||
|
||||
Reference in New Issue
Block a user