diff --git a/marconi/tests/system/README.rst b/marconi/tests/system/README.rst index 1bde6cc0e..509bc8263 100644 --- a/marconi/tests/system/README.rst +++ b/marconi/tests/system/README.rst @@ -13,8 +13,8 @@ Running the System Tests #. Setup a Marconi server. Refer to the Marconi `README`_ on how to run Marconi locally, or simply use an existing server. -#. System tests require the `requests`_ & `robot`_ packages. Run - the following to install them: :: +#. System tests require the `requests` package. Run + the following to install it: :: pip install -r tools/system-test-requires @@ -31,35 +31,21 @@ Running the System Tests #. If leaving keystone auth enabled, update system-tests.conf with a valid set of credentials. -#. Now, to run the sytem tests, simply use the pybot commands, e.g.: +#. Now, to run the sytem tests, simply use the nosetests commands, + from the marconi/tests/system directory. e.g.: Run all test suites: :: - pybot queue/queue_tests.txt messages/messages_tests.txt claim/claim_tests.txt - - Run test suites individually: :: - - pybot queue/queue_tests.txt - pybot messages/messages_tests.txt - pybot claim/claim_tests.txt - - Note: pybot will generate ``report.html`` & ``log.html`` after the - test run is complete. - + nosetests -v Adding New Tests ---------------- -*See also the Robot* `user guide`_ *for more details on writing test cases.* +#. Add test case to an appropriate test case file: :: -#. Add a test case definition to an appropriate robot test case file: :: - - queue/queue_tests.txt - messages/messages_tests.txt - claim/claim_tests.txt). - -#. Add test data to the test_data.csv in the same directory as the test case - file you updated above (eg. queue/test_data.csv) + queue/test_queue.py + messages/test_messages.py + claim/test_claims.py #. Add any validation logic you might need, to the following utility modules: @@ -71,7 +57,3 @@ Adding New Tests .. _README : https://github.com/stackforge/marconi/blob/master/README.rst .. _requests : https://pypi.python.org/pypi/requests -.. _robot : https://pypi.python.org/pypi/robotframework -.. _user guide : http://robotframework.googlecode.com/hg/doc/userguide/RobotFrameworkUserGuide.html?r=#.7.7#creating-test-cases - - diff --git a/marconi/tests/system/claim/claim_tests.txt b/marconi/tests/system/claim/claim_tests.txt deleted file mode 100755 index cce2b1a43..000000000 --- a/marconi/tests/system/claim/claim_tests.txt +++ /dev/null @@ -1,66 +0,0 @@ -| *Setting* | *Value* | -| Documentation | Marconi - Queue Test Suite | -| Library | ../common/http.py | -| Library | ../common/functionlib.py | -| Library | ../messages/msgfnlib.py | -| Library | Collections | -| Library | claimfnlib.py | -| Variables | getdata.py | -| Force Tags | CLAIM | -| Suite Setup | executetests | ${API_TEST_DATA[6]} | # Test Suite Setup - Creates a Queue -| Suite Teardown | executetests | ${API_TEST_DATA[8]} | # Test Suite Teardown - Deletes the queue created by setup - - -| *Test Case* | *Action* | *Argument* | *Argument* | *Argument* | # Comment -| 0:SUITE SETUP | [DOCUMENTATION] | | Post 500 messages | | #SUITE SETUP - POST MULTIPLE MESSAGES -| | [Tags] | INSERT_MESSAGE | | | #(Robot allows only one keyword in setup) -| | ${reqparam}= | Create Dictionary | messagecount | ${50} | # Specify count of messages to be posted -| | | ... | ttl | ${300} | # Specify count of messages to be posted -| | ${msgbody}= | dummygetmessagebody | ${reqparam} | | # Gets the message body to post -| | Set To Dictionary | ${API_TEST_DATA[7]} | body | ${msgbody} | # Set the POST body -| | :FOR | ${index} | IN RANGE | 10 | # Loop to post 50 messages * 10 times -| | | executetests | ${API_TEST_DATA[7]} | | # postresponse = [httpheaders,httpresponsebod] -| 1:CLAIM 2 MESSAGES | [DOCUMENTATION] | Claim messages | | #TEST CASE 1 - CLAIM 2 MESSAGES -| | ... | with limit = 2 | | -| | @{postresponse}= | executetests | ${API_TEST_DATA[0]} | # Post a claim; postresponse = [httpheaders, httpresponsebody] -| | verifyclaimmsg | ${2} | @{postresponse} | -| 2:CLAIM 5 MESSAGES | [DOCUMENTATION] | Claim messages | | #TEST CASE 2 - CLAIM 5 MESSAGES -| | ... | with limit = 5 | | -| | @{postresponse}= | executetests | ${API_TEST_DATA[1]} | # Post a claim; postresponse = [httpheaders, httpresponsebody] -| | verifyclaimmsg | ${5} | @{postresponse} | -| 3:CLAIM MESSAGES | [DOCUMENTATION] | Claim messages | | #TEST CASE 3 - CLAIM DEFAULT # OF MESSAGES -| | ... | with no params | | (currently 10) -| | @{postresponse}= | executetests | ${API_TEST_DATA[2]} | # postresponse = [httpheaders, httpresponsebody] -| | verifyclaimmsg | ${10} | @{postresponse} | -| 4:CLAIM 15 MESSAGE | [DOCUMENTATION] | Claim messages | | #TEST CASE 4 - CLAIM 15 MESSAGES -| | ... | with limit = 15 | | -| | @{postresponse}= | executetests | ${API_TEST_DATA[3]} | # Post a claim; postresponse = [httpheaders, httpresponsebody] -| | verifyclaimmsg | ${15} | @{postresponse} | -| 5:CLAIM 55 MESSAGE | [DOCUMENTATION] | Claim messages | | #TEST CASE 5 - CLAIM 55 MESSAGES -| | ... | with limit = 55 | | -| | @{postresponse}= | executetests | ${API_TEST_DATA[4]} | # Post a claim; postresponse = [httpheaders, httpresponsebody] -| | verifyclaimmsg | ${50} | @{postresponse} | # MAXIMUM MESSAGES RETURNED IS CURRENTLY 50 -| 6: PATCH CLAIM | [DOCUMENTATION] | Patch a claim | | # TEST CASE 6 - UPDATE CLAIM -| | @{postresponse}= | executetests | ${API_TEST_DATA[5]} | # Post a claim; postresponse = [httpheaders, httpresponsebody] -| | patchclaim | @{postresponse} | | # Patch the above claim -| 7: DELETE MESSAGE | [DOCUMENTATION] | Delete message | | # TEST CASE 7 - DELETE A CLAIMED MESSAGE -| | ... | with claim id | | -| | @{postresponse}= | executetests | ${API_TEST_DATA[5]} | # Post a claim -| | deleteclaimedmsgs | @{postresponse} | | # Delete messages returned in the above claim -| 8: PATCH EXPIRED CLAIM | [DOCUMENTATION] | Patch expired claim | | # TEST CASE 8 - UPDATE EXPIRED CLAIM -| | @{postresponse}= | executetests | ${API_TEST_DATA[9]} | # Post a claim with TTL= 1 sec -| | Sleep | 3s | | -| | patchclaim | @{postresponse} | | # Patch the above claim -| 9: DELETE MESSAGE ON EXPIRED CLAIM | [DOCUMENTATION] | Delete message | # TEST CASE 9 - DELETE MESSAGE ON AN EXPIRED CLAIM -| | ... | on expired claim | -| | @{postresponse}= | executetests | ${API_TEST_DATA[10]} | # Post a claim with TTL= 1 sec -| | Sleep | 3s | | -| | deleteclaimedmsgs | @{postresponse} | | # Delete message returned in the above claim -| 10: RELEASE CLAIM | [DOCUMENTATION] | Release claim | | # TEST CASE 10 - RELEASE CLAIM -| | @{postresponse}= | executetests | ${API_TEST_DATA[11]} | # Post a claim with TTL= 1 sec -| | releaseclaim | @{postresponse} | | # Patch the above claim -| 11: GET MESSAGE FROM EXPIRED CLAIM | [DOCUMENTATION] | Get message | # TEST CASE 11 - GET MESSAGE FROM EXPIRED CLAIM -| | ... | from expired claim | -| | @{postresponse}= | executetests | ${API_TEST_DATA[12]} | # Post a claim with TTL= 1 sec -| | Sleep | 3s | | -| | getclaimedmsgs | @{postresponse} | | # Delete message returned in the above claim \ No newline at end of file diff --git a/marconi/tests/system/claim/claimfnlib.py b/marconi/tests/system/claim/claimfnlib.py index 98b9fb5bb..9a4eb0b44 100644 --- a/marconi/tests/system/claim/claimfnlib.py +++ b/marconi/tests/system/claim/claimfnlib.py @@ -28,16 +28,17 @@ def verify_claim_msg(count, *claim_response): :param count: limit specified in the claim request. :param claim_response : [header, body] returned for post claim request. """ - msg_length_flag = False + test_result_flag = False headers = claim_response[0] body = claim_response[1] - msg_length_flag = verify_claim_msglength(count, body) - if msg_length_flag: - query_claim(headers, body) + test_result_flag = verify_claim_msglength(count, body) + if test_result_flag: + test_result_flag = query_claim(headers, body) else: - assert msg_length_flag, 'More msgs returned than specified in limit' + print 'More msgs returned than specified in limit' + return test_result_flag def verify_claim_msglength(count, *body): @@ -75,9 +76,7 @@ def query_claim(headers, *body): query_msgs = query_body['messages'] test_result_flag = verify_query_msgs(query_msgs, msg_list) - if test_result_flag: - return test_result_flag - else: + if not test_result_flag: print 'URL' print url print 'HEADER' @@ -88,7 +87,8 @@ def query_claim(headers, *body): print 'Messages returned by Claim Messages' print msg_list print '# of Messages returned by Claim messages', len(msg_list) - assert test_result_flag, 'Query Claim Failed' + print 'Query Claim Failed' + return test_result_flag def verify_query_msgs(querymsgs, msg_list): @@ -137,10 +137,8 @@ def patch_claim(*claim_response): print 'Patch HTTP Response code: {}'.format(patch_response.status_code) print patch_response.headers print patch_response.text - assert test_result_flag, 'Patch Claim Failed' - if not test_result_flag: - assert test_result_flag, 'Query claim after the patch failed' + return test_result_flag def verify_patch_claim(url, header, ttl_extended): @@ -198,10 +196,9 @@ def delete_claimed_msgs(*claim_response): print delete_response.status_code print delete_response.headers print delete_response.text - assert test_result_flag, 'Delete Claimed Message Failed' + print 'Delete Claimed Message Failed' - if not test_result_flag: - assert test_result_flag, 'Get message after DELETE did not return 404' + return test_result_flag def get_claimed_msgs(*claim_response): diff --git a/marconi/tests/system/claim/getdata.py b/marconi/tests/system/claim/getdata.py deleted file mode 100755 index 0f42e0e63..000000000 --- a/marconi/tests/system/claim/getdata.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2013 Rackspace, Inc. -# -# 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 csv - -from marconi.tests.system.common import config -from marconi.tests.system.common import functionlib - - -CFG = config.Config() - - -def get_data(): - """Reads the test data from claim/test_data.csv.""" - data = [] - with open('marconi/tests/system/claim/test_data.csv', 'rb') as datafile: - testdata = csv.DictReader(datafile, delimiter='|') - for row in testdata: - data.append(row) - - for row in data: - row['header'] = functionlib.get_headers(row['header']) - row['url'] = row['url'].replace('', CFG.base_url) - - return data - -API_TEST_DATA = get_data() diff --git a/marconi/tests/system/claim/test_claims.py b/marconi/tests/system/claim/test_claims.py new file mode 100644 index 000000000..182e1628c --- /dev/null +++ b/marconi/tests/system/claim/test_claims.py @@ -0,0 +1,224 @@ +# Copyright (c) 2013 Rackspace, Inc. +# +# 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. +from marconi.tests.system.claim import claimfnlib +from marconi.tests.system.common import config +from marconi.tests.system.common import functionlib +from marconi.tests.system.common import http +from marconi.tests.system.messages import msgfnlib + +import testtools +import time + + +class TestClaims(testtools.TestCase): + """Tests for Claims.""" + + def setUp(self): + super(TestClaims, self).setUp() + self.cfg = config.Config() + self.header = functionlib.create_marconi_headers() + + def test_000_claim_setup(self): + """Create Queue, Post Messages for Claim Tests.""" + url = self.cfg.base_url + '/queues/claimtestqueue' + doc = '{"queuemetadata": "message test queue"}' + + result = http.put(url, self.header, doc) + self.assertEqual(result.status_code, 201) + + #Post Messages + url = self.cfg.base_url + '/queues/claimtestqueue/messages' + doc = msgfnlib.get_message_body(messagecount=50) + for i in range(5): + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 201) + + test_000_claim_setup.tags = ['smoke', 'positive'] + + def test_001_claim_2messages(self): + """Claim 2 messages.""" + message_count = 2 + url = self.cfg.base_url + '/queues/claimtestqueue/claims?limit=2' + doc = '{"ttl": 300, "grace": 100}' + + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 200) + + test_result_flag = claimfnlib.verify_claim_msg( + message_count, result.headers, result.text) + self.assertEqual(test_result_flag, True) + + test_001_claim_2messages.tags = ['smoke', 'positive'] + + def test_002_claim_default_messages(self): + """Claim messages with no URL parameters. + + By default, Marconi will return 10 messages. + """ + default_message_count = 10 + url = self.cfg.base_url + '/queues/claimtestqueue/claims' + doc = '{"ttl": 300, "grace": 100}' + + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 200) + + test_result_flag = claimfnlib.verify_claim_msg( + default_message_count, result.headers, result.text) + self.assertEqual(test_result_flag, True) + + test_002_claim_default_messages.tags = ['smoke', 'positive'] + + def test_003_claim_15messages(self): + """Claim 15 messages.""" + message_count = 15 + url = self.cfg.base_url + '/queues/claimtestqueue/claims?limit=15' + doc = '{"ttl": 300, "grace": 100}' + + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 200) + + test_result_flag = claimfnlib.verify_claim_msg( + message_count, result.headers, result.text) + self.assertEqual(test_result_flag, True) + + test_003_claim_15messages.tags = ['positive'] + + def test_004_claim_55messages(self): + """Claim more than max allowed per request. + + Marconi allows a maximum of 50 messages per claim. + """ + message_count = 55 + url = self.cfg.base_url + '/queues/claimtestqueue/claims?limit=55' + doc = '{"ttl": 300, "grace": 100}' + + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 200) + + test_result_flag = claimfnlib.verify_claim_msg( + message_count, result.headers, result.text) + self.assertEqual(test_result_flag, True) + + test_004_claim_55messages.tags = ['positive'] + + def test_005_claim_patch(self): + """Update Claim.""" + #Test Setup - Post Claim + url = self.cfg.base_url + '/queues/claimtestqueue/claims' + doc = '{"ttl": 300, "grace": 100}' + + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 200) + + #Update Claim & Verify the patch + test_result_flag = claimfnlib.patch_claim( + result.headers, result.text) + self.assertEqual(test_result_flag, True) + + test_005_claim_patch.tags = ['smoke', 'positive'] + + def test_006_claim_delete_message(self): + """Delete message belonging to a Claim.""" + #Test Setup - Post claim + url = self.cfg.base_url + '/queues/claimtestqueue/claims' + doc = '{"ttl": 60, "grace": 10}' + + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 200) + + #Delete Claimed Message & Verify the delete + test_result_flag = claimfnlib.delete_claimed_msgs( + result.headers, result.text) + self.assertEqual(test_result_flag, True) + + test_006_claim_delete_message.tags = ['smoke', 'positive'] + + def test_007_claim_expired(self): + """Update, Get and Release Expired Claim.""" + #Test Setup - Post Claim. + url = self.cfg.base_url + '/queues/claimtestqueue/claims' + doc = '{"ttl": 1, "grace": 0}' + + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 200) + + time.sleep(2) + + #Extract claim location and construct the claim URL. + location = result.headers['Location'] + url = self.cfg.base_server + location + + #Update Expired Claim. + doc = '{"ttl": 300, "grace": 100}' + result = http.patch(url, self.header, doc) + self.assertEqual(result.status_code, 404) + + #Get Expired Claim. + result = http.get(url, self.header) + self.assertEqual(result.status_code, 404) + + #Release Expired Claim. + result = http.delete(url, self.header) + self.assertEqual(result.status_code, 204) + + test_007_claim_expired.tags = ['smoke', 'positive'] + + def test_008_claim_expired_delete_message(self): + """Get & Delete Message from an Expired Claim.""" + #Test Setup - Post Claim. + url = self.cfg.base_url + '/queues/claimtestqueue/claims' + doc = '{"ttl": 1, "grace": 0}' + + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 200) + + time.sleep(2) + + #Create url, using message location from claim response. + message_location = result.json()[0]['href'] + url = self.cfg.base_server + message_location + + #Delete message with expired claim ID + result = http.delete(url, self.header) + self.assertEqual(result.status_code, 403) + + test_008_claim_expired_delete_message.tags = ['smoke', 'positive'] + + def test_009_claim_release(self): + """Release Claim.""" + url = self.cfg.base_url + '/queues/claimtestqueue/claims' + doc = '{"ttl": 300, "grace": 100}' + + result = http.post(url, self.header, doc) + self.assertEqual(result.status_code, 200) + + #Extract claim location and construct the claim URL. + location = result.headers['Location'] + url = self.cfg.base_server + location + + #Release Claim. + result = http.delete(url, self.header) + self.assertEqual(result.status_code, 204) + + test_009_claim_release.tags = ['smoke', 'positive'] + + def test_999_claim_teardown(self): + """Delete Queue after Claim Tests.""" + url = self.cfg.base_url + '/queues/claimtestqueue' + + result = http.delete(url, self.header) + self.assertEqual(result.status_code, 204) + + test_999_claim_teardown.tags = ['smoke', 'positive'] diff --git a/marconi/tests/system/claim/test_data.csv b/marconi/tests/system/claim/test_data.csv deleted file mode 100755 index 2e9fa52a3..000000000 --- a/marconi/tests/system/claim/test_data.csv +++ /dev/null @@ -1,15 +0,0 @@ -TestID|httpverb|url|header|body|params|expectedRC|expectedResponseBody -1|POST |/queues/claimtestqueue/claims?limit=2||{"ttl": 50, "grace": 60}||200| -2|POST |/queues/claimtestqueue/claims?limit=5||{"ttl": 50, "grace": 60}||200| -3|POST |/queues/claimtestqueue/claims||{"ttl": 50, "grace": 60}||200| -4|POST |/queues/claimtestqueue/claims?limit=15||{"ttl": 50, "grace": 60}||200| -5|POST |/queues/claimtestqueue/claims?limit=55||{"ttl": 50, "grace": 60}||200| -6|POST |/queues/claimtestqueue/claims?limit=4||{"ttl": 50, "grace": 60}||200| -7|PUT |/queues/claimtestqueue||{"ttl": 50, "grace": 60}||201| -0|POST |/queues/claimtestqueue/messages||||201| -0|DELETE |/queues/claimtestqueue||||204| -8|POST |/queues/claimtestqueue/claims?limit=2||{"ttl": 1, "grace": 1}||200| -9|POST |/queues/claimtestqueue/claims?limit=2||{"ttl": 1, "grace": 1}||200| -10|POST |/queues/claimtestqueue/claims?limit=2||{"ttl": 50, "grace": 60}||200| -11|POST |/queues/claimtestqueue/claims?limit=2||{"ttl": 1, "grace": 1}||200 -11|GET |||||200 \ No newline at end of file diff --git a/marconi/tests/system/common/config.py b/marconi/tests/system/common/config.py index 36c150caa..443d62504 100644 --- a/marconi/tests/system/common/config.py +++ b/marconi/tests/system/common/config.py @@ -41,6 +41,10 @@ class Config(object): def password(self): return self.parser.get('auth', 'password') + @property + def auth_url(self): + return self.parser.get('auth', 'url') + @property def base_server(self): return self.parser.get('marconi_env', 'marconi_url') @@ -49,14 +53,9 @@ class Config(object): def marconi_version(self): return self.parser.get('marconi_env', 'marconi_version') - @property - def tenant_id(self): - return self.parser.get('marconi_env', 'tenant_id') - @property def base_url(self): - return (self.base_server + '/' + self.marconi_version + - '/' + self.tenant_id) + return (self.base_server + '/' + self.marconi_version) @property def uuid(self): @@ -69,3 +68,7 @@ class Config(object): @property def host(self): return self.parser.get('header_values', 'host') + + @property + def project_id(self): + return self.parser.get('header_values', 'project_id') diff --git a/marconi/tests/system/common/functionlib.py b/marconi/tests/system/common/functionlib.py index 2d34378f0..2daad91ed 100644 --- a/marconi/tests/system/common/functionlib.py +++ b/marconi/tests/system/common/functionlib.py @@ -16,6 +16,7 @@ import binascii import json import os +import string from marconi.tests.system.common import config from marconi.tests.system.common import http @@ -49,7 +50,7 @@ def get_keystone_token(): def get_auth_token(): """Returns a valid auth token if auth is turned on.""" - if CFG.auth_enabled == 'true': + if CFG.auth_enabled: auth_token = get_keystone_token() else: auth_token = 'notrealtoken' @@ -61,70 +62,69 @@ def create_marconi_headers(): """Returns headers to be used for all Marconi requests.""" auth_token = get_auth_token() - headers = '{"Host": "","User-Agent": "","Date":"",' + headers = '{"Host": "$host","User-Agent": "$user_agent","Date":"DATE",' headers += '"Accept": "application/json","Accept-Encoding": "gzip",' - headers += '"X-Auth-Token": "","Client-ID": ""}' - headers = headers.replace('', auth_token) - headers = headers.replace('', CFG.host) - headers = headers.replace('', CFG.user_agent) - headers = headers.replace('', CFG.uuid) + headers += '"X-Project-ID": "$project_id",' + headers += '"X-Auth-Token": "$token","Client-ID": "$uuid"}' + headers = string.Template(headers) - return headers + return headers.substitute(host=CFG.host, user_agent=CFG.user_agent, + project_id=CFG.project_id, + token=auth_token, uuid=CFG.uuid) def invalid_auth_token_header(): """Returns a header with invalid auth token.""" - auth_token = get_auth_token() - - headers = '{"Host":"","User-Agent":"","Date":"",' + headers = '{"Host":"$host","User-Agent":"$user_agent","Date":"DATE",' headers += '"Accept": "application/json","Accept-Encoding": "gzip",' - headers += 'X-Auth-Token: }' - headers = headers.replace('', auth_token) - headers = headers.replace('', CFG.host) - headers = headers.replace('', CFG.user_agent) + headers += '"X-Project-ID": "$project_id",' + headers += '"X-Auth-Token": "InvalidToken"}' + headers = string.Template(headers) - return headers + return headers.substitute(host=CFG.host, + project_id=CFG.project_id, + user_agent=CFG.user_agent) def missing_header_fields(): - """Returns a header with missing USER_AGENT header.""" + """Returns a header with missing USER_AGENT & X-Project-ID.""" auth_token = get_auth_token() - headers = '{"Host": "","Date": "",' + headers = '{"Host": "$host","Date": "DATE",' headers += '"Accept": "application/json","Accept-Encoding": "gzip",' - headers += '"X-Auth-Token": ""}' - headers = headers.replace('', auth_token) - headers = headers.replace('', CFG.host) + headers += '"X-Auth-Token": "$token"}' + headers = string.Template(headers) - return headers + return headers.substitute(host=CFG.host, token=auth_token) def plain_text_in_header(): """Returns headers to be used for all Marconi requests.""" auth_token = get_auth_token() - headers = '{"Host":"","User-Agent":"","Date":"",' + headers = '{"Host":"$host","User-Agent":"$user_agent","Date":"DATE",' headers += '"Accept": "text/plain","Accept-Encoding": "gzip",' - headers += '"X-Auth-Token": ""}' - headers = headers.replace('', auth_token) - headers = headers.replace('', CFG.host) - headers = headers.replace('', CFG.user_agent) + headers += '"X-Project-ID": "$project_id",' + headers += '"X-Auth-Token": "$token","Client-ID": "$uuid"}' + headers = string.Template(headers) - return headers + return headers.substitute(host=CFG.host, user_agent=CFG.user_agent, + project_id=CFG.project_id, + token=auth_token, uuid=CFG.uuid) def asterisk_in_header(): """Returns headers to be used for all Marconi requests.""" auth_token = get_auth_token() - headers = '{"Host":"","User-Agent":"","Date":"",' + headers = '{"Host":"$host","User-Agent":"$user_agent","Date":"DATE",' headers += '"Accept": "*/*","Accept-Encoding": "gzip",' - headers += '"X-Auth-Token": ""}' - headers = headers.replace('', auth_token) - headers = headers.replace('', CFG.host) - headers = headers.replace('', CFG.user_agent) + headers += '"X-Project-ID": "$project_id",' + headers += '"X-Auth-Token": "$token"}' + headers = string.Template(headers) - return headers + return headers.substitute(host=CFG.host, user_agent=CFG.user_agent, + project_id=CFG.project_id, token=auth_token) def get_headers(input_header): @@ -146,7 +146,7 @@ def get_headers(input_header): def get_custom_body(kwargs): """Returns a custom request body.""" - req_body = {'data': ''} + req_body = {'data': '[DATA]'} if 'metadatasize' in kwargs.keys(): random_data = binascii.b2a_hex(os.urandom(kwargs['metadatasize'])) req_body['data'] = random_data @@ -167,24 +167,6 @@ def get_url_from_location(header): return url -def verify_metadata(get_data, posted_body): - """TODO(malini) - Really verify the metadata.""" - test_result_flag = False - - get_data = str(get_data) - posted_body = str(posted_body) - print(get_data, type(get_data)) - print(posted_body, type(posted_body)) - - if get_data in posted_body: - print('AYYY') - else: - test_result_flag = False - print('NAYYY') - - return test_result_flag - - def verify_delete(url, header): """Verifies the DELETE was successful, with a GET on the deleted item.""" test_result_flag = False @@ -200,6 +182,6 @@ def verify_delete(url, header): print header print('Response Body') print getmsg.text - assert test_result_flag, 'GET Code {}'.format(getmsg.status_code) + print 'GET Code {}'.format(getmsg.status_code) return test_result_flag diff --git a/marconi/tests/system/common/http.py b/marconi/tests/system/common/http.py index 912f15d5a..020c23daf 100755 --- a/marconi/tests/system/common/http.py +++ b/marconi/tests/system/common/http.py @@ -17,12 +17,12 @@ import json import requests -def get(url, header='', param=''): +def get(url, header=''): """Does http GET.""" if header: header = json.loads(header) try: - response = requests.get(url, headers=header, params=param) + response = requests.get(url, headers=header) except requests.ConnectionError as detail: print('ConnectionError: Exception in http.get {}'.format(detail)) except requests.HTTPError as detail: @@ -34,15 +34,14 @@ def get(url, header='', param=''): return response -def post(url, header='', body='', param=''): +def post(url, header='', body=''): """Does http POST.""" if header: header = json.loads(header) body = str(body) body = body.replace("'", '"') try: - response = requests.post(url, headers=header, data=body, - params=param) + response = requests.post(url, headers=header, data=body) except requests.ConnectionError as detail: print('ConnectionError: Exception in http.post {}'.format(detail)) except requests.HTTPError as detail: @@ -54,15 +53,14 @@ def post(url, header='', body='', param=''): return response -def put(url, header='', body='', param=''): +def put(url, header='', body=''): """Does http PUT.""" response = None if header: header = json.loads(header) try: - response = requests.put(url, headers=header, data=body, - params=param) + response = requests.put(url, headers=header, data=body) except requests.ConnectionError as detail: print('ConnectionError: Exception in http.put {}'.format(detail)) except requests.HTTPError as detail: @@ -74,14 +72,14 @@ def put(url, header='', body='', param=''): return response -def delete(url, header='', param=''): +def delete(url, header=''): """Does http DELETE.""" response = None if header: header = json.loads(header) try: - response = requests.delete(url, headers=header, params=param) + response = requests.delete(url, headers=header) except requests.ConnectionError as detail: print('ConnectionError: Exception in http.delete {}'.format(detail)) except requests.HTTPError as detail: @@ -93,15 +91,14 @@ def delete(url, header='', param=''): return response -def patch(url, header='', body='', param=''): +def patch(url, header='', body=''): """Does http PATCH.""" response = None if header: header = json.loads(header) try: - response = requests.patch(url, headers=header, data=body, - params=param) + response = requests.patch(url, headers=header, data=body) except requests.ConnectionError as detail: print('ConnectionError: Exception in http.patch {}'.format(detail)) except requests.HTTPError as detail: @@ -111,68 +108,3 @@ def patch(url, header='', body='', param=''): except requests.TooManyRedirects as detail: print('TooManyRedirects: Exception in http.patch {}'.format(detail)) return response - - -def executetests(row): - """Entry Point for all tests. - - Executes the tests defined in the *_tests.txt, - using the test data from *_data.csv. - """ - http_verb = row['httpverb'].strip() - url = row['url'] - header = row['header'] - params = row['params'] - body = row['body'] - expected_RC = row['expectedRC'] - expected_RC = int(expected_RC) - expected_response_body = row['expectedResponseBody'] - - response = None - - if http_verb == 'GET': - response = get(url, header, params) - elif http_verb == 'POST': - response = post(url, header, body, params) - elif http_verb == 'PUT': - response = put(url, header, body, params) - elif http_verb == 'DELETE': - response = delete(url, header, params) - elif http_verb == 'PATCH': - response = patch(url, header, body, params) - - if response is not None: - test_result_flag = verify_response(response, expected_RC) - else: - test_result_flag = False - - if test_result_flag: - return response.headers, response.text - else: - print http_verb - print url - print header - print body - print 'Actual Response: {}'.format(response.status_code) - print 'Actual Response Headers' - print response.headers - print'Actual Response Body' - print response.text - print'ExpectedRC: {}'.format(expected_RC) - print'expectedresponsebody: {}'.format(expected_response_body) - assert test_result_flag, 'Actual Response does not match the Expected' - - -def verify_response(response, expected_RC): - """Compares the http Response code with the expected Response code.""" - test_result_flag = True - actual_RC = response.status_code - actual_response_body = response.text - - if actual_RC != expected_RC: - test_result_flag = False - print('Unexpected http Response code {}'.format(actual_RC)) - print 'Response Body returned' - print actual_response_body - - return test_result_flag diff --git a/marconi/tests/system/etc/system-tests.conf-sample b/marconi/tests/system/etc/system-tests.conf-sample index cf064966c..654a7b5cf 100644 --- a/marconi/tests/system/etc/system-tests.conf-sample +++ b/marconi/tests/system/etc/system-tests.conf-sample @@ -6,10 +6,10 @@ username = user password = secret [marconi_env] -marconi_url = http://166.78.143.130:80 +marconi_url = http://0.0.0.0:8888 marconi_version = v1 -tenant_id = 1 [header_values] host = marconi.test.com -useragent = systemtests \ No newline at end of file +useragent = systemtests +project_id = 123456 diff --git a/marconi/tests/system/messages/getdata.py b/marconi/tests/system/messages/getdata.py deleted file mode 100755 index 61ef004b5..000000000 --- a/marconi/tests/system/messages/getdata.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2013 Rackspace, Inc. -# -# 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 csv - -from marconi.tests.system.common import config -from marconi.tests.system.common import functionlib - - -CFG = config.Config() - - -def get_data(): - """Gets Test data from a csv file.""" - data = [] - with open('marconi/tests/system/messages/test_data.csv', 'rb') as datafile: - test_data = csv.DictReader(datafile, delimiter='|') - for row in test_data: - data.append(row) - - for row in data: - row['header'] = functionlib.get_headers(row['header']) - row['url'] = row['url'].replace('', CFG.base_url) - - return data - - -API_TEST_DATA = get_data() diff --git a/marconi/tests/system/messages/messages_tests.txt b/marconi/tests/system/messages/messages_tests.txt deleted file mode 100755 index bd1ba3036..000000000 --- a/marconi/tests/system/messages/messages_tests.txt +++ /dev/null @@ -1,53 +0,0 @@ -| *Setting* | *Value* | -| Documentation | Marconi - Message Test Suite | -| Library | ../common/http.py | -| Library | ../common/functionlib.py | -| Library | msgfnlib.py | -| Library | Collections | -| Variables | getdata.py | -| Force Tags | MESSAGES | -| Suite Setup | executetests | ${API_TEST_DATA[0]} | # Test Suite Setup - Creates a Queue -| Suite Teardown | executetests | ${API_TEST_DATA[7]} | # Test Suite Teardown - Deletes the queue created by setup - -| *Test Case* | *Action* | *Argument* | *Argument* | *Argument* | # Comment -| 1:POST SINGLE MESSAGE | [DOCUMENTATION] | | Post single message | | #TEST CASE 1 - POST SINGLE MESSAGE -| | [Tags] | INSERT_MESSAGE | | | -| | ${reqparam}= | Create Dictionary | messagecount | ${1} | # test Setup- Specify count of messages to be posted -| | ${msgbody}= | dummygetmessagebody | ${reqparam} | | # test Setup- Get the message body to post -| | Set To Dictionary | ${API_TEST_DATA[1]} | body | ${msgbody} | # test Setup -Set the POST body -| | @{postresponse}= | executetests | ${API_TEST_DATA[1]} | | # postresponse = [httpheaders, httpresponsebody] | -| | verifypostmsg | ${postresponse[0]} | ${API_TEST_DATA[1]["body"]} | | # GET the posted message & verify metadata -| | -| 2:POST MULTIPLE MESSAGES | [DOCUMENTATION] | | Post 50 messages | | #TEST CASE 2 - POST MULTIPLE MESSAGES -| | [Tags] | INSERT_MESSAGE | | | -| | ${reqparam}= | Create Dictionary | messagecount | ${50} | # Specify count of messages to be posted -| | ${msgbody}= | dummygetmessagebody | ${reqparam} | | # Gets the message body to post -| | Set To Dictionary | ${API_TEST_DATA[2]} | body | ${msgbody} | # Set the POST body -| | @{postresponse}= | executetests | ${API_TEST_DATA[2]} | | # postresponse = [httpheaders, httpresponsebody] -#| | verifypostmsg | ${postresponse[0]} | ${API_TEST_DATA[2]["body"]} | | # GET the posted messages & verify metadata -| | -| 3:GET MESSAGES-no params | [DOCUMENTATION] | Get message with no params | | # TEST CASE 3 - GET MESSAGE WITH NO PARAMS -| | @{getresponse}= | executetests | ${API_TEST_DATA[3]} | -| | verifygetmsgs | ${10} | @{getresponse} | # Verifies that number of messages returned is <= 10 -| | -| 4:GET MESSAGES-limit=5 | [DOCUMENTATION] | Get message with limit = 5 | | # TEST CASE 4 - GET MESSAGE WITH limit = 5 -| | @{getresponse}= | executetests | ${API_TEST_DATA[4]} | -| | verifygetmsgs | ${5} | @{getresponse} | # Verifies that number of messages returned is <= 5 -| 5:GET MESSAGES-echo=False | [DOCUMENTATION] | Get message with echo=False | | # TEST CASE 5 - GET MESSAGE WITH echo = False -| | @{getresponse}= | executetests | ${API_TEST_DATA[5]} | -| | verifygetmsgs | ${10} | @{getresponse} | # Verifies that number of messages returned is <= 10 -| 6:DELETE MESSAGE | [DOCUMENTATION] | | Delete message | | #TEST CASE 6 - DELETE MESSAGE -| | [Tags] | INSERT_MESSAGE | | | -| | ${reqparam}= | Create Dictionary | messagecount | ${1} | # test Setup- Specify count of messages to be posted -| | ${msgbody}= | dummygetmessagebody | ${reqparam} | | # test Setup- Get the message body to post -| | Set To Dictionary | ${API_TEST_DATA[1]} | body | ${msgbody} | # test Setup -Set the POST body -| | @{postresponse}= | executetests | ${API_TEST_DATA[1]} | | # postresponse = [httpheaders, httpresponsebody] | -| | deletemsg | ${postresponse[0]} | | | # GET the posted message & verify metadata -| 7:POST 60 MESSAGES | [DOCUMENTATION] | POST > MAX NUMBER OF MESSAGES | | | #TEST CASE 7 - POST > 50 MESSAGES -| | ... | ALLOWED PER POST (currently 50) | | | -| | [Tags] | INSERT_MESSAGE | | | -| | ${reqparam}= | Create Dictionary | messagecount | ${60} | # test Setup- Specify count of messages to be posted -| | ${msgbody}= | dummygetmessagebody | ${reqparam} | | # test Setup- Get the message body to post -| | Set To Dictionary | ${API_TEST_DATA[6]} | body | ${msgbody} | # test Setup -Set the POST body -| | @{postresponse}= | executetests | ${API_TEST_DATA[6]} | | # postresponse = [httpheaders, httpresponsebody] | -| | verifypostmsg | ${postresponse[0]} | ${API_TEST_DATA[6]["body"]} | | # GET the posted message & verify metadata diff --git a/marconi/tests/system/messages/msgfnlib.py b/marconi/tests/system/messages/msgfnlib.py index 5f79a0a6d..920b7bf58 100644 --- a/marconi/tests/system/messages/msgfnlib.py +++ b/marconi/tests/system/messages/msgfnlib.py @@ -22,9 +22,6 @@ from marconi.tests.system.common import functionlib from marconi.tests.system.common import http -CFG = config.Config() - - def generate_dict(dict_length): """Returns dictionary of specified length. Key:Value is random data. @@ -72,21 +69,16 @@ def get_message_body(**kwargs): """ message_count = kwargs['messagecount'] multiple_message_body = [] - for i in range[message_count]: + for i in range(message_count): message_body = single_message_body(**kwargs) multiple_message_body.append(message_body) return multiple_message_body -def dummyget_message_body(dict): - """Dummy function since Robot framework does not support **kwargs.""" - dict = get_message_body(**dict) - return dict - - -def create_url(base_url=CFG.base_url, *msg_id_list): +def create_url(*msg_id_list): """Creates url list for retrieving messages with message id.""" - url = [(base_url + msg_id) for msg_id in msg_id_list] + cfg = config.Config() + url = [(cfg.base_url + msg_id) for msg_id in msg_id_list] return url @@ -133,8 +125,7 @@ def verify_post_msg(msg_headers, posted_body): getmsg = http.get(url, header) if getmsg.status_code == 200: - test_result_flag = functionlib.verify_metadata(getmsg.text, - posted_body) + test_result_flag = True else: print('Failed to GET {}'.format(url)) print('Request Header') @@ -143,7 +134,7 @@ def verify_post_msg(msg_headers, posted_body): print getmsg.headers print('Response Body') print getmsg.text - assert test_result_flag, 'HTTP code {}'.format(getmsg.status_code) + return test_result_flag def get_next_msgset(responsetext): @@ -184,8 +175,7 @@ def verify_get_msgs(count, *getresponse): print('Messages returned exceed requested number of messages') test_result_flag = False - if not test_result_flag: - assert test_result_flag, 'Recursive Get Messages Failed' + return test_result_flag def delete_msg(*postresponse): @@ -211,4 +201,6 @@ def delete_msg(*postresponse): print header print('Response Body') print deletemsg.text - assert test_result_flag, 'DELETE Code {}'.format(deletemsg.status_code) + print 'DELETE Code {}'.format(deletemsg.status_code) + + return test_result_flag diff --git a/marconi/tests/system/messages/test_data.csv b/marconi/tests/system/messages/test_data.csv deleted file mode 100755 index 75a22b853..000000000 --- a/marconi/tests/system/messages/test_data.csv +++ /dev/null @@ -1,9 +0,0 @@ -TestID|httpverb|url|header|body|params|expectedRC|expectedResponseBody -0|PUT |/queues/msgtestqueue||{"messages":{"ttl": 86400}}||201| -1|POST |/queues/msgtestqueue/messages||||201| -2|POST |/queues/msgtestqueue/messages||||201| -3|GET |/queues/msgtestqueue/messages?echo=true||||200| -4|GET |/queues/msgtestqueue/messages?limit=5&echo=true||||200| -5|GET |/queues/msgtestqueue/messages?limit=5&echo=true||||200| -6|POST |/queues/msgtestqueue/messages||{"messages":{"ttl": 86400}}||201| -0|DELETE |/queues/msgtestqueue||||204| \ No newline at end of file diff --git a/marconi/tests/system/messages/test_messages.py b/marconi/tests/system/messages/test_messages.py new file mode 100644 index 000000000..49b6016c0 --- /dev/null +++ b/marconi/tests/system/messages/test_messages.py @@ -0,0 +1,158 @@ +# Copyright (c) 2013 Rackspace, Inc. +# +# 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. +from marconi.tests.system.common import config +from marconi.tests.system.common import functionlib +from marconi.tests.system.common import http +from marconi.tests.system.messages import msgfnlib + +import testtools + + +class TestMessages(testtools.TestCase): + """Tests for Messages.""" + + def setUp(self): + super(TestMessages, self).setUp() + self.cfg = config.Config() + self.header = functionlib.create_marconi_headers() + + def test_000_message_setup(self): + """Create Queue for Message Tests.""" + url = self.cfg.base_url + '/queues/messagetestqueue' + doc = '{"queuemetadata": "message test queue"}' + result = http.put(url, self.header, doc) + + self.assertEqual(result.status_code, 201) + + test_000_message_setup.tags = ['smoke', 'positive'] + + def test_001_message_single_insert(self): + """Insert Single Message into the Queue.""" + doc = msgfnlib.get_message_body(messagecount=1) + url = self.cfg.base_url + '/queues/messagetestqueue/messages' + result = http.post(url, self.header, doc) + + self.assertEqual(result.status_code, 201) + + #GET on posted message + location = result.headers['location'] + url = self.cfg.base_server + location + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + + #Compare message metadata + result_body = result.json()['body'] + posted_metadata = doc[0]['body'] + self.assertEqual(result_body, posted_metadata) + + test_001_message_single_insert.tags = ['smoke', 'positive'] + + def test_002_message_bulk_insert(self): + """Bulk Insert Messages into the Queue.""" + doc = msgfnlib.get_message_body(messagecount=30) + url = self.cfg.base_url + '/queues/messagetestqueue/messages' + result = http.post(url, self.header, doc) + + self.assertEqual(result.status_code, 201) + + #GET on posted messages + location = result.headers['location'] + url = self.cfg.base_server + location + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + + #Compare message metadata + result_body = result.json()['body'] + posted_metadata = doc[0]['body'] + self.assertEqual(result_body, posted_metadata) + + test_002_message_bulk_insert.tags = ['smoke', 'positive'] + + def test_003_message_get_no_params(self): + """Get Messages with no params.""" + default_msg_count = 10 + url = self.cfg.base_url + '/queues/messagetestqueue/messages' + result = http.get(url, self.header) + + self.assertEqual(result.status_code, 200) + + test_result_flag = msgfnlib.verify_get_msgs(default_msg_count, + result.headers, + result.text) + self.assertEqual(test_result_flag, True) + + test_003_message_get_no_params.tags = ['smoke', 'positive'] + + def test_004_message_get_limit_5(self): + """Get Messages with no params.""" + msg_count = 5 + url = self.cfg.base_url + '/queues/messagetestqueue/messages?limit=5' + result = http.get(url, self.header) + + self.assertEqual(result.status_code, 200) + + test_result_flag = msgfnlib.verify_get_msgs(msg_count, + result.headers, + result.text) + self.assertEqual(test_result_flag, True) + + test_004_message_get_limit_5.tags = ['smoke', 'positive'] + + def test_005_message_get_echo_false(self): + """Get Messages with echo=false.""" + url = self.cfg.base_url + \ + '/queues/messagetestqueue/messages?echo=false' + result = http.get(url, self.header) + + self.assertEqual(result.status_code, 204) + + test_005_message_get_echo_false.tags = ['smoke', 'positive'] + + def test_006_message_delete(self): + """Delete Message.""" + doc = msgfnlib.get_message_body(messagecount=1) + url = self.cfg.base_url + '/queues/messagetestqueue/messages' + result = http.post(url, self.header, doc) + + self.assertEqual(result.status_code, 201) + + #Delete posted message + location = result.headers['location'] + url = self.cfg.base_server + location + result = http.delete(url, self.header) + self.assertEqual(result.status_code, 204) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 404) + + test_006_message_delete.tags = ['smoke', 'positive'] + + def test_007_message_bulk_insert_60(self): + """Insert more than max allowed messages. + + Marconi allows a maximum of 50 message per POST. + """ + doc = msgfnlib.get_message_body(messagecount=60) + url = self.cfg.base_url + '/queues/messagetestqueue/messages' + result = http.post(url, self.header, doc) + + self.assertEqual(result.status_code, 400) + + test_007_message_bulk_insert_60.tags = ['negative'] + + def test_999_message_teardown(self): + url = self.cfg.base_url + '/queues/messagetestqueue' + http.delete(url, self.header) + test_999_message_teardown.tags = ['smoke', 'positive'] diff --git a/marconi/tests/system/queue/getdata.py b/marconi/tests/system/queue/getdata.py deleted file mode 100755 index a6a0ea242..000000000 --- a/marconi/tests/system/queue/getdata.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2013 Rackspace, Inc. -# -# 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 csv - -from marconi.tests.system.common import config -from marconi.tests.system.common import functionlib - - -CFG = config.Config() - - -def get_data(): - """Gets Test data from a csv file.""" - data = [] - with open('marconi/tests/system/queue/test_data.csv', 'rb') as datafile: - test_data = csv.DictReader(datafile, delimiter='|') - for row in test_data: - data.append(row) - - for row in data: - row['header'] = functionlib.get_headers(row['header']) - row['url'] = row['url'].replace('', CFG.base_url) - - return data - -API_TEST_DATA = get_data() diff --git a/marconi/tests/system/queue/queue_tests.txt b/marconi/tests/system/queue/queue_tests.txt deleted file mode 100755 index c9106ffe2..000000000 --- a/marconi/tests/system/queue/queue_tests.txt +++ /dev/null @@ -1,106 +0,0 @@ -| *Setting* | *Value* | -| Documentation | Marconi - Queue Test Suite | -| Library | ../common/http.py | -| Library | queuefnlib.py | -| Library | ../common/functionlib.py | -| Library | Collections | -| Variables | getdata.py | -| Force Tags | QUEUE | - -| *Test Case* | *Action* | *Argument* | *Argument* | -| 1: PUT QUEUE | [DOCUMENTATION] | Creates, gets & verifies | | -| | ... | Queue | | -| | @{putresponse}= | executetests | ${API_TEST_DATA[0]} | -| | ${url}= | geturlfromlocation | ${putresponse[0]} | -| | ${getresponse}= | executetests | ${API_TEST_DATA[1]} | -| | verifymetadata | ${API_TEST_DATA[0]["body"]} | ${getresponse} | -| 2: PUT QUEUE | [DOCUMENTATION] | Verifies that queue name | | -| | ... | are NOT case sensitive | | -| | ${putresponse}= | executetests | ${API_TEST_DATA[2]} | -| | ${getresponse}= | executetests | ${API_TEST_DATA[3]} | -| | verifymetadata | ${API_TEST_DATA[2]["body"]} | ${getresponse} | -| 3: UPDATE QUEUE | [DOCUMENTATION] | Updates an existing queue | | -| | ${putresponse}= | executetests | ${API_TEST_DATA[4]} | -| | ${getresponse}= | executetests | ${API_TEST_DATA[5]} | -| | verifymetadata | ${API_TEST_DATA[4]["body"]} | ${getresponse} | -| 4: PUT QUEUE | [DOCUMENTATION] | Create Queue with no request | | -| | ... | body | | -| | executetests | ${API_TEST_DATA[6]} | | -| 5: PUT QUEUE | [DOCUMENTATION] | Create Queue with invalid | | -| | ... | Authtoken | | -| | ${header}= | invalidauthtokenheader | | -| | Set To Dictionary | ${API_TEST_DATA[7]} | header | ${header} | # test Setup -Set the POST header -| | executetests | ${API_TEST_DATA[7]} | | -| 6: PUT QUEUE | [DOCUMENTATION] | Create Queue with missing | | -| | ... | header field USERAGENT | | -| | ${header}= | missingheaderfields | | -| | Set To Dictionary | ${API_TEST_DATA[8]} | header | ${header} | # test Setup -Set the POST header -| | executetests | ${API_TEST_DATA[8]} | | -| 7: PUT QUEUE | [DOCUMENTATION] | Verifies metadata toplevel | | -| | ... | field do not start with _ | | -| | executetests | ${API_TEST_DATA[9]} | | -| 8: PUT QUEUE | [DOCUMENTATION] | Header has Accept value that | | -| | ... | is not "application/json" | | -| | ${header}= | plaintextinheader | | -| | Set To Dictionary | ${API_TEST_DATA[10]} | header | ${header} | # test Setup -Set the POST header -| | executetests | ${API_TEST_DATA[10]} | | -| 9: PUT QUEUE | [DOCUMENTATION] | Header has Accept value that | | -| | ... | is "\*/\*" | | -| | ${header}= | asteriskinheader | | -| | Set To Dictionary | ${API_TEST_DATA[11]} | header | ${header} | # test Setup -Set the POST header -| | executetests | ${API_TEST_DATA[11]} | | -| 10: PUT QUEUE | [DOCUMENTATION] | Create queue with Non ASCII | | -| | ... | characters in name | | -| | executetests | ${API_TEST_DATA[12]} | | -| 11: PUT QUEUE | [DOCUMENTATION] | Create queue with Non ASCII | | -| | ... | characters in body | | -| | executetests | ${API_TEST_DATA[13]} | | -| 12: PUT QUEUE | [DOCUMENTATION] | Create queue with metadata | | -| | ... | size = 4KB | | -| | ${reqdata}= | Create Dictionary | metadatasize | ${4096} | -| | ${body}= | getcustombody | ${reqdata} | -| | Set To Dictionary | ${API_TEST_DATA[14]} | body | ${body} | # test Setup -Set the POST body -| | executetests | ${API_TEST_DATA[14]} | | -| 13: PUT QUEUE | [DOCUMENTATION] | Create queue with metadata | | -| | ... | size = 4KB + 1 | | -| | ${reqdata}= | Create Dictionary | metadatasize | ${4097} | -| | ${body}= | getcustombody | ${reqdata} | -| | Set To Dictionary | ${API_TEST_DATA[15]} | body | ${body} | # test Setup -Set the POST body -| | executetests | ${API_TEST_DATA[15]} | | -| 14: PUT QUEUE | [DOCUMENTATION] | Create queue with metadata | | -| | ... | size = 4KB - 1 | | -| | ${reqdata}= | Create Dictionary | metadatasize | ${4095} | -| | ${body}= | getcustombody | ${reqdata} | -| | Set To Dictionary | ${API_TEST_DATA[16]} | body | ${body} | # test Setup -Set the POST body -| | executetests | ${API_TEST_DATA[16]} | | -| 15: PUT QUEUE | [DOCUMENTATION] | Create queue with name | | -| | ... | longer than 64 char | | -| | ${url}= | getqueuename | | -| | Set To Dictionary | ${API_TEST_DATA[17]} | url | ${url} | # test Setup -Set the PUT url -| | executetests | ${API_TEST_DATA[17]} | | -| 16: GET QUEUE STATS | [DOCUMENTATION] | Get Queue Stats | | -| | @{getresponse}= | executetests | ${API_TEST_DATA[18]} | -| | verifyqueuestats | @{getresponse} | | -| 17: LIST QUEUES | [DOCUMENTATION] | List queues with no params | | -| | @{listqueues}= | executetests | ${API_TEST_DATA[19]} | -| | verifylistqueues | @{listqueues} | | -| 18: LIST QUEUES DETAILED | [DOCUMENTATION] | List queues ?detailed=true | | -| | @{listqueues}= | executetests | ${API_TEST_DATA[20]} | -| | verifylistqueues | @{listqueues} | | -| 19: DELETE QUEUE | [DOCUMENTATION] | Delete a queue | | -| | executetests | ${API_TEST_DATA[21]} | | -| 20: PUT QUEUE | [DOCUMENTATION] | Creates a queue with same | | -| | ... | name as deleted | | -| | @{putresponse}= | executetests | ${API_TEST_DATA[22]} | -| | ${url}= | geturlfromlocation | ${putresponse[0]} | -| | ${getresponse}= | executetests | ${API_TEST_DATA[23]} | -| | verifymetadata | ${API_TEST_DATA[22]["body"]} | ${getresponse} | -| 21: PUT QUEUE | [DOCUMENTATION] | Create Queue with invalid | | -| | ... | char in metadata | | -| | executetests | ${API_TEST_DATA[24]} | | -| 22: DELETE QUEUE | [DOCUMENTATION] | Delete a queue | | -| | executetests | ${API_TEST_DATA[25]} | | -| 23: GET QUEUE - 404 | [DOCUMENTATION] | Get non existing queue | | -| | executetests | ${API_TEST_DATA[26]} | | - - diff --git a/marconi/tests/system/queue/queuefnlib.py b/marconi/tests/system/queue/queuefnlib.py index 751f01ca9..ebe514b1d 100644 --- a/marconi/tests/system/queue/queuefnlib.py +++ b/marconi/tests/system/queue/queuefnlib.py @@ -69,8 +69,7 @@ def get_queue_name(namelength=65): """ appender = '/queues/' + binascii.b2a_hex(os.urandom(namelength)) - url = functionlib.create_url_from_appender(appender) - return url + return appender def verify_list_queues(*list_queue_response): @@ -78,6 +77,7 @@ def verify_list_queues(*list_queue_response): :param *list_queue_response: [header, body] returned for list queue. """ + test_result_flag = True response_body = json.loads(list_queue_response[1]) links = response_body['links'] href = links[0]['href'] @@ -90,10 +90,12 @@ def verify_list_queues(*list_queue_response): if False in test_result_flags: test_result_flag = False print 'List Queue API response: {}'.format(response_body) - assert test_result_flag, 'List Queue failed' + return test_result_flag if links[0]['rel'] == 'next': - list_queues(href) + test_result_flag = list_queues(href) + + return test_result_flag def verify_listed(queue, detail_enabled): @@ -136,8 +138,7 @@ def list_queues(href): if list_queue_response.status_code == 200: headers = list_queue_response.headers text = list_queue_response.text - verify_list_queues(headers, text) + test_result_flag = verify_list_queues(headers, text) elif list_queue_response.status_code == 204: test_result_flag = True - else: - assert test_result_flag, 'List Queue failed' + return test_result_flag diff --git a/marconi/tests/system/queue/test_data.csv b/marconi/tests/system/queue/test_data.csv deleted file mode 100755 index ff02780d1..000000000 --- a/marconi/tests/system/queue/test_data.csv +++ /dev/null @@ -1,28 +0,0 @@ -TestID|httpverb|url|header|body|params|expectedRC|expectedResponseBody -1|PUT |/queues/qtestqueue||{"messages":{"ttl": 86400}}||201| -1|GET |/queues/qtestqueue||||200|{"ttl": 86400} -2|PUT |/queues/qtestqueue||{"messages": {"ttl": 86400}}||204| -2|GET |/queues/qtestqueue||||200|{"ttl": 86400} -3|PUT |/queues/qtestqueue||{"messages": {"ttl": 86400}}||204| -3|GET |/queues/qtestqueue||||200|{"ttl": 86400} -4|PUT |/queues/qtestqueue||||400|{"title": "Bad request","description": "Missing queue metadata."} -5|PUT |/queues/qtestqueue||{"messages": {"ttl": 86400}}||401| -6|PUT |/queues/qtestqueue||{"messages": {"ttl": 86400}}||400| -7|PUT |/queues/qtestqueue||{"_TOPLEVEL": {"ttl": 86400}}||400| -8|PUT |/queues/qtestqueue||{"TOPLEVEL": {"ttl": 86400}}||406| -9|PUT |/queues/qtestqueue||{"TOPLEVEL": {"ttl": 86400}}||200| -10|PUT |/queues/汉字/漢字||{"messages": {"ttl": 86400}}||201| -11|PUT |/queues/qtestqueue||{"汉字": {"ttl": 86400}}||201| -12|PUT |/queues/qtestqueue||||201| -13|PUT |/queues/qtestqueue||||400| -14|PUT |/queues/qtestqueue||||204| -15|PUT |||{"messages":{"ttl": 86400}}||400| -16|GET |/queues/qtestqueue/stats||||200| -17|GET |/queues?limit=1||||200| -18|GET |/queues?detailed=true||||200| -19|DELETE |/queues/qtestqueue||||204| -20|PUT |/queues/qtestqueue||{"messages":{"ttl": 86400}}||201| -20|GET |/queues/qtestqueue||||200|{"ttl": 86400} -21|PUT |/queues/qtestqueue||{"mess~&%^":{"ttl": 86400}}||400| -22|DELETE |/queues/qtestqueue||||204| -23|GET |/queues/nonexistingqueue||||404| \ No newline at end of file diff --git a/marconi/tests/system/queue/test_queue.py b/marconi/tests/system/queue/test_queue.py new file mode 100644 index 000000000..a284e63cd --- /dev/null +++ b/marconi/tests/system/queue/test_queue.py @@ -0,0 +1,331 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013 Rackspace, Inc. +# +# 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 testtools + +from marconi.tests.system.common import config +from marconi.tests.system.common import functionlib +from marconi.tests.system.common import http +from marconi.tests.system.queue import queuefnlib + +import json + + +class TestQueue(testtools.TestCase): + """Tests for queue.""" + + def setUp(self): + super(TestQueue, self).setUp() + self.cfg = config.Config() + self.header = functionlib.create_marconi_headers() + + def test_001_queue_insert(self): + """Insert Queue. + + Creates Queue, does a get & verifies data. + """ + url = self.cfg.base_url + '/queues/qtestqueue' + doc = '{"queue": "Apple"}' + result = http.put(url, self.header, doc) + + self.assertEqual(result.status_code, 201) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + self.assertEqual(result.json(), json.loads(doc)) + + test_001_queue_insert.tags = ['smoke', 'positive', 'create_queue'] + + def test_002_queue_insert_case_insensitive(self): + """Insert Queue with same name, different case.""" + url = self.cfg.base_url + '/queues/QteStquEue' + doc = '{"queue": "Orange"}' + + result = http.put(url, self.header, doc) + self.assertEqual(result.status_code, 201) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + self.assertEqual(result.json(), json.loads(doc)) + + http.delete(url, self.header) + + test_002_queue_insert_case_insensitive.tags = ['positive'] + + def test_003_queue_update_empty_metadata(self): + """Update Queue with empty metadata.""" + url = self.cfg.base_url + '/queues/qtestqueue' + doc_original = '{"queue": "Apple"}' + doc = '' + + result = http.put(url, self.header, doc) + self.assertEqual(result.status_code, 400) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + self.assertEqual(result.json(), json.loads(doc_original)) + + test_003_queue_update_empty_metadata.tags = ['negative'] + + def test_004_queue_update_empty_json(self): + """Update Queue with empty json.""" + url = self.cfg.base_url + '/queues/qtestqueue' + doc = '{}' + + result = http.put(url, self.header, doc) + self.assertEqual(result.status_code, 204) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + self.assertEqual(result.json(), json.loads(doc)) + + test_004_queue_update_empty_json.tags = ['smoke', 'positive'] + + def test_005_queue_insert_invalid_authtoken(self): + """Insert Queue with invalid authtoken.""" + url = self.cfg.base_url + '/queues/invalidauthtoken' + header = functionlib.invalid_auth_token_header() + doc = '{"queue": "invalid auth token"}' + + result = http.put(url, header, doc) + self.assertEqual(result.status_code, 401) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 404) + + test_005_queue_insert_invalid_authtoken.tags = ['negative'] + + def test_006_queue_update_invalid_authtoken(self): + """Update Queue with invalid authtoken.""" + url = self.cfg.base_url + '/queues/qtestqueue' + header = functionlib.invalid_auth_token_header() + doc = '{"queue": "invalid auth token"}' + doc_original = '{}' + + result = http.put(url, header, doc) + self.assertEqual(result.status_code, 401) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + self.assertEqual(result.json(), json.loads(doc_original)) + + test_006_queue_update_invalid_authtoken.tags = ['negative'] + + def test_007_queue_insert_missing_header(self): + """Insert Queue with missing header field. + + Request has no USER_AGENT & X-Project-Id headers. + """ + url = self.cfg.base_url + '/queues/missingheader' + header = functionlib.missing_header_fields() + doc = '{"queue": "USER_AGENT header is missing"}' + + result = http.put(url, header, doc) + self.assertEqual(result.status_code, 400) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 404) + + test_007_queue_insert_missing_header.tags = ['negative'] + + def test_008_queue_insert_toplevel_underscore(self): + """Insert Queue with underscore in toplevel field.""" + url = self.cfg.base_url + '/queues/toplevel' + doc = '{"_queue": "Top Level field with _"}' + + result = http.put(url, self.header, doc) + self.assertEqual(result.status_code, 400) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 404) + + test_008_queue_insert_toplevel_underscore.tags = ['negative'] + + def test_009_queue_insert_header_plaintext(self): + """Insert Queue with 'Accept': 'plain/text'.""" + url = self.cfg.base_url + '/queues/plaintextheader' + header = functionlib.plain_text_in_header() + doc = '{"queue": "text/plain in header"}' + + result = http.put(url, header, doc) + self.assertEqual(result.status_code, 406) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 404) + + test_009_queue_insert_header_plaintext.tags = ['negative'] + + def test_010_queue_insert_header_asterisk(self): + """Insert Queue with 'Accept': '*/*'.""" + url = self.cfg.base_url + '/queues/asteriskinheader' + header = functionlib.asterisk_in_header() + doc = '{"queue": "*/* in header"}' + + result = http.put(url, header, doc) + self.assertEqual(result.status_code, 201) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + + http.delete(url, self.header) + + test_010_queue_insert_header_asterisk.tags = ['positive'] + + def test_011_queue_insert_nonASCII_name(self): + """Insert Queue with non ASCII name.""" + url = self.cfg.base_url + '/queues/汉字/漢字' + doc = '{"queue": "non ASCII name"}' + + result = http.put(url, self.header, doc) + self.assertEqual(result.status_code, 400) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 404) + + test_011_queue_insert_nonASCII_name.tags = ['negative'] + + def test_012_queue_insert_nonASCII_metadata(self): + """Insert Queue with non ASCII name.""" + url = self.cfg.base_url + '/queues/nonASCIImetadata' + doc = '{"汉字": "non ASCII metadata"}' + + result = http.put(url, self.header, doc) + self.assertEqual(result.status_code, 400) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 404) + + test_012_queue_insert_nonASCII_metadata.tags = ['negative'] + + def test_013_queue_update_metadata_size4095(self): + """Updates Queue with metadata_size = 4095.""" + url = self.cfg.base_url + '/queues/qtestqueue' + doc = functionlib.get_custom_body({"metadatasize": 4095}) + result = http.put(url, self.header, doc) + + self.assertEqual(result.status_code, 204) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + self.assertEqual(result.json(), json.loads(doc)) + + test_013_queue_update_metadata_size4095.tags = ['positive'] + + def test_014_queue_update_metadata_size4096(self): + """Updates Queue with metadata_size = 4096.""" + url = self.cfg.base_url + '/queues/qtestqueue' + doc = functionlib.get_custom_body({"metadatasize": 4096}) + result = http.put(url, self.header, doc) + + self.assertEqual(result.status_code, 204) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 200) + self.assertEqual(result.json(), json.loads(doc)) + + test_014_queue_update_metadata_size4096.tags = ['positive'] + + def test_015_queue_update_metadata_size4097(self): + """Updates Queue with metadata_size = 4097.""" + url = self.cfg.base_url + '/queues/qtestqueue' + doc = functionlib.get_custom_body({"metadatasize": 4097}) + result = http.put(url, self.header, doc) + + self.assertEqual(result.status_code, 400) + + test_015_queue_update_metadata_size4097.tags = ['negative'] + + def test_016_queue_insert_long_queuename(self): + """Insert queue with name > 64 bytes.""" + url = self.cfg.base_url + queuefnlib.get_queue_name() + doc = '{"queue": "Longer than allowed queue name"}' + result = http.put(url, self.header, doc) + + self.assertEqual(result.status_code, 400) + + test_016_queue_insert_long_queuename.tags = ['negative'] + + def test_017_queue_stats(self): + """Insert queue with name > 64 bytes.""" + url = self.cfg.base_url + '/queues/qtestqueue/stats' + result = http.get(url, self.header) + + self.assertEqual(result.status_code, 200) + + test_result_flag = queuefnlib.verify_queue_stats(result.headers, + result.text) + self.assertEqual(test_result_flag, True) + + test_017_queue_stats.tags = ['smoke', 'positive'] + + def test_018_queue_list(self): + """List Queues.""" + url = self.cfg.base_url + '/queues' + result = http.get(url, self.header) + + self.assertEqual(result.status_code, 200) + + test_result_flag = queuefnlib.verify_list_queues(result.headers, + result.text) + self.assertEqual(test_result_flag, True) + + test_018_queue_list.tags = ['smoke', 'positive'] + + def test_019_queue_list_detailed(self): + """List Queues with detailed = True.""" + url = self.cfg.base_url + '/queues?detailed=True' + result = http.get(url, self.header) + + self.assertEqual(result.status_code, 200) + + test_result_flag = queuefnlib.verify_list_queues(result.headers, + result.text) + self.assertEqual(test_result_flag, True) + + test_019_queue_list_detailed.tags = ['smoke', 'positive'] + + def test_020_queue_insert_metadata_invalidchar(self): + """Update Queues with invalid char in metadata.""" + url = self.cfg.base_url + '/queues/qtestqueue' + doc = '{"queue": "#$%^&Apple"}' + result = http.put(url, self.header, doc) + + self.assertEqual(result.status_code, 400) + + test_020_queue_insert_metadata_invalidchar.tags = ['negative'] + + def test_021_queue_get_nonexisting(self): + """Update Queues with invalid char in metadata.""" + url = self.cfg.base_url + '/queues/nonexistingqueue' + result = http.get(url, self.header) + + self.assertEqual(result.status_code, 404) + + test_021_queue_get_nonexisting.tags = ['negative'] + + def test_999_delete_queue(self): + """Delete Queue. + + Deletes Queue & performs GET to confirm 404. + """ + url = self.cfg.base_url + '/queues/qtestqueue' + + result = http.delete(url, self.header) + self.assertEqual(result.status_code, 204) + + result = http.get(url, self.header) + self.assertEqual(result.status_code, 404) + + test_999_delete_queue.tags = ['smoke'] diff --git a/tools/system-test-requires b/tools/system-test-requires index b140c0d27..663bd1f6a 100644 --- a/tools/system-test-requires +++ b/tools/system-test-requires @@ -1,2 +1 @@ -robotframework requests \ No newline at end of file