Add simple tempest testcases for resource limiting
Change-Id: I928b80e83f3101f1a8dd0564a8fad4381deb3fef Story: 2001586 Task: 20065
This commit is contained in:
parent
2dbfd7af74
commit
a8425dc7cf
@ -0,0 +1,40 @@
|
||||
# Copyright 2018 AWCloud Software Co., Ltd
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
# Codes are from https://www.craig-wood.com/nick/articles/pi-machin/
|
||||
|
||||
def arctan_euler(x, one):
|
||||
x_squared = x * x
|
||||
x_squared_plus_1 = x_squared + 1
|
||||
term = (x * one) // x_squared_plus_1
|
||||
total = term
|
||||
two_n = 2
|
||||
while True:
|
||||
divisor = (two_n + 1) * x_squared_plus_1
|
||||
term *= two_n
|
||||
term = term // divisor
|
||||
if term == 0:
|
||||
break
|
||||
total += term
|
||||
two_n += 2
|
||||
return total
|
||||
|
||||
|
||||
def pi_machin(one):
|
||||
return 4 * (4 * arctan_euler(5, one) - arctan_euler(239, one))
|
||||
|
||||
|
||||
def main(digit=50000, *args, **kwargs):
|
||||
return str(pi_machin(10**digit))[:15]
|
@ -0,0 +1,23 @@
|
||||
# Copyright 2018 AWCloud Software Co., Ltd
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
S = 20 * 1024 * 1024 # 20M
|
||||
|
||||
|
||||
def main(*args, **kwargs):
|
||||
L = []
|
||||
for i in 'abcd':
|
||||
L.append(i * S)
|
||||
return len(L)
|
@ -85,7 +85,7 @@ class QinlingClient(client_base.QinlingClientBase):
|
||||
return resp, json.loads(resp.text)
|
||||
|
||||
def update_function(self, function_id, package_data=None, code=None,
|
||||
entry=None):
|
||||
entry=None, **kwargs):
|
||||
headers = {'X-Auth-Token': self.auth_provider.get_token()}
|
||||
|
||||
req_body = {}
|
||||
@ -93,6 +93,7 @@ class QinlingClient(client_base.QinlingClientBase):
|
||||
req_body['code'] = json.dumps(code)
|
||||
if entry:
|
||||
req_body['entry'] = entry
|
||||
req_body.update(kwargs)
|
||||
|
||||
req_kwargs = {
|
||||
'headers': headers,
|
||||
|
@ -12,6 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from concurrent import futures
|
||||
import json
|
||||
|
||||
import futurist
|
||||
from oslo_serialization import jsonutils
|
||||
@ -20,6 +21,9 @@ from tempest.lib import exceptions
|
||||
|
||||
from qinling_tempest_plugin.tests import base
|
||||
|
||||
INVOKE_ERROR = "Function execution failed because of too much resource " \
|
||||
"consumption"
|
||||
|
||||
|
||||
class ExecutionsTest(base.BaseQinlingTest):
|
||||
name_prefix = 'ExecutionsTest'
|
||||
@ -273,3 +277,121 @@ class ExecutionsTest(base.BaseQinlingTest):
|
||||
execution_id, ignore_notfound=True)
|
||||
self.assertEqual('success', body['status'])
|
||||
self.assertIn('Qinling', jsonutils.loads(body['result'])['output'])
|
||||
|
||||
@decorators.idempotent_id('2b5f0787-b82d-4fc4-af76-cf86d389a76b')
|
||||
def test_python_execution_memory_limit_non_image(self):
|
||||
"""In this case, the following steps are taken:
|
||||
|
||||
1. Create a function that requires ~80M memory to run.
|
||||
2. Create an execution using the function.
|
||||
3. Verify that the execution is killed by the OOM-killer
|
||||
because the function memory limit is only 32M(default).
|
||||
4. Increase the function memory limit to 96M.
|
||||
5. Create another execution.
|
||||
6. Check the execution finished normally.
|
||||
"""
|
||||
|
||||
# Create function
|
||||
package = self.create_package(
|
||||
name='python/test_python_memory_limit.py'
|
||||
)
|
||||
function_id = self.create_function(package_path=package)
|
||||
|
||||
# Invoke function
|
||||
resp, body = self.client.create_execution(function_id)
|
||||
|
||||
execution_id = body['id']
|
||||
self.addCleanup(self.client.delete_resource, 'executions',
|
||||
execution_id, ignore_notfound=True)
|
||||
|
||||
# Check the process is killed
|
||||
self.assertEqual(201, resp.status)
|
||||
result = json.loads(body['result'])
|
||||
output = result.get('output')
|
||||
self.assertEqual(INVOKE_ERROR, output)
|
||||
|
||||
# Increase the memory limit to 100663296(96M).
|
||||
resp, body = self.client.update_function(
|
||||
function_id, memory_size=100663296)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
# Invoke the function again
|
||||
resp, body = self.client.create_execution(function_id)
|
||||
|
||||
execution_id = body['id']
|
||||
self.addCleanup(self.client.delete_resource, 'executions',
|
||||
execution_id, ignore_notfound=True)
|
||||
|
||||
# Check the process exited normally
|
||||
self.assertEqual(201, resp.status)
|
||||
result = json.loads(body['result'])
|
||||
output = result.get('output')
|
||||
# The function returns the length of a list containing 4 long strings.
|
||||
self.assertEqual(4, output)
|
||||
|
||||
@decorators.idempotent_id('ed714f98-29fe-4e8d-b6ee-9730f92bddea')
|
||||
def test_python_execution_cpu_limit_non_image(self):
|
||||
"""In this case, the following steps are taken:
|
||||
|
||||
1. Create a function that takes some time to finish (calculating the
|
||||
first 50000 digits of PI)
|
||||
2. Create an execution using the function.
|
||||
3. Store the duration of the first execution.
|
||||
4. Increase the function cpu limit from 100(default) to 200 millicpu.
|
||||
5. Create another execution.
|
||||
6. Check whether the duration of the first execution is approximately
|
||||
the double of the duration of the second one as its cpu resource is
|
||||
half of the second run.
|
||||
"""
|
||||
|
||||
# Create function
|
||||
package = self.create_package(
|
||||
name='python/test_python_cpu_limit.py'
|
||||
)
|
||||
function_id = self.create_function(package_path=package)
|
||||
|
||||
# Invoke function
|
||||
resp, body = self.client.create_execution(function_id)
|
||||
|
||||
execution_id = body['id']
|
||||
self.addCleanup(self.client.delete_resource, 'executions',
|
||||
execution_id, ignore_notfound=True)
|
||||
|
||||
# Record the duration, check whether the result is correct.
|
||||
self.assertEqual(201, resp.status)
|
||||
result = json.loads(body['result'])
|
||||
output = result.get('output')
|
||||
# Only the first 15 digits are returned.
|
||||
self.assertEqual('314159265358979', output)
|
||||
first_duration = result.get('duration', 0)
|
||||
|
||||
# Increase the cpu limit
|
||||
resp, body = self.client.update_function(function_id, cpu=200)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
# Invoke the function again
|
||||
resp, body = self.client.create_execution(function_id)
|
||||
|
||||
execution_id = body['id']
|
||||
self.addCleanup(self.client.delete_resource, 'executions',
|
||||
execution_id, ignore_notfound=True)
|
||||
|
||||
# Record the second duration, check whether the result is correct.
|
||||
self.assertEqual(201, resp.status)
|
||||
result = json.loads(body['result'])
|
||||
output = result.get('output')
|
||||
# Only the first 15 digits are returned.
|
||||
self.assertEqual('314159265358979', output)
|
||||
second_duration = result.get('duration', 0)
|
||||
|
||||
# Check whether the duration of the first execution is approximately
|
||||
# the double (1.8x ~ 2.2x) of the duration of the second one.
|
||||
# NOTE(huntxu): on my testbed, the result is quite near 2x. However
|
||||
# it may vary in different environments, so we give a wider range
|
||||
# here.
|
||||
self.assertNotEqual(0, first_duration)
|
||||
self.assertNotEqual(0, second_duration)
|
||||
upper = second_duration * 2.2
|
||||
lower = second_duration * 1.8
|
||||
self.assertGreaterEqual(upper, first_duration)
|
||||
self.assertLessEqual(lower, first_duration)
|
||||
|
Loading…
Reference in New Issue
Block a user