blob: 1c54d09e76927d1c73bbd2dbd705a46390f1351d [file] [log] [blame]
#
# 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 contextlib
from mock import PropertyMock, call, create_autospec, patch
from apache.aurora.admin.admin import (
get_scheduler,
increase_quota,
prune_tasks,
query,
reconcile_tasks,
set_quota
)
from apache.aurora.client.api import AuroraClientAPI
from apache.aurora.client.api.scheduler_client import SchedulerClient, SchedulerProxy
from .util import AuroraClientCommandTest
from gen.apache.aurora.api.ttypes import (
AssignedTask,
GetQuotaResult,
JobKey,
Resource,
ResourceAggregate,
Response,
ResponseCode,
ResponseDetail,
Result,
ScheduledTask,
ScheduleStatus,
ScheduleStatusResult,
TaskConfig,
TaskQuery
)
class TestPruneCommand(AuroraClientCommandTest):
@classmethod
def setup_mock_options(cls, states=None, role=None, env=None, limit=None):
mock_options = create_autospec(
spec=['states', 'role', 'environment', 'limit'],
spec_set=False,
instance=True)
mock_options.role = role
mock_options.states = states
mock_options.environment = env
mock_options.limit = limit
mock_options.bypass_leader_redirect = False
return mock_options
@classmethod
def task_query(cls, options):
query = TaskQuery(
role=options.role,
environment=options.environment,
limit=options.limit)
if options.states:
query.statuses = set(map(ScheduleStatus._NAMES_TO_VALUES.get, options.states.split(',')))
return query
def test_prune(self):
mock_options = self.setup_mock_options(
role='aurora', env='devel', limit=10, states="LOST,FINISHED")
with contextlib.nested(
patch('twitter.common.app.get_options', return_value=mock_options),
patch('apache.aurora.admin.admin.make_admin_client',
return_value=create_autospec(spec=AuroraClientAPI)),
patch('apache.aurora.admin.admin.CLUSTERS', new=self.TEST_CLUSTERS)
) as (_, mock_make_admin_client, _):
api = mock_make_admin_client.return_value
api.prune_tasks.return_value = Response(responseCode=ResponseCode.OK)
prune_tasks(['cluster'], mock_options)
api.prune_tasks.assert_called_once_with(self.task_query(mock_options))
class TestQueryCommand(AuroraClientCommandTest):
@classmethod
def setup_mock_options(cls, force=False, shards=None, states='RUNNING', listformat=None):
mock_options = create_autospec(
spec=['force', 'shards', 'states', 'listformat', 'verbosity'],
spec_set=False,
instance=True)
mock_options.force = force
mock_options.shards = shards
mock_options.states = states
mock_options.listformat = listformat or '%role%/%name%/%instanceId% %status%'
mock_options.verbosity = False
mock_options.bypass_leader_redirect = False
return mock_options
@classmethod
def create_response(cls, tasks, response_code=ResponseCode.OK):
return Response(
responseCode=response_code,
details=[ResponseDetail(message='test')],
result=Result(scheduleStatusResult=ScheduleStatusResult(tasks=tasks)))
@classmethod
def create_task(cls):
return [ScheduledTask(
assignedTask=AssignedTask(
instanceId=0,
task=TaskConfig(job=JobKey(role='role', environment='test', name='job'))
),
status=ScheduleStatus.RUNNING
)]
@classmethod
def task_query(cls):
return TaskQuery(
role='test_role',
jobName='test_job',
instanceIds=set([0]),
statuses=set([ScheduleStatus.RUNNING]))
def test_query(self):
"""Tests successful execution of the query command."""
mock_options = self.setup_mock_options(force=True, shards="0")
with contextlib.nested(
patch('twitter.common.app.get_options', return_value=mock_options),
patch('apache.aurora.admin.admin.make_admin_client',
return_value=create_autospec(spec=AuroraClientAPI)),
patch('apache.aurora.admin.admin.CLUSTERS', new=self.TEST_CLUSTERS)
) as (_, mock_make_admin_client, _):
api = mock_make_admin_client.return_value
api.query.return_value = self.create_response(self.create_task())
query([self.TEST_CLUSTER, 'test_role', 'test_job'], mock_options)
api.query.assert_called_with(self.task_query())
def test_query_fails(self):
"""Tests failed execution of the query command."""
mock_options = self.setup_mock_options(shards="0")
with contextlib.nested(
patch('twitter.common.app.get_options', return_value=mock_options),
patch('apache.aurora.admin.admin.make_admin_client',
return_value=create_autospec(spec=AuroraClientAPI)),
patch('apache.aurora.admin.admin.CLUSTERS', new=self.TEST_CLUSTERS)
) as (_, mock_make_admin_client, _):
api = mock_make_admin_client.return_value
api.query.return_value = self.create_response(self.create_task())
try:
query([self.TEST_CLUSTER, 'test_role', 'test_job'], mock_options)
except SystemExit:
pass
else:
assert 'Expected exception is not raised'
api.query.assert_called_with(self.task_query())
class TestIncreaseQuotaCommand(AuroraClientCommandTest):
@classmethod
def create_response(cls, quota, prod, non_prod, response_code=ResponseCode.OK):
return Response(
responseCode=response_code,
details=[ResponseDetail(message='test')],
result=Result(getQuotaResult=GetQuotaResult(
quota=quota, prodSharedConsumption=prod, nonProdSharedConsumption=non_prod))
)
def test_increase_quota(self):
"""Tests successful execution of the increase_quota command."""
mock_options = self.setup_mock_options()
with contextlib.nested(
patch('twitter.common.app.get_options', return_value=mock_options),
patch('apache.aurora.admin.admin.make_admin_client',
return_value=create_autospec(spec=AuroraClientAPI)),
patch('apache.aurora.admin.admin.CLUSTERS', new=self.TEST_CLUSTERS)
) as (_, mock_make_admin_client, _):
api = mock_make_admin_client.return_value
role = 'test_role'
api.get_quota.return_value = self.create_response(
ResourceAggregate(resources=frozenset([
Resource(numCpus=20.0),
Resource(ramMb=4000),
Resource(diskMb=6000)])),
ResourceAggregate(resources=frozenset([
Resource(numCpus=15.0),
Resource(ramMb=2000),
Resource(diskMb=3000)])),
ResourceAggregate(resources=frozenset([
Resource(numCpus=6.0),
Resource(ramMb=200),
Resource(diskMb=600)])),
)
api.set_quota.return_value = self.create_simple_success_response()
increase_quota([self.TEST_CLUSTER, role, '4.0', '1MB', '1MB'])
api.set_quota.assert_called_with(role, 24.0, 4001, 6001)
assert isinstance(api.set_quota.call_args[0][1], float)
assert isinstance(api.set_quota.call_args[0][2], int)
assert isinstance(api.set_quota.call_args[0][3], int)
class TestSetQuotaCommand(AuroraClientCommandTest):
@classmethod
def create_response(cls, quota, prod, non_prod, response_code=None):
response_code = ResponseCode.OK if response_code is None else response_code
resp = Response(responseCode=response_code, details=[ResponseDetail(message='test')])
resp.result = Result(getQuotaResult=GetQuotaResult(
quota=quota, prodSharedConsumption=prod, nonProdSharedConsumption=non_prod))
return resp
def test_set_quota(self):
"""Tests successful execution of the set_quota command."""
mock_options = self.setup_mock_options()
with contextlib.nested(
patch('twitter.common.app.get_options', return_value=mock_options),
patch('apache.aurora.admin.admin.make_admin_client',
return_value=create_autospec(spec=AuroraClientAPI)),
patch('apache.aurora.admin.admin.CLUSTERS', new=self.TEST_CLUSTERS)
) as (_, mock_make_admin_client, _):
api = mock_make_admin_client.return_value
role = 'test_role'
api.set_quota.return_value = self.create_simple_success_response()
set_quota([self.TEST_CLUSTER, role, '4.0', '10MB', '10MB'])
api.set_quota.assert_called_with(role, 4.0, 10, 10)
assert isinstance(api.set_quota.call_args[0][1], float)
assert isinstance(api.set_quota.call_args[0][2], int)
assert isinstance(api.set_quota.call_args[0][3], int)
class TestGetSchedulerCommand(AuroraClientCommandTest):
def test_get_scheduler(self):
"""Tests successful execution of the get_scheduler command."""
mock_options = self.setup_mock_options()
mock_proxy = create_autospec(spec=SchedulerProxy, instance=True)
mock_scheduler_client = create_autospec(spec=SchedulerClient, instance=True)
mock_raw_url = PropertyMock(return_value="url")
mock_proxy.scheduler_client.return_value = mock_scheduler_client
type(mock_scheduler_client).raw_url = mock_raw_url
with contextlib.nested(
patch('twitter.common.app.get_options', return_value=mock_options),
patch('apache.aurora.admin.admin.make_admin_client',
return_value=create_autospec(spec=AuroraClientAPI)),
patch('apache.aurora.admin.admin.CLUSTERS', new=self.TEST_CLUSTERS),
) as (_, mock_make_admin_client, _):
api = mock_make_admin_client.return_value
type(api).scheduler_proxy = PropertyMock(return_value=mock_proxy)
get_scheduler([self.TEST_CLUSTER])
mock_raw_url.assert_called_once_with()
class TestReconcileTaskCommand(AuroraClientCommandTest):
@classmethod
def setup_mock_options(cls, reconcile_type='explicit', batch_size=None):
mock_options = create_autospec(spec=['type', 'batch_size'], instance=True)
mock_options.type = reconcile_type
mock_options.batch_size = batch_size
mock_options.bypass_leader_redirect = False
return mock_options
def test_reconcile_implicit(self):
"""Tests successful execution of the reconcile_tasks command."""
mock_options = self.setup_mock_options(reconcile_type='implicit')
mock_proxy = create_autospec(spec=SchedulerProxy, instance=True)
mock_scheduler_client = create_autospec(spec=SchedulerClient)
mock_proxy.scheduler_client.return_value = mock_scheduler_client
with contextlib.nested(
patch('twitter.common.app.get_options', return_value=mock_options),
patch('apache.aurora.admin.admin.make_admin_client',
return_value=create_autospec(spec=AuroraClientAPI)),
patch('apache.aurora.admin.admin.CLUSTERS', new=self.TEST_CLUSTERS),
) as (_, mock_make_admin_client, _):
api = mock_make_admin_client.return_value
type(api).scheduler_proxy = PropertyMock(return_value=mock_proxy)
api.reconcile_implicit.return_value = self.create_simple_success_response()
reconcile_tasks([self.TEST_CLUSTER])
assert api.reconcile_implicit.mock_calls == [call()]
def test_reconcile_explicit(self):
"""Tests successful execution of the reconcile_tasks command."""
mock_options = self.setup_mock_options()
mock_proxy = create_autospec(spec=SchedulerProxy, instance=True)
mock_scheduler_client = create_autospec(spec=SchedulerClient, instance=True)
mock_proxy.scheduler_client.return_value = mock_scheduler_client
with contextlib.nested(
patch('twitter.common.app.get_options', return_value=mock_options),
patch('apache.aurora.admin.admin.make_admin_client',
return_value=create_autospec(spec=AuroraClientAPI)),
patch('apache.aurora.admin.admin.CLUSTERS', new=self.TEST_CLUSTERS),
) as (_, mock_make_admin_client, _):
api = mock_make_admin_client.return_value
type(api).scheduler_proxy = PropertyMock(return_value=mock_proxy)
api.reconcile_explicit.return_value = self.create_simple_success_response()
reconcile_tasks([self.TEST_CLUSTER])
assert api.reconcile_explicit.mock_calls == [call(None)]
def test_reconcile_explicit_batch_size(self):
"""Tests successful execution of the reconcile_tasks command."""
mock_options = self.setup_mock_options(batch_size=500)
mock_proxy = create_autospec(spec=SchedulerProxy, instance=True)
mock_scheduler_client = create_autospec(spec=SchedulerClient, instance=True)
mock_proxy.scheduler_client.return_value = mock_scheduler_client
with contextlib.nested(
patch('twitter.common.app.get_options', return_value=mock_options),
patch('apache.aurora.admin.admin.make_admin_client',
return_value=create_autospec(spec=AuroraClientAPI)),
patch('apache.aurora.admin.admin.CLUSTERS', new=self.TEST_CLUSTERS),
) as (_, mock_make_admin_client, _):
api = mock_make_admin_client.return_value
type(api).scheduler_proxy = PropertyMock(return_value=mock_proxy)
api.reconcile_explicit.return_value = self.create_simple_success_response()
reconcile_tasks([self.TEST_CLUSTER])
assert api.reconcile_explicit.mock_calls == [call(500)]