Home | History | Annotate | Download | only in site_utils
      1 # Copyright 2014 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import mox
      6 import unittest
      7 
      8 import common
      9 
     10 import django.core.exceptions
     11 from autotest_lib.client.common_lib.cros.network import ping_runner
     12 from autotest_lib.frontend import setup_django_environment
     13 from autotest_lib.frontend.server import models as server_models
     14 from autotest_lib.site_utils import server_manager
     15 from autotest_lib.site_utils import server_manager_utils
     16 from autotest_lib.site_utils.lib import infra
     17 
     18 
     19 class QueriableList(list):
     20     """A mock list object supports queries including filter and all.
     21     """
     22 
     23     def filter(self, **kwargs):
     24         """Mock the filter call in django model.
     25         """
     26         raise NotImplementedError()
     27 
     28 
     29     def get(self, **kwargs):
     30         """Mock the get call in django model.
     31         """
     32         raise NotImplementedError()
     33 
     34 
     35     def all(self):
     36         """Return all items in the list.
     37 
     38         @return: All items in the list.
     39         """
     40         return [item for item in self]
     41 
     42 
     43 class ServerManagerUnittests(mox.MoxTestBase):
     44     """Unittest for testing server_manager module.
     45     """
     46 
     47     def setUp(self):
     48         """Initialize the unittest."""
     49         super(ServerManagerUnittests, self).setUp()
     50 
     51         # Initialize test objects.
     52         self.DRONE_ROLE = mox.MockObject(
     53                 server_models.ServerRole,
     54                 attrs={'role': server_models.ServerRole.ROLE.DRONE})
     55         self.SCHEDULER_ROLE = mox.MockObject(
     56                 server_models.ServerRole,
     57                 attrs={'role': server_models.ServerRole.ROLE.SCHEDULER})
     58         self.DRONE_ATTRIBUTE = mox.MockObject(
     59                 server_models.ServerAttribute,
     60                 attrs={'attribute': 'max_processes', 'value':1})
     61         self.PRIMARY_DRONE = mox.MockObject(
     62                 server_models.Server,
     63                 attrs={'hostname': 'primary_drone_hostname',
     64                        'status': server_models.Server.STATUS.PRIMARY,
     65                        'roles': QueriableList([self.DRONE_ROLE]),
     66                        'attributes': QueriableList([self.DRONE_ATTRIBUTE])})
     67         self.BACKUP_DRONE = mox.MockObject(
     68                 server_models.Server,
     69                 attrs={'hostname': 'backup_drone_hostname',
     70                        'status': server_models.Server.STATUS.BACKUP,
     71                        'roles': QueriableList([self.DRONE_ROLE]),
     72                        'attributes': QueriableList([self.DRONE_ATTRIBUTE])})
     73         self.PRIMARY_SCHEDULER = mox.MockObject(
     74                 server_models.Server,
     75                 attrs={'hostname': 'primary_scheduler_hostname',
     76                        'status': server_models.Server.STATUS.PRIMARY,
     77                        'roles': QueriableList([self.SCHEDULER_ROLE]),
     78                        'attributes': QueriableList([])})
     79         self.BACKUP_SCHEDULER = mox.MockObject(
     80                 server_models.Server,
     81                 attrs={'hostname': 'backup_scheduler_hostname',
     82                        'status': server_models.Server.STATUS.BACKUP,
     83                        'roles': QueriableList([self.SCHEDULER_ROLE]),
     84                        'attributes': QueriableList([])})
     85 
     86         self.mox.StubOutWithMock(server_manager_utils, 'check_server')
     87         self.mox.StubOutWithMock(server_manager_utils, 'warn_missing_role')
     88         self.mox.StubOutWithMock(server_manager_utils, 'use_server_db')
     89         self.mox.StubOutWithMock(server_models.Server, 'get_role_names')
     90         self.mox.StubOutWithMock(server_models.Server.objects, 'create')
     91         self.mox.StubOutWithMock(server_models.Server.objects, 'filter')
     92         self.mox.StubOutWithMock(server_models.Server.objects, 'get')
     93         self.mox.StubOutWithMock(server_models.ServerRole, 'delete')
     94         self.mox.StubOutWithMock(server_models.ServerRole.objects, 'create')
     95         self.mox.StubOutWithMock(server_models.ServerRole.objects, 'filter')
     96         self.mox.StubOutWithMock(server_models.ServerAttribute.objects,
     97                                  'create')
     98         self.mox.StubOutWithMock(server_models.ServerAttribute.objects,
     99                                  'filter')
    100         self.mox.StubOutWithMock(infra, 'execute_command')
    101         self.mox.StubOutWithMock(ping_runner.PingRunner, 'simple_ping')
    102 
    103 
    104     def testCreateServerSuccess(self):
    105         """Test create method can create a server successfully.
    106         """
    107         ping_runner.PingRunner().simple_ping(self.BACKUP_DRONE.hostname
    108                                              ).AndReturn(True)
    109         server_models.Server.objects.get(
    110                 hostname=self.BACKUP_DRONE.hostname
    111                 ).AndRaise(django.core.exceptions.ObjectDoesNotExist)
    112         server_models.Server.objects.create(
    113                 hostname=mox.IgnoreArg(), status=mox.IgnoreArg(),
    114                 date_created=mox.IgnoreArg(), note=mox.IgnoreArg()
    115                 ).AndReturn(self.BACKUP_DRONE)
    116         server_models.ServerRole.objects.create(
    117                 server=mox.IgnoreArg(), role=server_models.ServerRole.ROLE.DRONE
    118                 ).AndReturn(self.DRONE_ROLE)
    119         self.mox.ReplayAll()
    120         drone = server_manager.create(hostname=self.BACKUP_DRONE.hostname,
    121                                       role=server_models.ServerRole.ROLE.DRONE)
    122 
    123 
    124     def testAddRoleToBackupSuccess(self):
    125         """Test manager can add a role to a backup server successfully.
    126 
    127         Confirm that database call is made, and no action is taken, e.g.,
    128         restart scheduler to activate a new devserver.
    129         """
    130         server_models.validate(role=server_models.ServerRole.ROLE.DEVSERVER)
    131         server_manager_utils.check_server(mox.IgnoreArg(),
    132                                           mox.IgnoreArg()).AndReturn(True)
    133         server_manager_utils.use_server_db().MultipleTimes(
    134                 ).AndReturn(True)
    135         self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
    136         self.BACKUP_DRONE.get_role_names().AndReturn(
    137                 [server_models.ServerRole.ROLE.DRONE])
    138         server_models.ServerRole.objects.create(
    139                 server=mox.IgnoreArg(),
    140                 role=server_models.ServerRole.ROLE.DEVSERVER
    141                 ).AndReturn(self.DRONE_ROLE)
    142         self.mox.ReplayAll()
    143         server_manager._add_role(server=self.BACKUP_DRONE,
    144                                  role=server_models.ServerRole.ROLE.DEVSERVER,
    145                                  action=True)
    146 
    147 
    148     def testAddRoleToBackupFail_RoleAlreadyExists(self):
    149         """Test manager fails to add a role to a backup server if server already
    150         has the given role.
    151         """
    152         server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
    153         self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
    154         self.BACKUP_DRONE.get_role_names().AndReturn(
    155                 [server_models.ServerRole.ROLE.DRONE])
    156         self.mox.ReplayAll()
    157         self.assertRaises(server_manager_utils.ServerActionError,
    158                           server_manager._add_role,
    159                           server=self.BACKUP_DRONE,
    160                           role=server_models.ServerRole.ROLE.DRONE,
    161                           action=True)
    162 
    163 
    164     def testDeleteRoleFromBackupSuccess(self):
    165         """Test manager can delete a role from a backup server successfully.
    166 
    167         Confirm that database call is made, and no action is taken, e.g.,
    168         restart scheduler to delete an existing devserver.
    169         """
    170         server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
    171         server_manager_utils.use_server_db().MultipleTimes(
    172                 ).AndReturn(True)
    173         self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
    174         self.BACKUP_DRONE.get_role_names().MultipleTimes().AndReturn(
    175                 [server_models.ServerRole.ROLE.DRONE])
    176         self.mox.StubOutWithMock(self.BACKUP_DRONE.roles, 'get')
    177         self.BACKUP_DRONE.roles.get(
    178                 role=server_models.ServerRole.ROLE.DRONE
    179                 ).AndReturn(self.DRONE_ROLE)
    180         self.mox.ReplayAll()
    181         server_manager._delete_role(server=self.BACKUP_DRONE,
    182                                     role=server_models.ServerRole.ROLE.DRONE,
    183                                     action=True)
    184 
    185 
    186     def testDeleteRoleFromBackupFail_RoleNotExist(self):
    187         """Test manager fails to delete a role from a backup server if the
    188         server does not have the given role.
    189         """
    190         server_models.validate(role=server_models.ServerRole.ROLE.DEVSERVER)
    191         self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
    192         self.BACKUP_DRONE.get_role_names().AndReturn(
    193                 [server_models.ServerRole.ROLE.DRONE])
    194         self.mox.ReplayAll()
    195         self.assertRaises(server_manager_utils.ServerActionError,
    196                           server_manager._delete_role, server=self.BACKUP_DRONE,
    197                           role=server_models.ServerRole.ROLE.DEVSERVER,
    198                           action=True)
    199 
    200 
    201     def testChangeStatusSuccess_BackupToPrimary(self):
    202         """Test manager can change the status of a backup server to primary.
    203         """
    204         server_models.validate(status=server_models.Server.STATUS.PRIMARY)
    205         server_manager_utils.use_server_db().MultipleTimes(
    206                 ).AndReturn(True)
    207         self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
    208         self.BACKUP_DRONE.get_role_names().MultipleTimes().AndReturn(
    209                 [server_models.ServerRole.ROLE.DRONE])
    210         self.mox.StubOutWithMock(self.BACKUP_DRONE.roles, 'filter')
    211         self.BACKUP_DRONE.roles.filter(
    212                 role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE
    213                 ).AndReturn(None)
    214         server_models.Server.objects.filter(
    215                 roles__role=server_models.ServerRole.ROLE.SCHEDULER,
    216                 status=server_models.Server.STATUS.PRIMARY
    217                 ).AndReturn([self.PRIMARY_SCHEDULER])
    218         infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
    219         self.mox.ReplayAll()
    220         server_manager._change_status(
    221                 server=self.BACKUP_DRONE,
    222                 status=server_models.Server.STATUS.PRIMARY,
    223                 action=True)
    224 
    225 
    226     def testChangeStatusSuccess_PrimaryToBackup(self):
    227         """Test manager can change the status of a primary server to backup.
    228         """
    229         server_models.validate(status=server_models.Server.STATUS.BACKUP)
    230         self.mox.StubOutWithMock(self.PRIMARY_DRONE.roles, 'filter')
    231         self.mox.StubOutWithMock(self.PRIMARY_DRONE, 'get_role_names')
    232         self.PRIMARY_DRONE.get_role_names().MultipleTimes().AndReturn(
    233                 [server_models.ServerRole.ROLE.DRONE])
    234         self.PRIMARY_DRONE.roles.filter(
    235                 role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE
    236                 ).AndReturn(None)
    237         server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
    238         server_manager_utils.warn_missing_role(
    239                 server_models.ServerRole.ROLE.DRONE, self.PRIMARY_DRONE)
    240         server_models.Server.objects.filter(
    241                 roles__role=server_models.ServerRole.ROLE.SCHEDULER,
    242                 status=server_models.Server.STATUS.PRIMARY
    243                 ).AndReturn([self.PRIMARY_SCHEDULER])
    244         infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
    245         self.mox.ReplayAll()
    246         server_manager._change_status(
    247                 server=self.PRIMARY_DRONE,
    248                 status=server_models.Server.STATUS.BACKUP,
    249                 action=True)
    250 
    251 
    252     def testChangeStatusFail_StatusNoChange(self):
    253         """Test manager cannot change the status of a server with the same
    254         status.
    255         """
    256         server_models.validate(status=server_models.Server.STATUS.BACKUP)
    257         self.mox.ReplayAll()
    258         self.assertRaises(server_manager_utils.ServerActionError,
    259                           server_manager._change_status,
    260                           server=self.BACKUP_DRONE,
    261                           status=server_models.Server.STATUS.BACKUP,
    262                           action=True)
    263 
    264 
    265     def testChangeStatusFail_UniqueInstance(self):
    266         """Test manager cannot change the status of a server from backup to
    267         primary if there is already a primary exists for role doesn't allow
    268         multiple instances.
    269         """
    270         server_models.validate(status=server_models.Server.STATUS.PRIMARY)
    271         self.mox.StubOutWithMock(self.BACKUP_SCHEDULER.roles, 'filter')
    272         self.BACKUP_SCHEDULER.roles.filter(
    273                 role__in=server_models.ServerRole.ROLES_REQUIRE_UNIQUE_INSTANCE
    274                 ).AndReturn(QueriableList([self.SCHEDULER_ROLE]))
    275         server_models.Server.objects.filter(
    276                 roles__role=self.SCHEDULER_ROLE.role,
    277                 status=server_models.Server.STATUS.PRIMARY
    278                 ).AndReturn(QueriableList([self.PRIMARY_SCHEDULER]))
    279         self.mox.ReplayAll()
    280         self.assertRaises(server_manager_utils.ServerActionError,
    281                           server_manager._change_status,
    282                           server=self.BACKUP_SCHEDULER,
    283                           status=server_models.Server.STATUS.PRIMARY,
    284                           action=True)
    285 
    286 
    287     def testAddRoleToBackupFail_CheckServerFail(self):
    288         """Test manager fails to add a role to a backup server if check_server
    289         is failed.
    290         """
    291         server_manager_utils.check_server(mox.IgnoreArg(),
    292                                           mox.IgnoreArg()).AndReturn(False)
    293         server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
    294         self.mox.StubOutWithMock(self.BACKUP_DRONE, 'get_role_names')
    295         self.BACKUP_DRONE.get_role_names().MultipleTimes().AndReturn(
    296                 [server_models.ServerRole.ROLE.DRONE])
    297         self.mox.ReplayAll()
    298         self.assertRaises(server_manager_utils.ServerActionError,
    299                           server_manager._add_role, server=self.BACKUP_DRONE,
    300                           role=server_models.ServerRole.ROLE.SCHEDULER,
    301                           action=True)
    302 
    303 
    304     def testAddRoleToPrimarySuccess(self):
    305         """Test manager can add a role to a primary server successfully.
    306 
    307         Confirm that actions needs to be taken, e.g., restart scheduler for
    308         new drone to be added.
    309         """
    310         server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
    311         server_manager_utils.check_server(mox.IgnoreArg(),
    312                                           mox.IgnoreArg()).AndReturn(True)
    313         server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
    314         self.mox.StubOutWithMock(self.PRIMARY_SCHEDULER, 'get_role_names')
    315         self.PRIMARY_SCHEDULER.get_role_names().AndReturn(
    316                 [server_models.ServerRole.ROLE.SCHEDULER])
    317         server_models.ServerRole.objects.create(
    318                 server=self.PRIMARY_SCHEDULER,
    319                 role=server_models.ServerRole.ROLE.DRONE
    320                 ).AndReturn(self.DRONE_ROLE)
    321         server_models.Server.objects.filter(
    322                 roles__role=server_models.ServerRole.ROLE.SCHEDULER,
    323                 status=server_models.Server.STATUS.PRIMARY
    324                 ).AndReturn([self.PRIMARY_SCHEDULER])
    325         infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
    326         self.mox.ReplayAll()
    327         server_manager._add_role(self.PRIMARY_SCHEDULER,
    328                                  server_models.ServerRole.ROLE.DRONE,
    329                                  action=True)
    330 
    331 
    332     def testDeleteRoleFromPrimarySuccess(self):
    333         """Test manager can delete a role from a primary server successfully.
    334 
    335         Confirm that database call is made, and actions are taken, e.g.,
    336         restart scheduler to delete an existing drone.
    337         """
    338         server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
    339         server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
    340         self.mox.StubOutWithMock(self.PRIMARY_DRONE, 'get_role_names')
    341         self.PRIMARY_DRONE.get_role_names().MultipleTimes().AndReturn(
    342                 [server_models.ServerRole.ROLE.DRONE])
    343 
    344         self.mox.StubOutWithMock(self.PRIMARY_DRONE.roles, 'get')
    345         self.PRIMARY_DRONE.roles.get(
    346                 role=server_models.ServerRole.ROLE.DRONE
    347                 ).AndReturn(self.DRONE_ROLE)
    348 
    349         server_models.Server.objects.filter(
    350                 roles__role=server_models.ServerRole.ROLE.SCHEDULER,
    351                 status=server_models.Server.STATUS.PRIMARY
    352                 ).AndReturn([self.PRIMARY_SCHEDULER])
    353         server_manager.server_manager_utils.warn_missing_role(
    354                 server_models.ServerRole.ROLE.DRONE, self.PRIMARY_DRONE)
    355         infra.execute_command(mox.IgnoreArg(), mox.IgnoreArg())
    356         self.mox.ReplayAll()
    357         server_manager._delete_role(self.PRIMARY_DRONE,
    358                                     server_models.ServerRole.ROLE.DRONE,
    359                                     action=True)
    360 
    361 
    362     def testDeleteRoleFromPrimarySuccess_NoAction(self):
    363         """Test manager can delete a role from a primary server successfully.
    364 
    365         Confirm that database call is made, and no action is taken as action
    366         is set to False.
    367         """
    368         server_manager_utils.use_server_db().MultipleTimes().AndReturn(True)
    369         server_models.validate(role=server_models.ServerRole.ROLE.DRONE)
    370         self.mox.StubOutWithMock(self.PRIMARY_DRONE, 'get_role_names')
    371         self.PRIMARY_DRONE.get_role_names().MultipleTimes().AndReturn(
    372                 [server_models.ServerRole.ROLE.DRONE])
    373 
    374         self.mox.StubOutWithMock(self.PRIMARY_DRONE.roles, 'get')
    375         self.PRIMARY_DRONE.roles.get(
    376                 role=server_models.ServerRole.ROLE.DRONE
    377                 ).AndReturn(self.DRONE_ROLE)
    378 
    379         server_manager.server_manager_utils.warn_missing_role(
    380                 server_models.ServerRole.ROLE.DRONE, self.PRIMARY_DRONE)
    381         self.mox.ReplayAll()
    382         server_manager._delete_role(self.PRIMARY_DRONE,
    383                                     server_models.ServerRole.ROLE.DRONE,
    384                                     action=False)
    385 
    386 
    387 if '__main__':
    388     unittest.main()
    389