Implements integration testing framework
- reusing functional tests for integration purposes - common parts of both test frameworks were extracted to tests/common - tox.ini updated - README updated - test_regression.sh updated to run regression checks on both integration and functional
This commit is contained in:
parent
d5df8430b9
commit
fd43c0f157
68
README.md
68
README.md
@ -61,10 +61,6 @@ Install dependencies:
|
||||
|
||||
$ pip install -r requirements.txt -r test-requirements.txt
|
||||
|
||||
Install `functions_python` lib:
|
||||
|
||||
$ pip install -e git+ssh://git@github.com/iron-io/functions_python.git#egg=functions-python
|
||||
|
||||
Install LaOS itself:
|
||||
|
||||
$ pip install -e .
|
||||
@ -191,8 +187,70 @@ Cons:
|
||||
Testing: Integration
|
||||
--------------------
|
||||
|
||||
TBD
|
||||
Integration tests are dependent on following env variables:
|
||||
|
||||
* TEST_DB_URI - similar to functional tests, database endpoint
|
||||
* FUNCTIONS_HOST - IronFunctions API host
|
||||
* FUNCTIONS_PORT - IronFunctions API port
|
||||
* FUNCTIONS_API_PROTO - IronFunctions API protocol
|
||||
* FUNCTIONS_API_VERSION - IronFunctions API version
|
||||
* OS_AUTH_URL - OpenStack Identity endpoint
|
||||
* OS_PROJECT_ID - OpenStack user-specific project ID
|
||||
* OS_TOKEN - OpenStack user project-bound auth token
|
||||
|
||||
How to get token? - Set env variables:
|
||||
|
||||
* OS_USERNAME
|
||||
* OS_PASSWORD
|
||||
* OS_PROJECT_NAME
|
||||
|
||||
and run following command:
|
||||
|
||||
echo -e "{
|
||||
\"auth\": {
|
||||
\"identity\": {
|
||||
\"methods\": [\"password\"],
|
||||
\"password\": {
|
||||
\"user\": {
|
||||
\"name\": \"${OS_USERNAME:-admin}\",
|
||||
\"domain\": { \"id\": \"${OS_DOMAIN:-default}\" },
|
||||
\"password\": \"${OS_PASSWORD:-root}\"
|
||||
}
|
||||
}
|
||||
},
|
||||
\"scope\": {
|
||||
\"project\": {
|
||||
\"name\": \"${OS_PROJECT_NAME:-admin}\",
|
||||
\"domain\": {\"id\": \"${OS_DOMAIN:-default}\" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}" >> token_request.json
|
||||
|
||||
After that:
|
||||
|
||||
export OS_TOKEN=`curl -si -d @token_request.json -H "Content-type: application/json" ${OS_AUTH_URL}/auth/tokens | awk '/X-Subject-Token/ {print $2}'`
|
||||
|
||||
If variable remains empty, please check your authentication parameters specified in `token_request.json`.
|
||||
|
||||
How to get project ID? - Use following command
|
||||
|
||||
export RAW_PrID=`curl -si -d @token_request.json -H "Content-type: application/json" ${OS_AUTH_URL}/auth/tokens | grep Default | awk '{print $20}'`
|
||||
export OS_PROJECT_ID=${RAW_PrID:1:-2}
|
||||
|
||||
If variable remains empty, please check your authentication parameters specified in `token_request.json`.
|
||||
|
||||
To run tests use following command:
|
||||
|
||||
export TEST_DB_URI=mysql://<your-user>:<your-user-password>@<mysql-host>:<mysql-port>/<functions-db>
|
||||
export FUNCTIONS_HOST=<functions-host>
|
||||
export FUNCTIONS_PORT=<functions-port>
|
||||
export FUNCTIONS_API_PROTO=<functions-api-protocol>
|
||||
export FUNCTIONS_API_VERSION=<functions-api-version>
|
||||
export OS_AUTH_URL=<openstack-idenitity-url>
|
||||
export OS_PROJECT_ID=<project-id>
|
||||
export OS_TOKEN=<project-bound-auth-token>
|
||||
tox -epy35-integration
|
||||
|
||||
Testing: Coverage regression
|
||||
----------------------------
|
||||
|
@ -210,7 +210,8 @@ class AppV1Controller(controllers.ServiceControllerBase):
|
||||
if fn_app_routes:
|
||||
return web.json_response(data={
|
||||
"error": {
|
||||
"message": ("Unable to delete app {} with routes".format(app))
|
||||
"message": ("Unable to delete app {} "
|
||||
"with routes".format(app))
|
||||
}
|
||||
}, status=403)
|
||||
|
||||
|
0
laos/tests/common/__init__.py
Normal file
0
laos/tests/common/__init__.py
Normal file
84
laos/tests/common/apps.py
Normal file
84
laos/tests/common/apps.py
Normal file
@ -0,0 +1,84 @@
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
class AppsTestSuite(object):
|
||||
|
||||
def list_apps(self):
|
||||
json, http_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.list())
|
||||
self.assertIn("message", json)
|
||||
self.assertIn("apps", json)
|
||||
self.assertEqual(200, http_status)
|
||||
|
||||
def get_unknown(self):
|
||||
json, http_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.show("unknown"))
|
||||
self.assertEqual(404, http_status)
|
||||
self.assertIn("error", json)
|
||||
|
||||
def create_and_delete(self):
|
||||
create_json, create_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
delete_json, delete_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
|
||||
self.assertIn("message", create_json)
|
||||
self.assertIn("app", create_json)
|
||||
self.assertEqual(200, create_status)
|
||||
|
||||
self.assertIn("message", delete_json)
|
||||
self.assertEqual(200, delete_status)
|
||||
|
||||
def attempt_to_double_create(self):
|
||||
app = "testapp"
|
||||
create_json, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create(app))
|
||||
err, status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create(app))
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
self.assertEqual(409, status)
|
||||
self.assertIn("error", err)
|
||||
self.assertIn("message", err["error"])
|
||||
|
||||
def attempt_delete_unknonw(self):
|
||||
json, http_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete("unknown"))
|
||||
self.assertEqual(404, http_status)
|
||||
self.assertIn("error", json)
|
||||
|
||||
def delete_with_routes(self):
|
||||
app_name = "testapp"
|
||||
app, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create(app_name))
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.routes.create(
|
||||
app["app"]["name"], **self.route_data)
|
||||
)
|
||||
attempt, status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(app["app"]["name"])
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.routes.delete(
|
||||
app["app"]["name"], self.route_data["path"])
|
||||
)
|
||||
_, status_2 = self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(app["app"]["name"])
|
||||
)
|
||||
self.assertEqual(403, status)
|
||||
self.assertIn("error", attempt)
|
||||
self.assertIn("message", attempt["error"])
|
||||
self.assertIn("with routes", attempt["error"]["message"])
|
||||
self.assertEqual(200, status_2)
|
42
laos/tests/common/base.py
Normal file
42
laos/tests/common/base.py
Normal file
@ -0,0 +1,42 @@
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 asyncio
|
||||
import datetime
|
||||
import uvloop
|
||||
|
||||
from laos.common import logger as log
|
||||
|
||||
|
||||
class LaosTestsBase(object):
|
||||
|
||||
def get_loop_and_logger(self, test_type):
|
||||
self.route_data = {
|
||||
"type": "sync",
|
||||
"path": "/hello-sync-private",
|
||||
"image": "iron/hello",
|
||||
"is_public": "false"
|
||||
}
|
||||
try:
|
||||
testloop = asyncio.get_event_loop()
|
||||
except Exception:
|
||||
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||
testloop = asyncio.get_event_loop()
|
||||
|
||||
logger = log.UnifiedLogger(
|
||||
log_to_console=False,
|
||||
filename=("/tmp/laos-{}-tests-run-{}.log"
|
||||
.format(test_type, datetime.datetime.now())),
|
||||
level="DEBUG").setup_logger(__package__)
|
||||
return testloop, logger
|
@ -74,12 +74,15 @@ class RoutesV1(object):
|
||||
|
||||
class ProjectBoundLaosTestClient(test_utils.TestClient):
|
||||
|
||||
def __init__(self, app_or_server, project_id):
|
||||
def __init__(self, app_or_server, project_id, **kwargs):
|
||||
super(ProjectBoundLaosTestClient, self).__init__(app_or_server)
|
||||
self.project_id = project_id
|
||||
self.headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
if kwargs.get("headers"):
|
||||
self.headers.update(kwargs.get("headers"))
|
||||
|
||||
self.apps = AppsV1(self)
|
||||
self.routes = RoutesV1(self)
|
||||
|
118
laos/tests/common/routes.py
Normal file
118
laos/tests/common/routes.py
Normal file
@ -0,0 +1,118 @@
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 json as jsonlib
|
||||
|
||||
|
||||
class AppRoutesTestSuite(object):
|
||||
|
||||
def list_routes_from_unknown_app(self):
|
||||
json, status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.list("uknown_app")
|
||||
)
|
||||
self.assertEqual(status, 404)
|
||||
self.assertIn("error", json)
|
||||
self.assertIn("not found", json["error"]["message"])
|
||||
|
||||
def list_routes_from_existing_app(self):
|
||||
create_json, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
json, status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.list(create_json["app"]["name"])
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
self.assertEqual(status, 200)
|
||||
self.assertIn("routes", json)
|
||||
self.assertIn("message", json)
|
||||
|
||||
def show_unknown_route_from_existing_app(self):
|
||||
path = "/unknown_path"
|
||||
create_json, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
json, status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.show(
|
||||
create_json["app"]["name"], path)
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
|
||||
self.assertEqual(404, status)
|
||||
self.assertIn("error", json)
|
||||
self.assertIn("not found", json["error"]["message"])
|
||||
|
||||
def delete_unknown_route_from_existing_app(self):
|
||||
create_json, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
json, status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.delete(
|
||||
create_json["app"]["name"], "/unknown_path")
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
|
||||
self.assertEqual(404, status)
|
||||
self.assertIn("error", json)
|
||||
self.assertIn("not found", json["error"]["message"])
|
||||
|
||||
def create_and_delete_route(self):
|
||||
app, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
route, create_status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.create(
|
||||
app["app"]["name"], **self.route_data)
|
||||
)
|
||||
route_deleted, delete_status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.delete(
|
||||
app["app"]["name"], self.route_data["path"])
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(app["app"]["name"]))
|
||||
after_post = route["route"]
|
||||
for k in self.route_data:
|
||||
if k == "path":
|
||||
self.assertIn(self.route_data["path"], after_post[k])
|
||||
continue
|
||||
if k == "is_public":
|
||||
is_public = jsonlib.loads(self.route_data[k])
|
||||
self.assertEqual(is_public, after_post[k])
|
||||
continue
|
||||
self.assertEqual(self.route_data[k], after_post[k])
|
||||
self.assertEqual(200, delete_status)
|
||||
self.assertEqual(200, create_status)
|
||||
self.assertIn("message", route_deleted)
|
||||
|
||||
def double_create_route(self):
|
||||
app, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.routes.create(
|
||||
app["app"]["name"], **self.route_data)
|
||||
)
|
||||
|
||||
json, double_create_status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.create(
|
||||
app["app"]["name"], **self.route_data)
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.routes.delete(
|
||||
app["app"]["name"], self.route_data["path"])
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(app["app"]["name"]))
|
||||
|
||||
self.assertEqual(409, double_create_status)
|
||||
self.assertIn("error", json)
|
||||
self.assertIn("message", json["error"])
|
||||
self.assertIn("already exist", json["error"]["message"])
|
@ -12,13 +12,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import asyncio
|
||||
import collections
|
||||
import datetime
|
||||
import os
|
||||
import testtools
|
||||
import uuid
|
||||
import uvloop
|
||||
|
||||
from laos.api.controllers import apps
|
||||
from laos.api.controllers import routes
|
||||
@ -28,27 +25,16 @@ from laos.api.middleware import content_type
|
||||
|
||||
from laos.common.base import service
|
||||
from laos.common import config
|
||||
from laos.common import logger as log
|
||||
|
||||
|
||||
from laos.tests.common import base
|
||||
from laos.tests.common import client
|
||||
from laos.tests.fakes import functions_api
|
||||
from laos.tests.functional import client
|
||||
|
||||
|
||||
class LaosFunctionalTestsBase(testtools.TestCase):
|
||||
class LaosFunctionalTestsBase(base.LaosTestsBase, testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
try:
|
||||
self.testloop = asyncio.get_event_loop()
|
||||
except Exception:
|
||||
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||
self.testloop = asyncio.get_event_loop()
|
||||
|
||||
logger = log.UnifiedLogger(
|
||||
log_to_console=False,
|
||||
filename=("/tmp/laos-integration-tests-run-{}.log"
|
||||
.format(datetime.datetime.now())),
|
||||
level="DEBUG").setup_logger(__package__)
|
||||
self.testloop, logger = self.get_loop_and_logger("functional")
|
||||
|
||||
self.testapp = service.AbstractWebServer(
|
||||
host="localhost",
|
||||
|
@ -12,71 +12,26 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from laos.tests.common import apps as apps_suite
|
||||
from laos.tests.functional import base
|
||||
|
||||
|
||||
class TestApps(base.LaosFunctionalTestsBase):
|
||||
class TestApps(base.LaosFunctionalTestsBase, apps_suite.AppsTestSuite):
|
||||
|
||||
def test_list_apps(self):
|
||||
json, http_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.list())
|
||||
self.assertIn("message", json)
|
||||
self.assertIn("apps", json)
|
||||
self.assertEqual(200, http_status)
|
||||
super(TestApps, self).list_apps()
|
||||
|
||||
def test_get_unknown(self):
|
||||
json, http_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.show("unknown"))
|
||||
self.assertEqual(404, http_status)
|
||||
self.assertIn("error", json)
|
||||
super(TestApps, self).get_unknown()
|
||||
|
||||
def test_create_and_delete(self):
|
||||
create_json, create_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
delete_json, delete_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
|
||||
self.assertIn("message", create_json)
|
||||
self.assertIn("app", create_json)
|
||||
self.assertEqual(200, create_status)
|
||||
|
||||
self.assertIn("message", delete_json)
|
||||
self.assertEqual(200, delete_status)
|
||||
super(TestApps, self).create_and_delete()
|
||||
|
||||
def test_attempt_to_double_create(self):
|
||||
app = "testapp"
|
||||
create_json, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create(app))
|
||||
err, status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create(app))
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
self.assertEqual(409, status)
|
||||
self.assertIn("error", err)
|
||||
self.assertIn("message", err["error"])
|
||||
super(TestApps, self).attempt_to_double_create()
|
||||
|
||||
def test_attempt_delete_unknonw(self):
|
||||
json, http_status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete("unknown"))
|
||||
self.assertEqual(404, http_status)
|
||||
self.assertIn("error", json)
|
||||
super(TestApps, self).attempt_delete_unknonw()
|
||||
|
||||
def test_delete_with_routes(self):
|
||||
app_name = "testapp"
|
||||
app, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create(app_name))
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.routes.create(
|
||||
app["app"]["name"], **self.route_data)
|
||||
)
|
||||
attempt, status = self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(app["app"]["name"])
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.routes.delete(
|
||||
app["app"]["name"], self.route_data["path"])
|
||||
)
|
||||
self.assertEqual(403, status)
|
||||
self.assertIn("error", attempt)
|
||||
self.assertIn("message", attempt["error"])
|
||||
self.assertIn("has routes", attempt["error"]["message"])
|
||||
super(TestApps, self).delete_with_routes()
|
||||
|
@ -12,110 +12,31 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json as jsonlib
|
||||
|
||||
from laos.tests.common import routes as routes_suite
|
||||
from laos.tests.functional import base
|
||||
|
||||
|
||||
class TestAppRoutes(base.LaosFunctionalTestsBase):
|
||||
class TestAppRoutes(base.LaosFunctionalTestsBase,
|
||||
routes_suite.AppRoutesTestSuite):
|
||||
|
||||
def test_list_routes_from_unknown_app(self):
|
||||
json, status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.list("uknown_app")
|
||||
)
|
||||
self.assertEqual(status, 404)
|
||||
self.assertIn("error", json)
|
||||
self.assertIn("not found", json["error"]["message"])
|
||||
super(TestAppRoutes, self).list_routes_from_unknown_app()
|
||||
|
||||
def test_list_routes_from_existing_app(self):
|
||||
create_json, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
json, status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.list(create_json["app"]["name"])
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
self.assertEqual(status, 200)
|
||||
self.assertIn("routes", json)
|
||||
self.assertIn("message", json)
|
||||
super(TestAppRoutes, self).list_routes_from_existing_app()
|
||||
|
||||
def test_show_unknown_route_from_existing_app(self):
|
||||
path = "/unknown_path"
|
||||
create_json, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
json, status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.show(
|
||||
create_json["app"]["name"], path)
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
|
||||
self.assertEqual(404, status)
|
||||
self.assertIn("error", json)
|
||||
self.assertIn("not found", json["error"]["message"])
|
||||
self.assertIn(path[1:], json["error"]["message"])
|
||||
super(
|
||||
TestAppRoutes, self
|
||||
).show_unknown_route_from_existing_app()
|
||||
|
||||
def test_delete_unknown_route_from_existing_app(self):
|
||||
create_json, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
json, status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.delete(
|
||||
create_json["app"]["name"], "/unknown_path")
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(create_json["app"]["name"]))
|
||||
|
||||
self.assertEqual(404, status)
|
||||
self.assertIn("error", json)
|
||||
self.assertIn("not found", json["error"]["message"])
|
||||
super(
|
||||
TestAppRoutes, self
|
||||
).delete_unknown_route_from_existing_app()
|
||||
|
||||
def test_create_and_delete_route(self):
|
||||
app, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
route, create_status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.create(
|
||||
app["app"]["name"], **self.route_data)
|
||||
)
|
||||
route_deleted, delete_status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.delete(
|
||||
app["app"]["name"], self.route_data["path"])
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(app["app"]["name"]))
|
||||
after_post = route["route"]
|
||||
for k in self.route_data:
|
||||
if k == "path":
|
||||
self.assertIn(self.route_data["path"], after_post[k])
|
||||
continue
|
||||
if k == "is_public":
|
||||
is_public = jsonlib.loads(self.route_data[k])
|
||||
self.assertEqual(is_public, after_post[k])
|
||||
continue
|
||||
self.assertEqual(self.route_data[k], after_post[k])
|
||||
self.assertEqual(200, delete_status)
|
||||
self.assertEqual(200, create_status)
|
||||
self.assertIn("message", route_deleted)
|
||||
super(TestAppRoutes, self).create_and_delete_route()
|
||||
|
||||
def test_double_create_route(self):
|
||||
app, _ = self.testloop.run_until_complete(
|
||||
self.test_client.apps.create("testapp"))
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.routes.create(
|
||||
app["app"]["name"], **self.route_data)
|
||||
)
|
||||
|
||||
json, double_create_status = self.testloop.run_until_complete(
|
||||
self.test_client.routes.create(
|
||||
app["app"]["name"], **self.route_data)
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.routes.delete(
|
||||
app["app"]["name"], self.route_data["path"])
|
||||
)
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.apps.delete(app["app"]["name"]))
|
||||
|
||||
self.assertEqual(409, double_create_status)
|
||||
self.assertIn("error", json)
|
||||
self.assertIn("message", json["error"])
|
||||
self.assertIn("already exist", json["error"]["message"])
|
||||
super(TestAppRoutes, self).double_create_route()
|
||||
|
0
laos/tests/integration/__init__.py
Normal file
0
laos/tests/integration/__init__.py
Normal file
72
laos/tests/integration/base.py
Normal file
72
laos/tests/integration/base.py
Normal file
@ -0,0 +1,72 @@
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 os
|
||||
import testtools
|
||||
|
||||
from laos.common import config
|
||||
from laos.service import laos_api
|
||||
|
||||
from laos.tests.common import base
|
||||
from laos.tests.common import client
|
||||
|
||||
|
||||
class LaosIntegrationTestsBase(base.LaosTestsBase, testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
self.testloop, logger = self.get_loop_and_logger("integration")
|
||||
|
||||
(functions_host, functions_port,
|
||||
functions_api_protocol,
|
||||
functions_api_version, db_uri,
|
||||
keystone_endpoint, project_id, os_token) = (
|
||||
os.getenv("FUNCTIONS_HOST"), os.getenv("FUNCTIONS_PORT", 8080),
|
||||
os.getenv("FUNCTIONS_API_PROTO", "http"),
|
||||
os.getenv("FUNCTIONS_API_VERSION", "v1"), os.getenv("TEST_DB_URI"),
|
||||
os.getenv("OS_AUTH_URL"), os.getenv("OS_PROJECT_ID"),
|
||||
os.getenv("OS_TOKEN"),
|
||||
)
|
||||
|
||||
fnclient = config.FunctionsClient(
|
||||
functions_host,
|
||||
api_port=functions_port,
|
||||
api_protocol=functions_api_protocol,
|
||||
api_version=functions_api_version,
|
||||
)
|
||||
self.testloop.run_until_complete(fnclient.ping(loop=self.testloop))
|
||||
connection_pool = config.Connection(db_uri, loop=self.testloop)
|
||||
|
||||
config.Config(
|
||||
auth_url=keystone_endpoint,
|
||||
functions_client=fnclient,
|
||||
logger=logger,
|
||||
connection=connection_pool,
|
||||
event_loop=self.testloop,
|
||||
)
|
||||
|
||||
self.test_app = laos_api.API(
|
||||
loop=self.testloop, logger=logger, debug=True)
|
||||
|
||||
self.test_client = client.ProjectBoundLaosTestClient(
|
||||
self.test_app.root_service, project_id, headers={
|
||||
"X-Auth-Token": os_token
|
||||
})
|
||||
self.testloop.run_until_complete(
|
||||
self.test_client.start_server())
|
||||
super(LaosIntegrationTestsBase, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
self.testloop.run_until_complete(self.test_client.close())
|
||||
super(LaosIntegrationTestsBase, self).tearDown()
|
38
laos/tests/integration/test_apps.py
Normal file
38
laos/tests/integration/test_apps.py
Normal file
@ -0,0 +1,38 @@
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 laos.tests.common import apps as apps_suite
|
||||
from laos.tests.integration import base
|
||||
|
||||
|
||||
class TestIntegrationApps(base.LaosIntegrationTestsBase,
|
||||
apps_suite.AppsTestSuite):
|
||||
|
||||
def test_list_apps(self):
|
||||
super(TestIntegrationApps, self).list_apps()
|
||||
|
||||
def test_get_unknown(self):
|
||||
super(TestIntegrationApps, self).get_unknown()
|
||||
|
||||
def test_create_and_delete(self):
|
||||
super(TestIntegrationApps, self).create_and_delete()
|
||||
|
||||
def test_attempt_to_double_create(self):
|
||||
super(TestIntegrationApps, self).attempt_to_double_create()
|
||||
|
||||
def test_attempt_delete_unknonw(self):
|
||||
super(TestIntegrationApps, self).attempt_delete_unknonw()
|
||||
|
||||
def test_delete_with_routes(self):
|
||||
super(TestIntegrationApps, self).delete_with_routes()
|
50
laos/tests/integration/test_routes.py
Normal file
50
laos/tests/integration/test_routes.py
Normal file
@ -0,0 +1,50 @@
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 laos.tests.common import routes as routes_suite
|
||||
from laos.tests.functional import base
|
||||
|
||||
|
||||
class TestIntegrationAppRoutes(base.LaosFunctionalTestsBase,
|
||||
routes_suite.AppRoutesTestSuite):
|
||||
|
||||
def test_list_routes_from_unknown_app(self):
|
||||
super(
|
||||
TestIntegrationAppRoutes, self
|
||||
).list_routes_from_unknown_app()
|
||||
|
||||
def test_list_routes_from_existing_app(self):
|
||||
super(
|
||||
TestIntegrationAppRoutes, self
|
||||
).list_routes_from_existing_app()
|
||||
|
||||
def test_show_unknown_route_from_existing_app(self):
|
||||
super(
|
||||
TestIntegrationAppRoutes, self
|
||||
).show_unknown_route_from_existing_app()
|
||||
|
||||
def test_delete_unknown_route_from_existing_app(self):
|
||||
super(
|
||||
TestIntegrationAppRoutes, self
|
||||
).delete_unknown_route_from_existing_app()
|
||||
|
||||
def test_create_and_delete_route(self):
|
||||
super(
|
||||
TestIntegrationAppRoutes, self
|
||||
).create_and_delete_route()
|
||||
|
||||
def test_double_create_route(self):
|
||||
super(
|
||||
TestIntegrationAppRoutes, self
|
||||
).double_create_route()
|
@ -4,17 +4,17 @@ set +x
|
||||
set +e
|
||||
|
||||
function get_current_coverage {
|
||||
local prev_stat_raw=`TEST_DB_URI=${TEST_DB_URI} pytest --tb=long --capture=sys --cov=laos --capture=fd laos/tests/functional | grep TOTAL | awk '{print $4}'`
|
||||
local prev_stat_raw=`pytest --tb=long --capture=sys --cov=laos --capture=fd laos/tests/${1:-functional} | grep TOTAL | awk '{print $4}'`
|
||||
echo ${prev_stat_raw:0:2}
|
||||
}
|
||||
|
||||
function get_coverage_delta {
|
||||
local current_coverage=$(get_current_coverage)
|
||||
local current_coverage=$(get_current_coverage $1)
|
||||
local current_branch=`git branch | awk '{print $2}'`
|
||||
echo -e "Falling back to ${1} commits."
|
||||
local commits=`seq -f "^" -s '' ${1:-1}`
|
||||
echo -e "Falling back to ${2} commits."
|
||||
local commits=`seq -f "^" -s '' ${2}`
|
||||
git checkout `git rev-parse --verify HEAD${commits}` &> /dev/null
|
||||
local prev_coverage=$(get_current_coverage)
|
||||
local prev_coverage=$(get_current_coverage $1)
|
||||
echo -e "Current coverage: ${current_coverage}%"
|
||||
echo -e "Previous coverage: ${prev_coverage}%"
|
||||
if [ "${prev_coverage}" -gt "${current_coverage}" ]; then
|
||||
@ -27,4 +27,4 @@ function get_coverage_delta {
|
||||
}
|
||||
|
||||
|
||||
get_coverage_delta ${1:-1}
|
||||
get_coverage_delta ${1:-functional} ${2:-1}
|
||||
|
15
tox.ini
15
tox.ini
@ -1,7 +1,7 @@
|
||||
# Project LaOS
|
||||
|
||||
[tox]
|
||||
envlist = py35-functional,pep8
|
||||
envlist = py35-functional,py35-functional-regression,py35-integration,py35-integration-regression,pep8
|
||||
minversion = 1.6
|
||||
skipsdist = True
|
||||
|
||||
@ -9,6 +9,13 @@ skipsdist = True
|
||||
passenv =
|
||||
PYTHONASYNCIODEBUG
|
||||
TEST_DB_URI
|
||||
FUNCTIONS_HOST
|
||||
FUNCTIONS_PORT
|
||||
FUNCTIONS_API_PROTO
|
||||
FUNCTIONS_API_VERSION
|
||||
OS_AUTH_URL
|
||||
OS_PROJECT_ID
|
||||
OS_TOKEN
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
usedevelop = True
|
||||
install_command = pip install -U {opts} {packages}
|
||||
@ -26,13 +33,17 @@ commands = flake8
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:py35-integration]
|
||||
commands = pytest --tb=long --capture=sys --cov=laos --capture=fd {toxinidir}/laos/tests/integration
|
||||
|
||||
[testenv:py35-functional]
|
||||
commands = pytest --tb=long --capture=sys --cov=laos --capture=fd {toxinidir}/laos/tests/functional
|
||||
|
||||
[testenv:py35-functional-regression]
|
||||
commands = {toxinidir}/scripts/test_regression.sh {posargs}
|
||||
commands = {toxinidir}/scripts/test_regression.sh functional {posargs}
|
||||
|
||||
[testenv:py35-integration-regression]
|
||||
commands = {toxinidir}/scripts/test_regression.sh integration {posargs}
|
||||
|
||||
[testenv:docs]
|
||||
commands =
|
||||
|
Loading…
x
Reference in New Issue
Block a user