package org.ovirt.engine.core.utils.customprop;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.ovirt.engine.core.common.utils.customprop.PropertiesUtilsTestHelper.validateFailure;
import static org.ovirt.engine.core.common.utils.customprop.PropertiesUtilsTestHelper.validatePropertyMap;
import static org.ovirt.engine.core.common.utils.customprop.PropertiesUtilsTestHelper.validatePropertyValue;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType;
import org.ovirt.engine.core.common.utils.customprop.ValidationError;
import org.ovirt.engine.core.common.utils.customprop.ValidationFailureReason;
import org.ovirt.engine.core.common.utils.exceptions.InitializationException;
import org.ovirt.engine.core.compat.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Tests for custom device properties handling
*/
@RunWith(MockitoJUnitRunner.class)
public class DevicePropertiesUtilsTest {
private static final Logger log = LoggerFactory.getLogger(DevicePropertiesUtilsTest.class);
/**
* Initializes {@code DevicePropertiesUtils} instance for test
*
* @return initialized instance
*/
private DevicePropertiesUtils mockDevicePropertiesUtils() {
return mockDevicePropertiesUtils("{type=disk;prop={bootable=^(true|false)$}};"
+ "{type=interface;prop={speed=^([0-9]{1,5})$;duplex=^(full|half)$;debug=([a-z0-9A-Z]*)$}}");
}
/**
* Initializes {@code DevicePropertiesUtils} instance with specified custom device properties for test
*
* @param customDevPropSpec
* custom device properties specification
* @return initialized instance
*/
private DevicePropertiesUtils mockDevicePropertiesUtils(String customDevPropSpec) {
DevicePropertiesUtils mockedUtils = spy(new DevicePropertiesUtils());
doReturn(customDevPropSpec).
when(mockedUtils)
.getCustomDeviceProperties(Version.v4_0);
doReturn(Collections.singleton(Version.v4_0)).
when(mockedUtils)
.getSupportedClusterLevels();
try {
mockedUtils.init();
} catch (InitializationException ex) {
log.error("Error initializing DevicePropertiesUtils instance", ex);
}
return mockedUtils;
}
/**
* Tries to set property with no value (value is invalid due provided REGEX) to a device with supported version
*/
@Test
public void invalidPropertyValue1() {
DevicePropertiesUtils utils = mockDevicePropertiesUtils();
Map<String, String> map = new HashMap<>();
map.put("bootable", null);
List<ValidationError> errors = utils.validateProperties(Version.v4_0, VmDeviceGeneralType.DISK, map);
validateFailure(errors, ValidationFailureReason.INCORRECT_VALUE);
}
/**
* Tries to set invalid property value to a device with supported version
*/
@Test
public void invalidPropertyValue2() {
DevicePropertiesUtils utils = mockDevicePropertiesUtils();
List<ValidationError> errors =
utils.validateProperties(Version.v4_0, VmDeviceGeneralType.DISK, utils.convertProperties("bootable=x"));
validateFailure(errors, ValidationFailureReason.INCORRECT_VALUE);
}
/**
* Tries to set valid property to a device (device type differs from the type the properties are defined for) with
* supported version
*/
@Test
public void validPropertyInvalidDeviceType() {
DevicePropertiesUtils utils = mockDevicePropertiesUtils();
List<ValidationError> errors =
utils.validateProperties(Version.v4_0,
VmDeviceGeneralType.DISK,
utils.convertProperties("speed=10;duplex=half"));
validateFailure(errors, ValidationFailureReason.KEY_DOES_NOT_EXIST);
}
/**
* Tries to set valid property to unknown device type with supported version
*/
@Test
public void validPropertyUnknownDeviceType() {
DevicePropertiesUtils utils = mockDevicePropertiesUtils();
List<ValidationError> errors =
utils.validateProperties(Version.v4_0,
VmDeviceGeneralType.UNKNOWN,
utils.convertProperties("speed=10;duplex=half"));
validateFailure(errors, ValidationFailureReason.INVALID_DEVICE_TYPE);
}
/**
* Tries to set valid properties to valid device type with supported version
*/
@Test
public void validPropertyValidDeviceType() {
DevicePropertiesUtils utils = mockDevicePropertiesUtils();
List<ValidationError> errors =
utils.validateProperties(Version.v4_0,
VmDeviceGeneralType.INTERFACE,
utils.convertProperties("speed=10;duplex=half;debug="));
assertTrue(errors.isEmpty());
}
/**
* Tries to validate valid custom device properties specification
*/
@Test
public void validCustomDevPropSpec() {
String customDevPropSpec = "{type=disk;prop={bootable=^(true|false)$}};"
+ "{type=interface;prop={speed=[0-9]{1,5};duplex=^(full|half)$;debug=([a-z0-9A-Z]*)$}};"
+ "{type=video;prop={turned_on=^(true|false)$}};"
+ "{type=sound;prop={volume=[0-9]{1,2}}};"
+ "{type=controller;prop={hotplug=^(true|false)$}};"
+ "{type=balloon;prop={max_size=[0-9]{1,15}}};"
+ "{type=channel;prop={auth_type=^(plain|md5|kerberos)$}};"
+ "{type=redir;prop={max_len=[0-9]{1,15}}};"
+ "{type=console;prop={type=^(text|vnc)$}};"
+ "{type=smartcard;prop={version=([1-9]{1}).([0-9]{1})}}";
DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();
assertTrue(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
}
/**
* Tries to validate valid custom device properties specification with special characters
*/
@Test
public void validCustomDevPropSpecWithSpecChars() {
String customDevPropSpec =
"{type=disk;prop={bootable=[\\@\\#\\$\\%\\^\\&\\*\\(\\)\\{\\}\\:\\<\\>\\,\\.\\?\\[\\]]?}};";
DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();
assertTrue(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
}
/**
* Tries to validate custom device properties specification with invalid device type
*/
@Test
public void customDevPropSpecWithInvalidType() {
String customDevPropSpec = "{type=diks;prop={bootable=^(true|false)$}}";
DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();
assertFalse(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
}
/**
* Tries to validate custom device properties specification with invalid type key
*/
@Test
public void customDevPropSpecWithInvalidTypeKey() {
String customDevPropSpec = "{typ=disk;prop={bootable=^(true|false)$}}";
DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();
assertFalse(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
}
/**
* Tries to validate custom device properties specification with incomplete brackets
*/
@Test
public void customDevPropSpecWithIncompleteBrackets() {
String customDevPropSpec = "{type=disk;prop={bootable=^(true|false)$}";
DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();
assertFalse(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
}
/**
* Tries to validate custom device properties specification with invalid syntax
*/
@Test
public void customDevPropSpecWithInvalidTypePropDelimiter() {
String customDevPropSpec = "{type=disk,prop={bootable=^(true|false)$}}";
DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();
assertFalse(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
}
/**
* Tries to validate custom device properties specification with invalid property key name
*/
@Test
public void customDevPropSpecWithInvalidPropertyKeyName() {
String customDevPropSpec = "{type=disk;prop={boot*able=^(true|false)$}}";
DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();
assertFalse(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
}
/**
* Tries to validate custom device properties specification with invalid property value
*/
@Test
public void customDevPropSpecWithInvalidPropertyValue() {
String customDevPropSpec = "{type=disk;prop={bootable=^(true;false)$}}";
DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();
assertFalse(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
}
/**
* Tries to validate custom device properties specification with property value containing invalid characters
*/
@Test
public void customDevPropSpecWithInvalidCharsPropertyValue() {
String customDevPropSpec = "{type=disk;prop={bootable=([{};])?}}";
DevicePropertiesUtils utils = DevicePropertiesUtils.getInstance();
assertFalse(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
}
/**
* Tries to validate if a valid custom device properties specification have been parsed correctly
*/
@Test
public void parseValidCustomDevPropSpec() {
Map<String, String> devProp;
String customDevPropSpec = "{type=disk;prop={bootable=^(true|false)$}};"
+ "{type=interface;prop={speed=[0-9]{1,5};duplex=^(full|half)$}};"
+ "{type=video;prop={turned_on=^(true|false)$}};"
+ "{type=sound;prop={volume=[0-9]{1,2}}};"
+ "{type=controller;prop={hotplug=^(true|false)$}};"
+ "{type=balloon;prop={max_size=[0-9]{1,15}}};"
+ "{type=channel;prop={auth_type=^(plain|md5|kerberos)$}};"
+ "{type=redir;prop={max_len=[0-9]{1,15}}};"
+ "{type=console;prop={type=^(text|vnc)$;prop=\\{\\}}};"
+ "{type=smartcard;prop={spec_chars=[\\@\\#\\$\\%\\^\\&\\*\\(\\)\\{\\}\\:\\<\\>\\,\\.\\?\\[\\]]?}}";
// mock DevicePropertiesUtils
DevicePropertiesUtils utils = mockDevicePropertiesUtils(customDevPropSpec);
// test if custom properties spec is valid
assertTrue(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
// test parsed properties
assertEquals(10, utils.getDeviceTypesWithProperties(Version.v4_0).size());
// test disk properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.DISK);
validatePropertyMap(devProp, 1);
validatePropertyValue(devProp, "bootable", "^(true|false)$");
// test interface properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.INTERFACE);
validatePropertyMap(devProp, 2);
validatePropertyValue(devProp, "speed", "[0-9]{1,5}");
validatePropertyValue(devProp, "duplex", "^(full|half)$");
// test video properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.VIDEO);
validatePropertyMap(devProp, 1);
validatePropertyValue(devProp, "turned_on", "^(true|false)$");
// test sound properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.SOUND);
validatePropertyMap(devProp, 1);
validatePropertyValue(devProp, "volume", "[0-9]{1,2}");
// test video properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.CONTROLLER);
validatePropertyMap(devProp, 1);
validatePropertyValue(devProp, "hotplug", "^(true|false)$");
// test balloon properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.BALLOON);
validatePropertyMap(devProp, 1);
validatePropertyValue(devProp, "max_size", "[0-9]{1,15}");
// test channel properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.CHANNEL);
validatePropertyMap(devProp, 1);
validatePropertyValue(devProp, "auth_type", "^(plain|md5|kerberos)$");
// test redir properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.REDIR);
validatePropertyMap(devProp, 1);
validatePropertyValue(devProp, "max_len", "[0-9]{1,15}");
// test console properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.CONSOLE);
validatePropertyMap(devProp, 2);
validatePropertyValue(devProp, "type", "^(text|vnc)$");
validatePropertyValue(devProp, "prop", "\\{\\}");
// test smartcard properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.SMARTCARD);
validatePropertyMap(devProp, 1);
validatePropertyValue(devProp, "spec_chars", "[\\@\\#\\$\\%\\^\\&\\*\\(\\)\\{\\}\\:\\<\\>\\,\\.\\?\\[\\]]?");
}
/**
* Tries to validate conversion of device properties to {@code Map<String, String>}
*/
@Test
public void validateGetRawDeviceProperties() {
Map<String, String> devProp;
String customDevPropSpec = "{type=disk;prop={bootable=^(true|false)$}};"
+ "{type=interface;prop={speed=[0-9]{1,5};duplex=^(full|half)$}};";
// mock DevicePropertiesUtils
DevicePropertiesUtils utils = mockDevicePropertiesUtils(customDevPropSpec);
// test if custom properties spec is valid
assertTrue(utils.isDevicePropertiesDefinitionValid(customDevPropSpec));
// test parsed properties
assertEquals(2, utils.getDeviceTypesWithProperties(Version.v4_0).size());
// test disk properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.DISK);
validatePropertyMap(devProp, 1);
validatePropertyValue(devProp, "bootable", "^(true|false)$");
// test interface properties
devProp = utils.getDeviceProperties(Version.v4_0, VmDeviceGeneralType.INTERFACE);
validatePropertyMap(devProp, 2);
validatePropertyValue(devProp, "speed", "[0-9]{1,5}");
validatePropertyValue(devProp, "duplex", "^(full|half)$");
}
}