package com.netflix.fenzo; import org.junit.Before; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import java.util.*; import java.util.stream.Collectors; import static com.netflix.fenzo.plugins.TestableVirtualMachineLease.leasesWithIds; import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class ScaleDownConstraintExecutorTest { private final ScaleDownOrderEvaluator orderEvaluator = mock(ScaleDownOrderEvaluator.class); private final ScaleDownConstraintEvaluator<Void> evenFirstEvaluator = mock(ScaleDownConstraintEvaluator.class); private final ScaleDownConstraintEvaluator<Void> oddFirstEvaluator = mock(ScaleDownConstraintEvaluator.class); private ScaleDownConstraintExecutor executor; @Before public void setUp() throws Exception { when(evenFirstEvaluator.getName()).thenReturn("evenFirstEvaluator"); when(oddFirstEvaluator.getName()).thenReturn("oddFirstEvaluator"); } @Test public void testScaleDownOrdering() throws Exception { Map<ScaleDownConstraintEvaluator, Double> scoringEvaluators = new HashMap<>(); scoringEvaluators.put(evenFirstEvaluator, 10.0); scoringEvaluators.put(oddFirstEvaluator, 2.0); executor = new ScaleDownConstraintExecutor(orderEvaluator, scoringEvaluators); List<VirtualMachineLease> candidates = leasesWithIds("l0", "l1", "l2", "l3", "l4"); when(orderEvaluator.evaluate(candidates)).thenReturn( asList(asSet(candidates.get(0), candidates.get(2), candidates.get(3)), asSet(candidates.get(1), candidates.get(4))) ); when(evenFirstEvaluator.evaluate(any(), any())).then(a -> { int idx = leaseIndexOf(a); return ScaleDownConstraintEvaluator.Result.of(idx == 0 ? 0 : (idx % 2 == 0 ? 1 : 0.5)); }); when(oddFirstEvaluator.evaluate(any(), any())).then(a -> { int idx = leaseIndexOf(a); return ScaleDownConstraintEvaluator.Result.of(idx == 0 ? 0 : (idx % 2 == 1 ? 1 : 0.5)); }); List<VirtualMachineLease> order = executor.evaluate(candidates); List<String> ids = order.stream().map(VirtualMachineLease::getId).collect(Collectors.toList()); assertThat(ids, is(equalTo(asList("l2", "l3", "l4", "l1")))); } @Test public void testWeightsValidation() throws Exception { Map<ScaleDownConstraintEvaluator, Double> scoringEvaluators = new HashMap<>(); scoringEvaluators.put(evenFirstEvaluator, -5.0); scoringEvaluators.put(oddFirstEvaluator, 0.0); try { new ScaleDownConstraintExecutor(orderEvaluator, scoringEvaluators); fail("Expected to fail argument validation"); } catch (IllegalArgumentException e) { assertThat(e.getMessage().contains("evenFirstEvaluator=-5.0"), is(true)); assertThat(e.getMessage().contains("oddFirstEvaluator=0.0"), is(true)); } } private static <T> Set<T> asSet(T... values) { Set<T> result = new HashSet<>(); Collections.addAll(result, values); return result; } private static int leaseIndexOf(InvocationOnMock invocation) { String id = ((VirtualMachineLease) invocation.getArgument(0)).getId(); return Integer.parseInt("" + id.charAt(1)); } }