package org.ovirt.engine.core.bll;

import java.util.ArrayList;

import junit.framework.Assert;

import org.junit.Test;

import org.ovirt.engine.core.common.action.VmManagementParametersBase;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VmStatic;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dal.VdcBllMessages;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;


public class VmManagementCommandBaseTest {


    @Test
    public void isCpuPinningValid() {
        VmManagementCommandBase<VmManagementParametersBase> test =
                spy(new VmManagementCommandBase<VmManagementParametersBase>(Guid.Empty));
        VmStatic vmStatic = new VmStatic();
        vmStatic.setNumOfSockets(6);
        vmStatic.setCpuPerSocket(2);
        vmStatic.setDedicatedVmForVds(Guid.Empty);
        final VDS dedicatedVds = new VDS();
        dedicatedVds.setCpuThreads(16);
        dedicatedVds.setvds_group_compatibility_version(Version.v3_2);

        doReturn(dedicatedVds).when(test).getVds(Guid.Empty);



        Assert.assertTrue("null value must be accepted",
                test.isCpuPinningValid(null, vmStatic));

        Assert.assertTrue("empty string must be accepted",
                test.isCpuPinningValid("", vmStatic));

        Assert.assertFalse(test.isCpuPinningValid("intentionally invalid", vmStatic));

        Assert.assertTrue(test.isCpuPinningValid("0#0", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1-4", vmStatic));
        Assert.assertFalse(test.isCpuPinningValid("0#^3", vmStatic));
        Assert.assertFalse(test.isCpuPinningValid("0#^3,^2", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1-8,^6", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1-8,^6,^7", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1-8,^6,^7", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1-8,^5,^6,^7", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1,2,3", vmStatic));
        Assert.assertFalse(test.isCpuPinningValid("0#^1,^2,^3", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1-4,6-8", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1-4,6-8,9-12", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1-4,^3,9-12,^10", vmStatic));

        Assert.assertTrue(test.isCpuPinningValid("0#0_1#1", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1-2_1#1-2", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1,2,3_1#2,3", vmStatic));
        Assert.assertTrue(test.isCpuPinningValid("0#1,2,3_1#1-4,^3", vmStatic));
        //validate vcpus over 9
        Assert.assertTrue(test.isCpuPinningValid("10#1,2,3_11#1-4,^3", vmStatic));

        //negative tests

        Assert.assertFalse("random wrong text",
                test.isCpuPinningValid("lorem ipsum", vmStatic));
        Assert.assertFalse("no cpu id specified, should not pass",
                test.isCpuPinningValid("0", vmStatic));
        Assert.assertFalse("letter instead of vcpu ID",
                test.isCpuPinningValid("A#1", vmStatic));
        Assert.assertFalse("letter instead of cpu ID",
                test.isCpuPinningValid("0#B", vmStatic));
        Assert.assertFalse("A separating _ while only one vcpu pinning",
                test.isCpuPinningValid("0#1_", vmStatic));
        Assert.assertFalse("Trailing _",
                test.isCpuPinningValid("0#1_1#2_", vmStatic));
        Assert.assertFalse("Too many separators",
                test.isCpuPinningValid("0#1__1#2", vmStatic));
        Assert.assertFalse("trailing junk",
                test.isCpuPinningValid("0#1_1#2...", vmStatic));


        // negative logical validation
        ArrayList<String> canDoActionMessages = test.getReturnValue().getCanDoActionMessages();
        canDoActionMessages.clear();
        Assert.assertFalse(test.isCpuPinningValid("10#1,2,3_10#1-4,^3", vmStatic));
        Assert.assertTrue(canDoActionMessages.size() > 0);
        if (canDoActionMessages.size() > 0) {
            Assert.assertEquals(VdcBllMessages.VM_PINNING_DUPLICATE_DEFINITION.toString(), canDoActionMessages.get(0));
        }
        canDoActionMessages.clear();
        Assert.assertFalse(test.isCpuPinningValid("10#1,2,^1,^2", vmStatic));
        Assert.assertTrue(canDoActionMessages.size() > 0);
        if (canDoActionMessages.size() > 0) {
            Assert.assertEquals(VdcBllMessages.VM_PINNING_PINNED_TO_NO_CPU.toString(), canDoActionMessages.get(0));
        }
        canDoActionMessages.clear();
        Assert.assertFalse(test.isCpuPinningValid("10#1,2,3_20#1-4,^3", vmStatic));
        Assert.assertTrue(canDoActionMessages.size() > 0);
        if (canDoActionMessages.size() > 0) {
            Assert.assertEquals(VdcBllMessages.VM_PINNING_VCPU_DOES_NOT_EXIST.toString(), canDoActionMessages.get(0));
        }
        canDoActionMessages.clear();
        Assert.assertFalse(test.isCpuPinningValid("10#1,2,3_11#1-20,^3", vmStatic));
        Assert.assertTrue(canDoActionMessages.size() > 0);
        if (canDoActionMessages.size() > 0) {
            Assert.assertEquals(VdcBllMessages.VM_PINNING_PCPU_DOES_NOT_EXIST.toString(), canDoActionMessages.get(0));
        }

        // making sure cluster < 3.2 does not get validated on pCPU as we cant tell the number for sure
        dedicatedVds.setvds_group_compatibility_version(Version.v3_1);
        Assert.assertTrue(test.isCpuPinningValid("10#1,2,3_11#1-20,^3", vmStatic));

    }
}
