'Test group can be updated.'

@ddt.data((False, fake.GROUP_TYPE_ID), (True, fake.GROUP_TYPE_ID), (True, fake.GROUP_TYPE2_ID))
@ddt.unpack
@mock.patch('cinder.volume.group_types.get_default_cgsnapshot_type', return_value={'id': fake.GROUP_TYPE2_ID})
@mock.patch.object(GROUP_QUOTAS, 'reserve', return_value=['RESERVATION'])
@mock.patch.object(GROUP_QUOTAS, 'commit')
@mock.patch.object(GROUP_QUOTAS, 'rollback')
@mock.patch.object(driver.VolumeDriver, 'create_group', return_value={'status': 'available'})
@mock.patch('cinder.volume.manager.VolumeManager._update_group_generic')
@mock.patch.object(driver.VolumeDriver, 'update_consistencygroup')
@mock.patch.object(driver.VolumeDriver, 'update_group')
def test_update_group(self, raise_error, type_id, fake_update_grp, fake_update_cg, fake_generic_update, fake_create_grp, fake_rollback, fake_commit, fake_reserve, fake_get_type):

    group = tests_utils.create_group(self.context, availability_zone=CONF.storage_availability_zone, volume_type_ids=[fake.VOLUME_TYPE_ID], group_type_id=type_id, host=CONF.host)
    self.volume.create_group(self.context, group)
    volume = tests_utils.create_volume(self.context, group_id=group.id, volume_type_id=fake.VOLUME_TYPE_ID, status='available', host=group.host)
    self.volume.create_volume(self.context, volume)
    volume2 = tests_utils.create_volume(self.context, group_id=None, volume_type_id=fake.VOLUME_TYPE_ID, status='available', host=group.host)
    self.volume.create_volume(self.context, volume)
    driver_result = ({'status': fields.GroupStatus.AVAILABLE}, [{'id': volume2.id, 'status': 'available'}], [{'id': volume.id, 'status': 'available'}])
    if raise_error:
        fake_update_grp.side_effect = [NotImplementedError]
        fake_update_cg.return_value = driver_result
        fake_generic_update.return_value = driver_result
    else:
        fake_update_grp.return_value = driver_result
    with mock.patch.object(self.volume, '_convert_group_to_cg', mock.Mock()) as mock_convert:
        with mock.patch.object(self.volume, '_remove_consistencygroup_id_from_volumes', mock.Mock()):
            mock_convert.return_value = ('fake_cg', [volume])
            self.volume.update_group(self.context, group, add_volumes=volume2.id, remove_volumes=volume.id)
    if raise_error:
        if (type_id == fake.GROUP_TYPE2_ID):
            fake_update_cg.assert_called_once_with(self.context, 'fake_cg', add_volumes=mock.ANY, remove_volumes=[volume])
        else:
            fake_generic_update.assert_called_once_with(self.context, group, add_volumes=mock.ANY, remove_volumes=mock.ANY)
    grp = objects.Group.get_by_id(self.context, group.id)
    expected = {'status': fields.GroupStatus.AVAILABLE, 'name': 'test_group', 'availability_zone': 'nova', 'tenant_id': self.context.project_id, 'created_at': mock.ANY, 'user_id': fake.USER_ID, 'group_id': group.id, 'group_type': type_id}
    self.assertEqual(fields.GroupStatus.AVAILABLE, grp.status)
    self.assertEqual(10, len(self.notifier.notifications), self.notifier.notifications)
    msg = self.notifier.notifications[6]
    self.assertEqual('group.update.start', msg['event_type'])
    self.assertDictEqual(expected, msg['payload'])
    msg = self.notifier.notifications[8]
    self.assertEqual('group.update.end', msg['event_type'])
    self.assertDictEqual(expected, msg['payload'])
    grpvolumes = db.volume_get_all_by_generic_group(self.context, group.id)
    grpvol_ids = [grpvol['id'] for grpvol in grpvolumes]
    self.assertNotIn(volume.id, grpvol_ids)
    self.assertIn(volume2.id, grpvol_ids)
    volume3 = tests_utils.create_volume(self.context, group_id=None, host=group.host, volume_type_id=fake.VOLUME_TYPE_ID, status='wrong-status')
    volume_id3 = volume3['id']
    volume_get_orig = self.volume.db.volume_get
    self.volume.db.volume_get = mock.Mock(return_value={'status': 'wrong_status', 'id': volume_id3})
    self.assertRaises(exception.InvalidVolume, self.volume.update_group, self.context, group, add_volumes=volume_id3, remove_volumes=None)
    self.volume.db.volume_get.reset_mock()
    self.volume.db.volume_get = volume_get_orig
