2024-01-28 02:10:08 +01:00
# -*- coding: utf-8 -*-
#
2024-01-30 03:49:36 +01:00
# Copyright (c) 2024 Virtual Cable S.L.U.
2024-01-28 02:10:08 +01:00
# All rights reserved.
#
2024-01-30 03:49:36 +01:00
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2024-01-28 02:10:08 +01:00
"""
Author : Adolfo Gómez , dkmaster at dkmon dot com
"""
import pickle
import typing
2024-01-30 03:49:36 +01:00
# We use storage, so we need transactional tests
from tests . utils . test import UDSTransactionTestCase
2024-01-28 02:10:08 +01:00
from uds . core . environment import Environment
2024-01-30 03:49:36 +01:00
from uds . services . Xen . deployment import Operation as Operation , XenLinkedDeployment as Deployment
2024-01-28 02:10:08 +01:00
# if not data.startswith(b'v'):
# return super().unmarshal(data)
# vals = data.split(b'\1')
# logger.debug('Values: %s', vals)
# if vals[0] == b'v1':
# self._name = vals[1].decode('utf8')
# self._ip = vals[2].decode('utf8')
# self._mac = vals[3].decode('utf8')
# self._vmid = vals[4].decode('utf8')
# self._reason = vals[5].decode('utf8')
# self._queue = pickle.loads(vals[6]) # nosec: not insecure, we are loading our own data
# self._task = vals[7].decode('utf8')
# self.flag_for_upgrade() # Force upgrade
2024-01-30 03:49:36 +01:00
EXPECTED_FIELDS : typing . Final [ set [ str ] ] = {
' _name ' ,
' _ip ' ,
' _mac ' ,
' _vmid ' ,
' _reason ' ,
' _queue ' ,
' _task ' ,
}
TEST_QUEUE : typing . Final [ list [ Operation ] ] = [
Operation . CREATE ,
Operation . REMOVE ,
Operation . RETRY ,
2024-01-28 02:10:08 +01:00
]
2024-01-30 03:49:36 +01:00
SERIALIZED_DEPLOYMENT_DATA : typing . Final [ typing . Mapping [ str , bytes ] ] = {
2024-03-02 05:07:28 +01:00
' v1 ' : b ' v1 \x01 name \x01 ip \x01 mac \x01 vmid \x01 reason \x01 ' + pickle . dumps ( TEST_QUEUE , protocol = 0 ) + b ' \x01 task ' ,
2024-01-28 02:10:08 +01:00
}
2024-01-30 03:49:36 +01:00
LAST_VERSION : typing . Final [ str ] = sorted ( SERIALIZED_DEPLOYMENT_DATA . keys ( ) , reverse = True ) [ 0 ]
2024-01-28 02:10:08 +01:00
2024-01-30 03:49:36 +01:00
class XenDeploymentSerializationTest ( UDSTransactionTestCase ) :
def check ( self , version : str , instance : Deployment ) - > None :
2024-01-28 02:10:08 +01:00
self . assertEqual ( instance . _name , ' name ' )
self . assertEqual ( instance . _ip , ' ip ' )
self . assertEqual ( instance . _mac , ' mac ' )
2024-01-30 03:49:36 +01:00
self . assertEqual ( instance . _task , ' task ' )
2024-01-28 02:10:08 +01:00
self . assertEqual ( instance . _vmid , ' vmid ' )
self . assertEqual ( instance . _reason , ' reason ' )
self . assertEqual ( instance . _queue , TEST_QUEUE )
2024-01-30 03:49:36 +01:00
def test_marshaling ( self ) - > None :
# queue is kept on "storage", so we need always same environment
environment = Environment . testing_environment ( )
2024-01-28 02:10:08 +01:00
2024-01-30 03:49:36 +01:00
def _create_instance ( unmarshal_data : ' bytes|None ' = None ) - > Deployment :
2024-02-26 05:50:36 +01:00
instance = Deployment ( environment = environment , service = None ) # type: ignore # service is not used
2024-01-30 03:49:36 +01:00
if unmarshal_data :
instance . unmarshal ( unmarshal_data )
return instance
2024-01-28 02:10:08 +01:00
2024-01-30 03:49:36 +01:00
for v in range ( 1 , len ( SERIALIZED_DEPLOYMENT_DATA ) + 1 ) :
version = f ' v { v } '
instance = _create_instance ( SERIALIZED_DEPLOYMENT_DATA [ version ] )
2024-01-28 02:10:08 +01:00
self . check ( version , instance )
2024-01-30 03:49:36 +01:00
# Ensure remarshalled flag is set
self . assertTrue ( instance . needs_upgrade ( ) )
instance . mark_for_upgrade ( False ) # reset flag
2024-01-28 02:10:08 +01:00
2024-01-30 03:49:36 +01:00
marshaled_data = instance . marshal ( )
self . assertFalse (
marshaled_data . startswith ( b ' \v ' )
) # Ensure fields has been marshalled using new format
2024-01-28 02:10:08 +01:00
2024-01-30 03:49:36 +01:00
instance = _create_instance ( marshaled_data )
self . assertFalse (
instance . needs_upgrade ( )
) # Reunmarshall again and check that remarshalled flag is not set
self . check ( version , instance )
2024-01-28 02:10:08 +01:00
def test_marshaling_queue ( self ) - > None :
2024-01-30 03:49:36 +01:00
# queue is kept on "storage", so we need always same environment
environment = Environment . testing_environment ( )
# Store queue
environment . storage . put_pickle ( ' queue ' , TEST_QUEUE )
def _create_instance ( unmarshal_data : ' bytes|None ' = None ) - > Deployment :
2024-02-26 05:50:36 +01:00
instance = Deployment ( environment = environment , service = None ) # type: ignore # service is not used
2024-01-28 02:10:08 +01:00
if unmarshal_data :
instance . unmarshal ( unmarshal_data )
return instance
2024-01-30 03:49:36 +01:00
instance = _create_instance ( SERIALIZED_DEPLOYMENT_DATA [ LAST_VERSION ] )
self . assertEqual ( instance . _queue , TEST_QUEUE )
2024-01-28 02:10:08 +01:00
2024-01-30 03:49:36 +01:00
instance . _queue = [
Operation . CREATE ,
Operation . FINISH ,
]
2024-01-28 02:10:08 +01:00
marshaled_data = instance . marshal ( )
instance = _create_instance ( marshaled_data )
2024-01-30 03:49:36 +01:00
self . assertEqual (
instance . _queue ,
[ Operation . CREATE , Operation . FINISH ] ,
)
2024-01-28 02:10:08 +01:00
# Append something remarshall and check
2024-01-30 03:49:36 +01:00
instance . _queue . insert ( 0 , Operation . RETRY )
2024-01-28 02:10:08 +01:00
marshaled_data = instance . marshal ( )
instance = _create_instance ( marshaled_data )
self . assertEqual (
2024-01-30 03:49:36 +01:00
instance . _queue ,
[
Operation . RETRY ,
Operation . CREATE ,
Operation . FINISH ,
] ,
2024-01-28 02:10:08 +01:00
)
# Remove something remarshall and check
instance . _queue . pop ( 0 )
marshaled_data = instance . marshal ( )
instance = _create_instance ( marshaled_data )
2024-01-30 03:49:36 +01:00
self . assertEqual (
instance . _queue ,
[ Operation . CREATE , Operation . FINISH ] ,
)
def test_autoserialization_fields ( self ) - > None :
# This test is designed to ensure that all fields are autoserializable
# If some field is added or removed, this tests will warn us about it to fix the rest of the related tests
with Environment . temporary_environment ( ) as env :
2024-02-26 05:50:36 +01:00
instance = Deployment ( environment = env , service = None ) # type: ignore # service is not used
2024-01-30 03:49:36 +01:00
self . assertSetEqual ( set ( f [ 0 ] for f in instance . _autoserializable_fields ( ) ) , EXPECTED_FIELDS )