# Copyright 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import mox
import unittest
import common
import django.core.exceptions
from autotest_lib.client.common_lib.cros.network import ping_runner
from autotest_lib.frontend import setup_django_environment
from autotest_lib.frontend.server import models as server_models
from autotest_lib.site_utils import server_manager
from autotest_lib.site_utils import server_manager_utils
from autotest_lib.site_utils.lib import infra
class QueriableList(list):
"""A mock list object supports queries including filter and all.
"""
def filter(self, **kwargs):
"""Mock the filter call in django model.
"""
raise NotImplementedError()
def get(self, **kwargs):
"""Mock the get call in django model.
"""
raise NotImplementedError()
def all(self):
"""Return all items in the list.
@return: All items in the list.
"""
return [item for item in self]
class ServerManagerUnittests(mox.MoxTestBase):
"""Unittest for testing server_manager module.
"""
def setUp(self):
"""Initialize the unittest."""
super(ServerManagerUnittests, self).setUp()
# Initialize test objects.
self.DRONE_ROLE = mox.MockObject(
server_models.ServerRole,
attrs={'role': server_models.ServerRole.ROLE.DRONE})
self.SCHEDULER_ROLE = mox.MockObject(
server_models.ServerRole,
attrs={'role': server_models.ServerRole.ROLE.SCHEDULER})
self.DRONE_ATTRIBUTE = mox.MockObject(
server_models.ServerAttribute,
attrs={'attribute': 'max_processes', 'value':1})
self.PRIMARY_DRONE = mox.MockObject(
server_models.Server,
attrs={'hostname': 'primary_drone_hostname',
'status': server_models.Server.STATUS.PRIMARY,
'roles': QueriableList([self.DRONE_ROLE]),
'attributes': QueriableList([self.DRONE_ATTRIBUTE])})
self.BACKUP_DRONE = mox.MockObject(
server_models.Server,
attrs={'hostname': 'backup_drone_hostname',
'status': server_models.Server.STATUS.BACKUP,
'roles': QueriableList([self.DRONE_ROLE]),
'attributes': QueriableList([self.DRONE_ATTRIBUTE])})
self.PRIMARY_SCHEDULER = mox.MockObject(
server_models.Server,
attrs={'hostname': 'primary_scheduler_hostname',
'status': server_models.Server.STATUS.PRIMARY,
'roles': QueriableList([self.SCHEDULER_ROLE]),
'attributes': QueriableList([])})
self.BACKUP_SCHEDULER = mox.MockObject(
server_models.Server,
attrs={'hostname': 'backup_scheduler_hostname',
'status': server_models.Server.STATUS.BACKUP,
'roles': QueriableList([self.SCHEDULER_ROLE]),
'attributes': QueriableList([])})
self.mox.StubOutWithMock(server_manager_utils, 'check_server')
self.mox.StubOutWithMock(server_manager_utils, 'warn_missing_role')
self.mox.StubOutWithMock(server_manager_utils, 'use_server_db')
self.mox.StubOutWithMock(server_models.Server, 'get_role_names')
self.mox.StubOutWithMock(server_models.Server.objects, 'create')
self.mox.StubOutWithMock(server_models.Server.objects, 'filter')
self.mox.StubOutWithMock(server_models.Server.objects, 'get')
self.mox.StubOutWithMock(server_models.ServerRole, 'delete')
self.mox.StubOutWithMock(server_models.ServerRole.objects, 'create')
self.mox.StubOutWithMock(server_models.ServerRole.objects, 'filter')
self.mox.StubOutWithMock(server_models.ServerAttribute.objects,
'create')
self.mox.StubOutWithMock(server_models.ServerAttribute.objects,
'filter')
self.mox.StubOutWithMock(infra, 'execute_command')
self.mox.StubOutWithMock(ping_runner.PingRunner, 'simple_ping')
def testCreateServerSuccess(self):
"""Test create method can create a server successfully.
"""
ping_runner.PingRunner().simple_ping(self.BACKUP_DRONE.hostname
).AndReturn(True)
server_models.Server.objects.get(
hostname=self.BACKUP_DRONE.hostname
).AndRaise(django.core.exceptions.ObjectDoesNotExist)
server_models.Server.objects.create(
hostname=mox.IgnoreArg(), status=mox.IgnoreArg(),
date_created=mox.IgnoreArg(), note=mox.IgnoreArg()
).AndReturn(self.BACKUP_DRONE)
server_models.ServerRole.objects.create(
server=mox.IgnoreArg(), role=server_models.ServerRole.ROLE.DRONE
).AndReturn(self.DRONE_ROLE)
self.mox.ReplayAll()
drone = server_manager.create(hostname=self.BACKUP_DRONE.hostname,
role=server_models.ServerRole.ROLE.DRONE)
def testAddRoleToBackupSuccess(self):
"""Test manager can add a role to a backup server successfully.
Confirm that database call is made, and no action is taken, e.g.,
restart scheduler to activate a new devserver.
"""
server_models.validate(role=server_models.ServerRole.ROLE.DEVSERVER)
server_manager_utils.check_server(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(True)
server_manager_utils.use_server_db().MultipleTimes(
).AndReturn(True)
self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
self.BACKUP_DRONE.get_role_names().AndReturn(
[server_models.ServerRole.ROLE.DRONE])
server_models.ServerRole.objects.create(
server=mox.IgnoreArg(),
role=server_models.ServerRole.ROLE.DEVSERVER
).AndReturn(self.DRONE_ROLE)
self.mox.ReplayAll()
server_manager._add_role(server=self.BACKUP_DRONE,
role=server_models.ServerRole.ROLE.DEVSERVER,
action=True)
def testAddRoleToBackupFail_RoleAlreadyExists(self):
"""Test manager fails to add a role to a backup server if server already
has the given role.
"""
server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
self.BACKUP_DRONE.get_role_names().AndReturn(
[server_models.ServerRole.ROLE.DRONE])
self.mox.ReplayAll()
self.assertRaises(server_manager_utils.ServerActionError,
server_manager._add_role,
server=self.BACKUP_DRONE,
role=server_models.ServerRole.ROLE.DRONE,
action=True)
def testDeleteRoleFromBackupSuccess(self):
"""Test manager can delete a role from a backup server successfully.
Confirm that database call is made, and no action is taken, e.g.,
restart scheduler to delete an existing devserver.
"""
server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
server_manager_utils.use_server_db().MultipleTimes(
).AndReturn(True)
self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
self.BACKUP_DRONE.get_role_names().MultipleTimes().AndReturn(
[server_models.ServerRole.ROLE.DRONE])
self.mox.StubOutWithMock(self.BACKUP_DRONE.roles, 'get')
self.BACKUP_DRONE.roles.get(
role=server_models.ServerRole.ROLE.DRONE
).AndReturn(self.DRONE_ROLE)
self.mox.ReplayAll()
server_manager._delete_role(server=self.BACKUP_DRONE,
role=server_models.ServerRole.ROLE.DRONE,
action=True)
def testDeleteRoleFromBackupFail_RoleNotExist(self):
"""Test manager fails to delete a role from a backup server if the
server does not have the given role.
"""
server_models.validate(role=server_models.ServerRole.ROLE.DEVSERVER)
self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
self.BACKUP_DRONE.get_role_names().AndReturn(
[server_models.ServerRole.ROLE.DRONE])
self.mox.ReplayAll()
self.assertRaises(server_manager_utils.ServerActionError,
server_manager._delete_role, server=self.BACKUP_DRONE,
role=server_models.ServerRole.ROLE.DEVSERVER,
action=True)
def testChangeStatusSuccess_BackupToPrimary(self):
"""Test manager can change the status of a backup server to primary.
"""
server_models.validate(status=server_models.Server.STATUS.PRIMARY)
server_manager_utils.use_server_db().MultipleTimes(
).AndReturn(True)
self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
self.BACKUP_DRONE.get_role_names().MultipleTimes().AndReturn(
[server_models.ServerRole.ROLE.DRONE])
self.mox.StubOutWithMock(self.BACKUP_DRONE.roles, 'filter')
self.BACKUP_DRONE.roles.filter(
role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE
).AndReturn(None)
server_models.Server.objects.filter(
roles__role=server_models.ServerRole.ROLE.SCHEDULER,
status=server_models.Server.STATUS.PRIMARY
).AndReturn([self.PRIMARY_SCHEDULER])
infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
self.mox.ReplayAll()
server_manager._change_status(
server=self.BACKUP_DRONE,
status=server_models.Server.STATUS.PRIMARY,
action=True)
def testChangeStatusSuccess_PrimaryToBackup(self):
"""Test manager can change the status of a primary server to backup.
"""
server_models.validate(status=server_models.Server.STATUS.BACKUP)
self.mox.StubOutWithMock(self.PRIMARY_DRONE.roles, 'filter')
self.mox.StubOutWithMock(self.PRIMARY_DRONE, 'get_role_names')
self.PRIMARY_DRONE.get_role_names().MultipleTimes().AndReturn(
[server_models.ServerRole.ROLE.DRONE])
self.PRIMARY_DRONE.roles.filter(
role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE
).AndReturn(None)
server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
server_manager_utils.warn_missing_role(
server_models.ServerRole.ROLE.DRONE, self.PRIMARY_DRONE)
server_models.Server.objects.filter(
roles__role=server_models.ServerRole.ROLE.SCHEDULER,
status=server_models.Server.STATUS.PRIMARY
).AndReturn([self.PRIMARY_SCHEDULER])
infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
self.mox.ReplayAll()
server_manager._change_status(
server=self.PRIMARY_DRONE,
status=server_models.Server.STATUS.BACKUP,
action=True)
def testChangeStatusFail_StatusNoChange(self):
"""Test manager cannot change the status of a server with the same
status.
"""
server_models.validate(status=server_models.Server.STATUS.BACKUP)
self.mox.ReplayAll()
self.assertRaises(server_manager_utils.ServerActionError,
server_manager._change_status,
server=self.BACKUP_DRONE,
status=server_models.Server.STATUS.BACKUP,
action=True)
def testChangeStatusFail_UniqueInstance(self):
"""Test manager cannot change the status of a server from backup to
primary if there is already a primary exists for role doesn't allow
multiple instances.
"""
server_models.validate(status=server_models.Server.STATUS.PRIMARY)
self.mox.StubOutWithMock(self.BACKUP_SCHEDULER.roles, 'filter')
self.BACKUP_SCHEDULER.roles.filter(
role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE
).AndReturn(QueriableList([self.SCHEDULER_ROLE]))
server_models.Server.objects.filter(
roles__role=self.SCHEDULER_ROLE.role,
status=server_models.Server.STATUS.PRIMARY
).AndReturn(QueriableList([self.PRIMARY_SCHEDULER]))
self.mox.ReplayAll()
self.assertRaises(server_manager_utils.ServerActionError,
server_manager._change_status,
server=self.BACKUP_SCHEDULER,
status=server_models.Server.STATUS.PRIMARY,
action=True)
def testAddRoleToBackupFail_CheckServerFail(self):
"""Test manager fails to add a role to a backup server if check_server
is failed.
"""
server_manager_utils.check_server(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(False)
server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
self.BACKUP_DRONE.get_role_names().MultipleTimes().AndReturn(
[server_models.ServerRole.ROLE.DRONE])
self.mox.ReplayAll()
self.assertRaises(server_manager_utils.ServerActionError,
server_manager._add_role, server=self.BACKUP_DRONE,
role=server_models.ServerRole.ROLE.SCHEDULER,
action=True)
def testAddRoleToPrimarySuccess(self):
"""Test manager can add a role to a primary server successfully.
Confirm that actions needs to be taken, e.g., restart scheduler for
new drone to be added.
"""
server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
server_manager_utils.check_server(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(True)
server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
self.mox.StubOutWithMock(self.PRIMARY_SCHEDULER, 'get_role_names')
self.PRIMARY_SCHEDULER.get_role_names().AndReturn(
[server_models.ServerRole.ROLE.SCHEDULER])
server_models.ServerRole.objects.create(
server=self.PRIMARY_SCHEDULER,
role=server_models.ServerRole.ROLE.DRONE
).AndReturn(self.DRONE_ROLE)
server_models.Server.objects.filter(
roles__role=server_models.ServerRole.ROLE.SCHEDULER,
status=server_models.Server.STATUS.PRIMARY
).AndReturn([self.PRIMARY_SCHEDULER])
infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
self.mox.ReplayAll()
server_manager._add_role(self.PRIMARY_SCHEDULER,
server_models.ServerRole.ROLE.DRONE,
action=True)
def testDeleteRoleFromPrimarySuccess(self):
"""Test manager can delete a role from a primary server successfully.
Confirm that database call is made, and actions are taken, e.g.,
restart scheduler to delete an existing drone.
"""
server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
self.mox.StubOutWithMock(self.PRIMARY_DRONE, 'get_role_names')
self.PRIMARY_DRONE.get_role_names().MultipleTimes().AndReturn(
[server_models.ServerRole.ROLE.DRONE])
self.mox.StubOutWithMock(self.PRIMARY_DRONE.roles, 'get')
self.PRIMARY_DRONE.roles.get(
role=server_models.ServerRole.ROLE.DRONE
).AndReturn(self.DRONE_ROLE)
server_models.Server.objects.filter(
roles__role=server_models.ServerRole.ROLE.SCHEDULER,
status=server_models.Server.STATUS.PRIMARY
).AndReturn([self.PRIMARY_SCHEDULER])
server_manager.server_manager_utils.warn_missing_role(
server_models.ServerRole.ROLE.DRONE, self.PRIMARY_DRONE)
infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
self.mox.ReplayAll()
server_manager._delete_role(self.PRIMARY_DRONE,
server_models.ServerRole.ROLE.DRONE,
action=True)
def testDeleteRoleFromPrimarySuccess_NoAction(self):
"""Test manager can delete a role from a primary server successfully.
Confirm that database call is made, and no action is taken as action
is set to False.
"""
server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
self.mox.StubOutWithMock(self.PRIMARY_DRONE, 'get_role_names')
self.PRIMARY_DRONE.get_role_names().MultipleTimes().AndReturn(
[server_models.ServerRole.ROLE.DRONE])
self.mox.StubOutWithMock(self.PRIMARY_DRONE.roles, 'get')
self.PRIMARY_DRONE.roles.get(
role=server_models.ServerRole.ROLE.DRONE
).AndReturn(self.DRONE_ROLE)
server_manager.server_manager_utils.warn_missing_role(
server_models.ServerRole.ROLE.DRONE, self.PRIMARY_DRONE)
self.mox.ReplayAll()
server_manager._delete_role(self.PRIMARY_DRONE,
server_models.ServerRole.ROLE.DRONE,
action=False)
if '__main__':
unittest.main()