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 argparse
|
||||||
import binascii
|
import binascii
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
|
import itertools
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import requests
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -38,6 +38,9 @@ from Crypto.Hash import SHA256
|
|||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
from Crypto.Signature import PKCS1_v1_5
|
from Crypto.Signature import PKCS1_v1_5
|
||||||
from keystoneclient.v2_0 import client as ksclient
|
from keystoneclient.v2_0 import client as ksclient
|
||||||
|
import requests
|
||||||
|
import requests.exceptions
|
||||||
|
import six.moves
|
||||||
from subunit_processor import SubunitProcessor
|
from subunit_processor import SubunitProcessor
|
||||||
|
|
||||||
|
|
||||||
@@ -197,6 +200,10 @@ class RefstackClient:
|
|||||||
self.logger.exception(e)
|
self.logger.exception(e)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if response.status_code == 201:
|
||||||
|
resp = response.json()
|
||||||
|
print 'Test results uploaded!\nURL: %s' % resp.get('url', '')
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
'''Execute Tempest test against the cloud.'''
|
'''Execute Tempest test against the cloud.'''
|
||||||
self._prep_test()
|
self._prep_test()
|
||||||
@@ -274,6 +281,41 @@ class RefstackClient:
|
|||||||
self.post_results(self.args.url, json_data,
|
self.post_results(self.args.url, json_data,
|
||||||
sign_with=self.args.priv_key)
|
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):
|
def parse_cli_args(args=None):
|
||||||
|
|
||||||
@@ -359,4 +401,24 @@ def parse_cli_args(args=None):
|
|||||||
'or the server specified by --url.')
|
'or the server specified by --url.')
|
||||||
parser_test.set_defaults(func="test")
|
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)
|
return parser.parse_args(args=args)
|
||||||
|
|||||||
@@ -14,11 +14,10 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
import logging
|
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
|
||||||
|
|
||||||
import httmock
|
import httmock
|
||||||
import mock
|
import mock
|
||||||
@@ -45,23 +44,25 @@ class TestRefstackClient(unittest.TestCase):
|
|||||||
self.addCleanup(patcher.stop)
|
self.addCleanup(patcher.stop)
|
||||||
return thing
|
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.
|
Build argv for test.
|
||||||
:param conf_file_name: Configuration file name
|
:param conf_file_name: Configuration file name
|
||||||
:param verbose: verbosity level
|
:param verbose: verbosity level
|
||||||
:return: argv
|
:return: argv
|
||||||
"""
|
"""
|
||||||
if conf_file_name is None:
|
argv = [command,
|
||||||
conf_file_name = self.conf_file_name
|
|
||||||
argv = ['test',
|
|
||||||
'-c', conf_file_name,
|
|
||||||
'--test-cases', 'tempest.api.compute',
|
|
||||||
'--url', 'http://127.0.0.1']
|
'--url', 'http://127.0.0.1']
|
||||||
if priv_key:
|
if command == 'test':
|
||||||
argv.extend(('-i', priv_key))
|
argv.extend(
|
||||||
if verbose:
|
('-c', kwargs.get('conf_file_name', self.conf_file_name)))
|
||||||
argv.append(verbose)
|
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
|
return argv
|
||||||
|
|
||||||
def mock_keystone(self):
|
def mock_keystone(self):
|
||||||
@@ -280,7 +281,8 @@ class TestRefstackClient(unittest.TestCase):
|
|||||||
Test that the test command will run the tempest script using the
|
Test that the test command will run the tempest script using the
|
||||||
default configuration.
|
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 = rc.RefstackClient(args)
|
||||||
client.tempest_dir = self.test_path
|
client.tempest_dir = self.test_path
|
||||||
mock_popen = self.patch(
|
mock_popen = self.patch(
|
||||||
@@ -307,7 +309,8 @@ class TestRefstackClient(unittest.TestCase):
|
|||||||
Test that the test command will run the tempest script and call
|
Test that the test command will run the tempest script and call
|
||||||
post_results when the --upload argument is passed in.
|
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')
|
argv.append('--upload')
|
||||||
args = rc.parse_cli_args(argv)
|
args = rc.parse_cli_args(argv)
|
||||||
client = rc.RefstackClient(args)
|
client = rc.RefstackClient(args)
|
||||||
@@ -334,7 +337,8 @@ class TestRefstackClient(unittest.TestCase):
|
|||||||
Test that the test command will run the tempest script and call
|
Test that the test command will run the tempest script and call
|
||||||
post_results when the --upload argument is passed in.
|
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')
|
argv.append('--upload')
|
||||||
args = rc.parse_cli_args(argv)
|
args = rc.parse_cli_args(argv)
|
||||||
client = rc.RefstackClient(args)
|
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
|
Check that the result JSON file is renamed with the result file tag
|
||||||
when the --result-file-tag argument is passed in.
|
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'])
|
argv.extend(['--result-file-tag', 'my-test'])
|
||||||
args = rc.parse_cli_args(argv)
|
args = rc.parse_cli_args(argv)
|
||||||
client = rc.RefstackClient(args)
|
client = rc.RefstackClient(args)
|
||||||
@@ -459,62 +464,55 @@ class TestRefstackClient(unittest.TestCase):
|
|||||||
client = rc.RefstackClient(args)
|
client = rc.RefstackClient(args)
|
||||||
self.assertRaises(SystemExit, client.upload)
|
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()
|
args = rc.parse_cli_args(self.mock_argv(command='list'))
|
||||||
env['args'] = rc.parse_cli_args(['setup', '-r', 'havana-eol',
|
client = rc.RefstackClient(args)
|
||||||
'--tempest-dir', '/tmp/tempest'])
|
expected_response = {
|
||||||
env['raw_input'] = self.patch(
|
"pagination": {
|
||||||
'refstack_client.refstack_client.get_input',
|
"current_page": 1,
|
||||||
return_value='yes'
|
"total_pages": 1
|
||||||
)
|
},
|
||||||
env['exists'] = self.patch(
|
"results": [
|
||||||
'refstack_client.refstack_client.os.path.exists',
|
{
|
||||||
return_value=True
|
"cpid": "42",
|
||||||
)
|
"created_at": "2015-04-28 13:57:05",
|
||||||
env['rmtree'] = self.patch(
|
"test_id": "1",
|
||||||
'refstack_client.refstack_client.shutil.rmtree',
|
"url": "http://127.0.0.1:8000/output.html?test_id=1"
|
||||||
return_value=True
|
},
|
||||||
)
|
{
|
||||||
env['test_commit_sha'] = '42'
|
"cpid": "42",
|
||||||
env['tag'] = MagicMock(
|
"created_at": "2015-04-28 13:57:05",
|
||||||
**{'commit.hexsha': env['test_commit_sha']}
|
"test_id": "2",
|
||||||
)
|
"url": "http://127.0.0.1:8000/output.html?test_id=2"
|
||||||
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
|
|
||||||
|
|
||||||
def _check_mocks_for_setup(self, env):
|
@httmock.urlmatch(netloc=r'(.*\.)?127.0.0.1$', path='/v1/results/')
|
||||||
"""
|
def refstack_api_mock(url, request):
|
||||||
Check mocks after successful run 'setup' command
|
return json.dumps(expected_response)
|
||||||
"""
|
|
||||||
env['exists'].assert_called_once_with('/tmp/tempest')
|
with httmock.HTTMock(refstack_api_mock):
|
||||||
env['rmtree'].assert_called_once_with('/tmp/tempest')
|
results = client.yield_results("http://127.0.0.1")
|
||||||
env['git.reset'].assert_called_once_with(
|
self.assertEqual(expected_response['results'], next(results))
|
||||||
env['test_commit_sha'], hard=True
|
self.assertRaises(StopIteration, next, results)
|
||||||
)
|
|
||||||
env['os.chdir'].assert_has_calls([mock.call('/tmp/tempest'),
|
@mock.patch('six.moves.input', side_effect=KeyboardInterrupt)
|
||||||
mock.call(os.getcwd())])
|
@mock.patch('sys.stdout', new_callable=MagicMock)
|
||||||
env['subprocess.check_output'].assert_has_calls([
|
def test_list(self, mock_stdout, mock_input):
|
||||||
mock.call(['virtualenv', '.venv'],
|
args = rc.parse_cli_args(self.mock_argv(command='list'))
|
||||||
stderr=subprocess.STDOUT),
|
client = rc.RefstackClient(args)
|
||||||
mock.call(['.venv//bin//pip', 'install', '-r', 'requirements.txt'],
|
results = [[{"cpid": "42",
|
||||||
stderr=subprocess.STDOUT)
|
"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