Return-Path: X-Original-To: apmail-brooklyn-commits-archive@minotaur.apache.org Delivered-To: apmail-brooklyn-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id D36FD187A0 for ; Tue, 18 Aug 2015 11:06:26 +0000 (UTC) Received: (qmail 84544 invoked by uid 500); 18 Aug 2015 11:06:17 -0000 Delivered-To: apmail-brooklyn-commits-archive@brooklyn.apache.org Received: (qmail 84520 invoked by uid 500); 18 Aug 2015 11:06:17 -0000 Mailing-List: contact commits-help@brooklyn.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@brooklyn.incubator.apache.org Delivered-To: mailing list commits@brooklyn.incubator.apache.org Received: (qmail 84511 invoked by uid 99); 18 Aug 2015 11:06:17 -0000 Received: from Unknown (HELO spamd3-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Aug 2015 11:06:17 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd3-us-west.apache.org (ASF Mail Server at spamd3-us-west.apache.org) with ESMTP id BF38818210F for ; Tue, 18 Aug 2015 11:06:16 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd3-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 0.794 X-Spam-Level: X-Spam-Status: No, score=0.794 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, RP_MATCHES_RCVD=-0.006] autolearn=disabled Received: from mx1-us-east.apache.org ([10.40.0.8]) by localhost (spamd3-us-west.apache.org [10.40.0.10]) (amavisd-new, port 10024) with ESMTP id 0zEkMlp_57Kd for ; Tue, 18 Aug 2015 11:06:01 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-us-east.apache.org (ASF Mail Server at mx1-us-east.apache.org) with SMTP id 06B5B42F2E for ; Tue, 18 Aug 2015 11:05:59 +0000 (UTC) Received: (qmail 83582 invoked by uid 99); 18 Aug 2015 11:05:59 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Aug 2015 11:05:59 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 4D51CE0582; Tue, 18 Aug 2015 11:05:59 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: heneveld@apache.org To: commits@brooklyn.incubator.apache.org Date: Tue, 18 Aug 2015 11:06:07 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [09/24] incubator-brooklyn git commit: [BROOKLYN-162] Renaming package policy http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d30ff597/policy/src/test/java/brooklyn/policy/loadbalancing/LoadBalancingPolicyTest.java ---------------------------------------------------------------------- diff --git a/policy/src/test/java/brooklyn/policy/loadbalancing/LoadBalancingPolicyTest.java b/policy/src/test/java/brooklyn/policy/loadbalancing/LoadBalancingPolicyTest.java deleted file mode 100644 index 442e3b3..0000000 --- a/policy/src/test/java/brooklyn/policy/loadbalancing/LoadBalancingPolicyTest.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.policy.loadbalancing; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; - -import org.apache.brooklyn.api.entity.basic.EntityLocal; -import org.testng.annotations.Test; - -import brooklyn.entity.basic.Entities; -import brooklyn.test.Asserts; -import brooklyn.util.collections.MutableMap; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; - -public class LoadBalancingPolicyTest extends AbstractLoadBalancingPolicyTest { - - // Expect no balancing to occur as container A isn't above the high threshold. - @Test - public void testNoopWhenWithinThresholds() { - MockContainerEntity containerA = newContainer(app, "A", 10, 100); - MockContainerEntity containerB = newContainer(app, "B", 20, 60); - MockItemEntity item1 = newItem(app, containerA, "1", 10); - MockItemEntity item2 = newItem(app, containerA, "2", 10); - MockItemEntity item3 = newItem(app, containerA, "3", 10); - MockItemEntity item4 = newItem(app, containerA, "4", 10); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4), - ImmutableList.of(40d, 0d)); - } - - @Test - public void testNoopWhenAlreadyBalanced() { - MockContainerEntity containerA = newContainer(app, "A", 20, 80); - MockContainerEntity containerB = newContainer(app, "B", 20, 80); - MockItemEntity item1 = newItem(app, containerA, "1", 10); - MockItemEntity item2 = newItem(app, containerA, "2", 30); - MockItemEntity item3 = newItem(app, containerB, "3", 20); - MockItemEntity item4 = newItem(app, containerB, "4", 20); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4), - ImmutableList.of(40d, 40d)); - assertEquals(containerA.getBalanceableItems(), ImmutableSet.of(item1, item2)); - assertEquals(containerB.getBalanceableItems(), ImmutableSet.of(item3, item4)); - } - - // Expect 20 units of workload to be migrated from hot container (A) to cold (B). - @Test - public void testSimpleBalancing() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 25); - MockContainerEntity containerB = newContainer(app, "B", 20, 60); - MockItemEntity item1 = newItem(app, containerA, "1", 10); - MockItemEntity item2 = newItem(app, containerA, "2", 10); - MockItemEntity item3 = newItem(app, containerA, "3", 10); - MockItemEntity item4 = newItem(app, containerA, "4", 10); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4), - ImmutableList.of(20d, 20d)); - } - - @Test - public void testSimpleBalancing2() { - MockContainerEntity containerA = newContainer(app, "A", 20, 40); - MockContainerEntity containerB = newContainer(app, "B", 20, 40); - MockItemEntity item1 = newItem(app, containerA, "1", 0); - MockItemEntity item2 = newItem(app, containerB, "2", 40); - MockItemEntity item3 = newItem(app, containerB, "3", 20); - MockItemEntity item4 = newItem(app, containerB, "4", 20); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4), - ImmutableList.of(40d, 40d)); - } - -// @Test -// public void testAdjustedItemNotMoved() { -// MockBalancingModel pool = new MockBalancingModel( -// containers( -// containerA, 20, 50, -// containerB, 20, 50), -// items( -// "item1", containerA, 0, -// "item2", containerB, -40, -// "item3", containerB, 20, -// "item4", containerB, 20) -// ); -// -// BalancingStrategy policy = new BalancingStrategy("Test", pool); -// policy.rebalance(); -// -// assertEquals((Object)pool.getItemsForContainer(containerA), ImmutableSet.of("item1", "item3", "item4"), pool.itemDistributionToString()); -// assertEquals((Object)pool.getItemsForContainer(containerB), ImmutableSet.of("item2"), pool.itemDistributionToString()); -// } - - @Test - public void testMultiMoveBalancing() { - MockContainerEntity containerA = newContainer(app, "A", 20, 50); - MockContainerEntity containerB = newContainer(app, "B", 20, 50); - MockItemEntity item1 = newItem(app, containerA, "1", 10); - MockItemEntity item2 = newItem(app, containerA, "2", 10); - MockItemEntity item3 = newItem(app, containerA, "3", 10); - MockItemEntity item4 = newItem(app, containerA, "4", 10); - MockItemEntity item5 = newItem(app, containerA, "5", 10); - MockItemEntity item6 = newItem(app, containerA, "6", 10); - MockItemEntity item7 = newItem(app, containerA, "7", 10); - MockItemEntity item8 = newItem(app, containerA, "8", 10); - MockItemEntity item9 = newItem(app, containerA, "9", 10); - MockItemEntity item10 = newItem(app, containerA, "10", 10); - - // non-deterministic which items will be moved; but can assert how many (given they all have same workrate) - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10), - ImmutableList.of(50d, 50d)); - assertEquals(containerA.getBalanceableItems().size(), 5); - assertEquals(containerB.getBalanceableItems().size(), 5); - } - - @Test - public void testRebalanceWhenWorkratesChange() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 50); - MockContainerEntity containerB = newContainer(app, "B", 10, 50); - MockItemEntity item1 = newItem(app, containerA, "1", 0); - MockItemEntity item2 = newItem(app, containerA, "2", 0); - - ((EntityLocal)item1).setAttribute(MockItemEntity.TEST_METRIC, 40); - ((EntityLocal)item2).setAttribute(MockItemEntity.TEST_METRIC, 40); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2), - ImmutableList.of(40d, 40d)); - } - - // Expect no balancing to occur in hot pool (2 containers over-threshold at 40). - // On addition of new container, expect hot containers to offload 10 each. - @Test - public void testAddContainerWhenHot() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 30); - MockContainerEntity containerB = newContainer(app, "B", 10, 30); - MockItemEntity item1 = newItem(app, containerA, "1", 10); - MockItemEntity item2 = newItem(app, containerA, "2", 10); - MockItemEntity item3 = newItem(app, containerA, "3", 10); - MockItemEntity item4 = newItem(app, containerA, "4", 10); - MockItemEntity item5 = newItem(app, containerB, "5", 10); - MockItemEntity item6 = newItem(app, containerB, "6", 10); - MockItemEntity item7 = newItem(app, containerB, "7", 10); - MockItemEntity item8 = newItem(app, containerB, "8", 10); - // Both containers are over-threshold at this point; should not rebalance. - - MockContainerEntity containerC = newAsyncContainer(app, "C", 10, 30, CONTAINER_STARTUP_DELAY_MS); - // New container allows hot ones to offload work. - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB, containerC), - ImmutableList.of(item1, item2, item3, item4, item5, item6, item7, item8), - ImmutableList.of(30d, 30d, 20d)); - } - - // On addition of new container, expect no rebalancing to occur as no existing container is hot. - @Test - public void testAddContainerWhenCold() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 50); - MockContainerEntity containerB = newContainer(app, "B", 10, 50); - MockItemEntity item1 = newItem(app, containerA, "1", 10); - MockItemEntity item2 = newItem(app, containerA, "2", 10); - MockItemEntity item3 = newItem(app, containerA, "3", 10); - MockItemEntity item4 = newItem(app, containerA, "4", 10); - MockItemEntity item5 = newItem(app, containerB, "5", 10); - MockItemEntity item6 = newItem(app, containerB, "6", 10); - MockItemEntity item7 = newItem(app, containerB, "7", 10); - MockItemEntity item8 = newItem(app, containerB, "8", 10); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4, item5, item6, item7, item8), - ImmutableList.of(40d, 40d)); - - MockContainerEntity containerC = newAsyncContainer(app, "C", 10, 50, CONTAINER_STARTUP_DELAY_MS); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB, containerC), - ImmutableList.of(item1, item2, item3, item4, item5, item6, item7, item8), - ImmutableList.of(40d, 40d, 0d)); - } - - // Expect no balancing to occur in cool pool (2 containers under-threshold at 30). - // On addition of new item, expect over-threshold container (A) to offload 20 to B. - @Test - public void testAddItem() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 50); - MockContainerEntity containerB = newContainer(app, "B", 10, 50); - MockItemEntity item1 = newItem(app, containerA, "1", 10); - MockItemEntity item2 = newItem(app, containerA, "2", 10); - MockItemEntity item3 = newItem(app, containerA, "3", 10); - MockItemEntity item4 = newItem(app, containerB, "4", 10); - MockItemEntity item5 = newItem(app, containerB, "5", 10); - MockItemEntity item6 = newItem(app, containerB, "6", 10); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4, item5, item6), - ImmutableList.of(30d, 30d)); - - newItem(app, containerA, "7", 40); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4, item5, item6), - ImmutableList.of(50d, 50d)); - } - - // FIXME Failed in build repeatedly (e.g. #1035), but couldn't reproduce locally yet with invocationCount=100 - @Test(groups="WIP") - public void testRemoveContainerCausesRebalancing() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 30); - MockContainerEntity containerB = newContainer(app, "B", 10, 30); - MockContainerEntity containerC = newContainer(app, "C", 10, 30); - MockItemEntity item1 = newItem(app, containerA, "1", 10); - MockItemEntity item2 = newItem(app, containerA, "2", 10); - MockItemEntity item3 = newItem(app, containerB, "3", 10); - MockItemEntity item4 = newItem(app, containerB, "4", 10); - MockItemEntity item5 = newItem(app, containerC, "5", 10); - MockItemEntity item6 = newItem(app, containerC, "6", 10); - - Entities.unmanage(containerC); - item5.move(containerA); - item6.move(containerA); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4, item5, item6), - ImmutableList.of(30d, 30d)); - } - - @Test - public void testRemoveItemCausesRebalancing() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 30); - MockContainerEntity containerB = newContainer(app, "B", 10, 30); - MockItemEntity item1 = newItem(app, containerA, "1", 30); - MockItemEntity item2 = newItem(app, containerB, "2", 20); - MockItemEntity item3 = newItem(app, containerB, "3", 20); - - item1.stop(); - Entities.unmanage(item1); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3), - ImmutableList.of(20d, 20d)); - } - - @Test - public void testRebalancesAfterManualMove() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 50); - MockContainerEntity containerB = newContainer(app, "B", 10, 50); - MockItemEntity item1 = newItem(app, containerA, "1", 20); - MockItemEntity item2 = newItem(app, containerA, "2", 20); - MockItemEntity item3 = newItem(app, containerB, "3", 20); - MockItemEntity item4 = newItem(app, containerB, "4", 20); - - // Move everything onto containerA, and expect it to be automatically re-balanced - item3.move(containerA); - item4.move(containerA); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3, item4), - ImmutableList.of(40d, 40d)); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Test - public void testModelIncludesItemsAndContainersStartedBeforePolicyCreated() { - pool.removePolicy(policy); - policy.destroy(); - - // Set-up containers and items. - final MockContainerEntity containerA = newContainer(app, "A", 10, 100); - newItem(app, containerA, "1", 10); - - policy = new LoadBalancingPolicy(MutableMap.of(), TEST_METRIC, model); - pool.addPolicy(policy); - - Asserts.succeedsEventually(MutableMap.of("timeout", TIMEOUT_MS), new Runnable() { - public void run() { - assertEquals(model.getContainerWorkrates(), ImmutableMap.of(containerA, 10d)); - } - }); - } - - @Test - public void testLockedItemsNotMoved() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 50); - MockContainerEntity containerB = newContainer(app, "B", 10, 50); - MockItemEntity item1 = newLockedItem(app, containerA, "1", 40); - MockItemEntity item2 = newLockedItem(app, containerA, "2", 40); - - assertWorkratesContinually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2), - ImmutableList.of(80d, 0d)); - } - - @Test - public void testLockedItemsContributeToOverloadedMeasurements() { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 50); - MockContainerEntity containerB = newContainer(app, "B", 10, 50); - MockItemEntity item1 = newLockedItem(app, containerA, "1", 40); - MockItemEntity item2 = newItem(app, containerA, "2", 25); - MockItemEntity item3 = newItem(app, containerA, "3", 25); - - assertWorkratesEventually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3), - ImmutableList.of(40d, 50d)); - } - - @Test - public void testOverloadedLockedItemsPreventMoreWorkEnteringContainer() throws Exception { - // Set-up containers and items. - MockContainerEntity containerA = newContainer(app, "A", 10, 50); - MockContainerEntity containerB = newContainer(app, "B", 10, 50); - MockItemEntity item1 = newLockedItem(app, containerA, "1", 50); - Thread.sleep(1); // increase chances of item1's workrate having been received first - MockItemEntity item2 = newItem(app, containerB, "2", 30); - MockItemEntity item3 = newItem(app, containerB, "3", 30); - - assertWorkratesContinually( - ImmutableList.of(containerA, containerB), - ImmutableList.of(item1, item2, item3), - ImmutableList.of(50d, 60d)); - } - - @Test - public void testPolicyUpdatesModel() { - final MockContainerEntity containerA = newContainer(app, "A", 10, 20); - final MockContainerEntity containerB = newContainer(app, "B", 11, 21); - final MockItemEntity item1 = newItem(app, containerA, "1", 12); - final MockItemEntity item2 = newItem(app, containerB, "2", 13); - - Asserts.succeedsEventually(MutableMap.of("timeout", TIMEOUT_MS), new Runnable() { - public void run() { - assertEquals(model.getPoolSize(), 2); - assertEquals(model.getPoolContents(), ImmutableSet.of(containerA, containerB)); - assertEquals(model.getItemWorkrate(item1), 12d); - assertEquals(model.getItemWorkrate(item2), 13d); - - assertEquals(model.getParentContainer(item1), containerA); - assertEquals(model.getParentContainer(item2), containerB); - assertEquals(model.getContainerWorkrates(), ImmutableMap.of(containerA, 12d, containerB, 13d)); - - assertEquals(model.getPoolLowThreshold(), 10+11d); - assertEquals(model.getPoolHighThreshold(), 20+21d); - assertEquals(model.getCurrentPoolWorkrate(), 12+13d); - assertFalse(model.isHot()); - assertFalse(model.isCold()); - } - }); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d30ff597/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntity.java ---------------------------------------------------------------------- diff --git a/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntity.java b/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntity.java deleted file mode 100644 index 70d4b57..0000000 --- a/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntity.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.policy.loadbalancing; - -import java.util.Map; - -import org.apache.brooklyn.api.entity.Effector; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.proxying.ImplementedBy; -import org.apache.brooklyn.core.util.flags.SetFromFlag; - -import brooklyn.config.ConfigKey; -import brooklyn.entity.annotation.EffectorParam; -import brooklyn.entity.basic.AbstractGroup; -import brooklyn.entity.basic.MethodEffector; -import brooklyn.entity.trait.Startable; -import brooklyn.event.basic.BasicConfigKey; - -@ImplementedBy(MockContainerEntityImpl.class) -public interface MockContainerEntity extends AbstractGroup, BalanceableContainer, Startable { - - @SetFromFlag("membership") - public static final ConfigKey MOCK_MEMBERSHIP = new BasicConfigKey( - String.class, "mock.container.membership", "For testing ItemsInContainersGroup"); - - @SetFromFlag("delay") - public static final ConfigKey DELAY = new BasicConfigKey( - Long.class, "mock.container.delay", "", 0L); - - public static final Effector OFFLOAD_AND_STOP = new MethodEffector(MockContainerEntity.class, "offloadAndStop"); - - public void lock(); - - public void unlock(); - - public int getWorkrate(); - - public Map getItemUsage(); - - public void addItem(Entity item); - - public void removeItem(Entity item); - - public void offloadAndStop(@EffectorParam(name="otherContianer") MockContainerEntity otherContainer); -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d30ff597/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntityImpl.java ---------------------------------------------------------------------- diff --git a/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntityImpl.java b/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntityImpl.java deleted file mode 100644 index 672addb..0000000 --- a/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntityImpl.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.policy.loadbalancing; - -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.event.AttributeSensor; -import org.apache.brooklyn.api.location.Location; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.entity.basic.AbstractGroupImpl; -import brooklyn.entity.basic.Attributes; -import brooklyn.util.collections.MutableList; -import brooklyn.util.time.Time; - -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - - -public class MockContainerEntityImpl extends AbstractGroupImpl implements MockContainerEntity { - - private static final Logger LOG = LoggerFactory.getLogger(MockContainerEntity.class); - - volatile boolean offloading; - volatile boolean running; - - ReentrantLock _lock = new ReentrantLock(); - - @Override - public T setAttribute(AttributeSensor attribute, T val) { - if (LOG.isDebugEnabled()) LOG.debug("Mocks: container {} setting {} to {}", new Object[] {this, attribute, val}); - return super.setAttribute(attribute, val); - } - - @Override - public void lock() { - _lock.lock(); - if (!running) { - _lock.unlock(); - throw new IllegalStateException("Container lock "+this+"; it is not running"); - } - } - - @Override - public void unlock() { - _lock.unlock(); - } - - @Override - public int getWorkrate() { - int result = 0; - for (Entity member : getMembers()) { - Integer memberMetric = member.getAttribute(MockItemEntity.TEST_METRIC); - result += ((memberMetric != null) ? memberMetric : 0); - } - return result; - } - - @Override - public Map getItemUsage() { - Map result = Maps.newLinkedHashMap(); - for (Entity member : getMembers()) { - Map memberItemUsage = member.getAttribute(MockItemEntity.ITEM_USAGE_METRIC); - if (memberItemUsage != null) { - for (Map.Entry entry : memberItemUsage.entrySet()) { - double val = (result.containsKey(entry.getKey()) ? result.get(entry.getKey()) : 0d); - val += ((entry.getValue() != null) ? entry.getValue() : 0); - result.put(entry.getKey(), val); - } - } - } - return result; - } - - @Override - public void addItem(Entity item) { - if (LOG.isDebugEnabled()) LOG.debug("Mocks: adding item {} to container {}", item, this); - if (!running || offloading) throw new IllegalStateException("Container "+getDisplayName()+" is not running; cannot add item "+item); - addMember(item); - emit(BalanceableContainer.ITEM_ADDED, item); - } - - @Override - public void removeItem(Entity item) { - if (LOG.isDebugEnabled()) LOG.debug("Mocks: removing item {} from container {}", item, this); - if (!running) throw new IllegalStateException("Container "+getDisplayName()+" is not running; cannot remove item "+item); - removeMember(item); - emit(BalanceableContainer.ITEM_REMOVED, item); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public Set getBalanceableItems() { - return (Set) Sets.newLinkedHashSet(getMembers()); - } - - public String toString() { - return "MockContainer["+getDisplayName()+"]"; - } - - private long getDelay() { - return getConfig(DELAY); - } - - @Override - public void start(Collection locs) { - if (LOG.isDebugEnabled()) LOG.debug("Mocks: starting container {}", this); - _lock.lock(); - try { - Time.sleep(getDelay()); - running = true; - addLocations(locs); - emit(Attributes.LOCATION_CHANGED, null); - setAttribute(SERVICE_UP, true); - } finally { - _lock.unlock(); - } - } - - @Override - public void stop() { - if (LOG.isDebugEnabled()) LOG.debug("Mocks: stopping container {}", this); - _lock.lock(); - try { - running = false; - Time.sleep(getDelay()); - setAttribute(SERVICE_UP, false); - } finally { - _lock.unlock(); - } - } - - private void stopWithoutLock() { - running = false; - Time.sleep(getDelay()); - setAttribute(SERVICE_UP, false); - } - - public void offloadAndStop(final MockContainerEntity otherContainer) { - if (LOG.isDebugEnabled()) LOG.debug("Mocks: offloading container {} to {} (items {})", new Object[] {this, otherContainer, getBalanceableItems()}); - runWithLock(ImmutableList.of(this, otherContainer), new Runnable() { - public void run() { - offloading = false; - for (Movable item : getBalanceableItems()) { - ((MockItemEntity)item).moveNonEffector(otherContainer); - } - if (LOG.isDebugEnabled()) LOG.debug("Mocks: stopping offloaded container {}", this); - stopWithoutLock(); - }}); - } - - @Override - public void restart() { - if (LOG.isDebugEnabled()) LOG.debug("Mocks: restarting {}", this); - throw new UnsupportedOperationException(); - } - - public static void runWithLock(List entitiesToLock, Runnable r) { - List entitiesToLockCopy = MutableList.copyOf(Iterables.filter(entitiesToLock, Predicates.notNull())); - List entitiesLocked = Lists.newArrayList(); - Collections.sort(entitiesToLockCopy, new Comparator() { - public int compare(MockContainerEntity o1, MockContainerEntity o2) { - return o1.getId().compareTo(o2.getId()); - }}); - - try { - for (MockContainerEntity it : entitiesToLockCopy) { - it.lock(); - entitiesLocked.add(it); - } - - r.run(); - - } finally { - for (MockContainerEntity it : entitiesLocked) { - it.unlock(); - } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d30ff597/policy/src/test/java/brooklyn/policy/loadbalancing/MockItemEntity.java ---------------------------------------------------------------------- diff --git a/policy/src/test/java/brooklyn/policy/loadbalancing/MockItemEntity.java b/policy/src/test/java/brooklyn/policy/loadbalancing/MockItemEntity.java deleted file mode 100644 index 9286072..0000000 --- a/policy/src/test/java/brooklyn/policy/loadbalancing/MockItemEntity.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.policy.loadbalancing; - -import java.util.Map; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.proxying.ImplementedBy; -import org.apache.brooklyn.api.event.AttributeSensor; - -import brooklyn.event.basic.Sensors; - -import com.google.common.reflect.TypeToken; - -@ImplementedBy(MockItemEntityImpl.class) -public interface MockItemEntity extends Entity, Movable { - - public static final AttributeSensor TEST_METRIC = Sensors.newIntegerSensor( - "test.metric", "Dummy workrate for test entities"); - - @SuppressWarnings("serial") - public static final AttributeSensor> ITEM_USAGE_METRIC = Sensors.newSensor( - new TypeToken>() {}, "test.itemUsage.metric", "Dummy item usage for test entities"); - - public boolean isStopped(); - - public void moveNonEffector(Entity rawDestination); - - public void stop(); -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d30ff597/policy/src/test/java/brooklyn/policy/loadbalancing/MockItemEntityImpl.java ---------------------------------------------------------------------- diff --git a/policy/src/test/java/brooklyn/policy/loadbalancing/MockItemEntityImpl.java b/policy/src/test/java/brooklyn/policy/loadbalancing/MockItemEntityImpl.java deleted file mode 100644 index ecc725e..0000000 --- a/policy/src/test/java/brooklyn/policy/loadbalancing/MockItemEntityImpl.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.policy.loadbalancing; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.event.AttributeSensor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.entity.basic.AbstractEntity; -import brooklyn.util.collections.MutableList; - - -public class MockItemEntityImpl extends AbstractEntity implements MockItemEntity { - - private static final Logger LOG = LoggerFactory.getLogger(MockItemEntityImpl.class); - - public static AtomicInteger totalMoveCount = new AtomicInteger(0); - - public static AtomicLong lastMoveTime = new AtomicLong(-1); - - private volatile boolean stopped; - private volatile MockContainerEntity currentContainer; - - private final ReentrantLock _lock = new ReentrantLock(); - - @Override - public String getContainerId() { - return (currentContainer == null) ? null : currentContainer.getId(); - } - - @Override - public boolean isStopped() { - return stopped; - } - - @Override - public T setAttribute(AttributeSensor attribute, T val) { - if (LOG.isDebugEnabled()) LOG.debug("Mocks: item {} setting {} to {}", new Object[] {this, attribute, val}); - return super.setAttribute(attribute, val); - } - - @Override - public void move(Entity destination) { - totalMoveCount.incrementAndGet(); - lastMoveTime.set(System.currentTimeMillis()); - moveNonEffector(destination); - } - - // only moves if the containers will accept us (otherwise we'd lose the item!) - @Override - public void moveNonEffector(Entity rawDestination) { - if (LOG.isDebugEnabled()) LOG.debug("Mocks: moving item {} from {} to {}", new Object[] {this, currentContainer, rawDestination}); - checkNotNull(rawDestination); - final MockContainerEntity previousContainer = currentContainer; - final MockContainerEntity destination = (MockContainerEntity) rawDestination; - - MockContainerEntityImpl.runWithLock(MutableList.of(previousContainer, destination), new Runnable() { - @Override public void run() { - _lock.lock(); - try { - if (stopped) throw new IllegalStateException("Item "+this+" is stopped; cannot move to "+destination); - if (currentContainer != null) currentContainer.removeItem(MockItemEntityImpl.this); - currentContainer = destination; - destination.addItem(MockItemEntityImpl.this); - setAttribute(CONTAINER, currentContainer); - } finally { - _lock.unlock(); - } - }}); - } - - @Override - public void stop() { - // FIXME How best to indicate this has been entirely stopped, rather than just in-transit? - if (LOG.isDebugEnabled()) LOG.debug("Mocks: stopping item {} (was in container {})", this, currentContainer); - _lock.lock(); - try { - if (currentContainer != null) currentContainer.removeItem(this); - currentContainer = null; - stopped = true; - } finally { - _lock.unlock(); - } - } - - @Override - public String toString() { - return "MockItem["+getDisplayName()+"]"; - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d30ff597/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyMetricTest.java ---------------------------------------------------------------------- diff --git a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyMetricTest.java b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyMetricTest.java new file mode 100644 index 0000000..83f7b33 --- /dev/null +++ b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyMetricTest.java @@ -0,0 +1,274 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.policy.autoscaling; + +import static org.apache.brooklyn.policy.autoscaling.AutoScalerPolicyTest.currentSizeAsserter; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.util.List; + +import org.apache.brooklyn.api.entity.proxying.EntitySpec; +import org.apache.brooklyn.api.event.AttributeSensor; +import org.apache.brooklyn.api.event.SensorEvent; +import org.apache.brooklyn.api.event.SensorEventListener; +import org.apache.brooklyn.test.entity.TestApplication; +import org.apache.brooklyn.test.entity.TestCluster; +import org.apache.brooklyn.test.entity.TestEntity; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import brooklyn.entity.basic.Entities; +import brooklyn.event.basic.BasicNotificationSensor; +import brooklyn.event.basic.Sensors; +import brooklyn.test.Asserts; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; + +public class AutoScalerPolicyMetricTest { + + private static long TIMEOUT_MS = 10000; + private static long SHORT_WAIT_MS = 50; + + private static final AttributeSensor MY_ATTRIBUTE = Sensors.newIntegerSensor("autoscaler.test.intAttrib"); + TestApplication app; + TestCluster tc; + + @BeforeMethod(alwaysRun=true) + public void before() { + app = TestApplication.Factory.newManagedInstanceForTests(); + tc = app.createAndManageChild(EntitySpec.create(TestCluster.class) + .configure("initialSize", 1)); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + if (app != null) Entities.destroyAll(app.getManagementContext()); + } + + @Test + public void testIncrementsSizeIffUpperBoundExceeded() { + tc.resize(1); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE).metricLowerBound(50).metricUpperBound(100).build(); + tc.addPolicy(policy); + + tc.setAttribute(MY_ATTRIBUTE, 100); + Asserts.succeedsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), currentSizeAsserter(tc, 1)); + + tc.setAttribute(MY_ATTRIBUTE, 101); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 2)); + } + + @Test + public void testDecrementsSizeIffLowerBoundExceeded() { + tc.resize(2); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE).metricLowerBound(50).metricUpperBound(100).build(); + tc.addPolicy(policy); + + tc.setAttribute(MY_ATTRIBUTE, 50); + Asserts.succeedsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), currentSizeAsserter(tc, 2)); + + tc.setAttribute(MY_ATTRIBUTE, 49); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 1)); + } + + @Test(groups="Integration") + public void testIncrementsSizeInProportionToMetric() { + tc.resize(5); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE).metricLowerBound(50).metricUpperBound(100).build(); + tc.addPolicy(policy); + + // workload 200 so requires doubling size to 10 to handle: (200*5)/100 = 10 + tc.setAttribute(MY_ATTRIBUTE, 200); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 10)); + + // workload 5, requires 1 entity: (10*110)/100 = 11 + tc.setAttribute(MY_ATTRIBUTE, 110); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 11)); + } + + @Test(groups="Integration") + public void testDecrementsSizeInProportionToMetric() { + tc.resize(5); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE).metricLowerBound(50).metricUpperBound(100).build(); + tc.addPolicy(policy); + + // workload can be handled by 4 servers, within its valid range: (49*5)/50 = 4.9 + tc.setAttribute(MY_ATTRIBUTE, 49); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 4)); + + // workload can be handled by 4 servers, within its valid range: (25*4)/50 = 2 + tc.setAttribute(MY_ATTRIBUTE, 25); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 2)); + + tc.setAttribute(MY_ATTRIBUTE, 0); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 1)); + } + + @Test(groups="Integration") + public void testObeysMinAndMaxSize() { + tc.resize(4); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .minPoolSize(2).maxPoolSize(6) + .build(); + tc.addPolicy(policy); + + // Decreases to min-size only + tc.setAttribute(MY_ATTRIBUTE, 0); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 2)); + + // Increases to max-size only + tc.setAttribute(MY_ATTRIBUTE, 100000); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 6)); + } + + @Test(groups="Integration",invocationCount=20) + public void testWarnsWhenMaxCapReached() { + final List maxReachedEvents = Lists.newCopyOnWriteArrayList(); + tc.resize(1); + + BasicNotificationSensor maxSizeReachedSensor = AutoScalerPolicy.DEFAULT_MAX_SIZE_REACHED_SENSOR; + + app.subscribe(tc, maxSizeReachedSensor, new SensorEventListener() { + @Override public void onEvent(SensorEvent event) { + maxReachedEvents.add(event.getValue()); + }}); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .maxPoolSize(6) + .maxSizeReachedSensor(maxSizeReachedSensor) + .build(); + tc.addPolicy(policy); + + // workload can be handled by 6 servers, so no need to notify: 6 <= (100*6)/50 + tc.setAttribute(MY_ATTRIBUTE, 600); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 6)); + assertTrue(maxReachedEvents.isEmpty()); + + // Increases to above max capacity: would require (100000*6)/100 = 6000 + tc.setAttribute(MY_ATTRIBUTE, 100000); + + // Assert our listener gets notified (once) + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() { + public void run() { + assertEquals(maxReachedEvents.size(), 1); + assertEquals(maxReachedEvents.get(0).getMaxAllowed(), 6); + assertEquals(maxReachedEvents.get(0).getCurrentPoolSize(), 6); + assertEquals(maxReachedEvents.get(0).getCurrentUnbounded(), 6000); + assertEquals(maxReachedEvents.get(0).getMaxUnbounded(), 6000); + assertEquals(maxReachedEvents.get(0).getTimeWindow(), 0); + }}); + Asserts.succeedsContinually(new Runnable() { + @Override public void run() { + assertEquals(maxReachedEvents.size(), 1); + }}); + currentSizeAsserter(tc, 6).run(); + } + + @Test + public void testDestructionState() { + tc.resize(1); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE).metricLowerBound(50).metricUpperBound(100).build(); + tc.addPolicy(policy); + + policy.destroy(); + assertTrue(policy.isDestroyed()); + assertFalse(policy.isRunning()); + + tc.setAttribute(MY_ATTRIBUTE, 100000); + Asserts.succeedsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), currentSizeAsserter(tc, 1)); + + // TODO Could assert all subscriptions have been de-registered as well, + // but that requires exposing more things just for testing... + } + + @Test + public void testSuspendState() { + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE).metricLowerBound(50).metricUpperBound(100).build(); + tc.addPolicy(policy); + + policy.suspend(); + assertFalse(policy.isRunning()); + assertFalse(policy.isDestroyed()); + + policy.resume(); + assertTrue(policy.isRunning()); + assertFalse(policy.isDestroyed()); + } + + @Test + public void testPostSuspendActions() { + tc.resize(1); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE).metricLowerBound(50).metricUpperBound(100).build(); + tc.addPolicy(policy); + + policy.suspend(); + + tc.setAttribute(MY_ATTRIBUTE, 100000); + Asserts.succeedsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), currentSizeAsserter(tc, 1)); + } + + @Test + public void testPostResumeActions() { + tc.resize(1); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE).metricLowerBound(50).metricUpperBound(100).build(); + tc.addPolicy(policy); + + policy.suspend(); + policy.resume(); + tc.setAttribute(MY_ATTRIBUTE, 101); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 2)); + } + + @Test + public void testSubscribesToMetricOnSpecifiedEntity() { + TestEntity entityWithMetric = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + + tc.resize(1); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder() + .metric(TestEntity.SEQUENCE) + .entityWithMetric(entityWithMetric) + .metricLowerBound(50) + .metricUpperBound(100) + .build(); + tc.addPolicy(policy); + + // First confirm that tc is not being listened to for this entity + tc.setAttribute(TestEntity.SEQUENCE, 101); + Asserts.succeedsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), currentSizeAsserter(tc, 1)); + + // Then confirm we listen to the correct "entityWithMetric" + entityWithMetric.setAttribute(TestEntity.SEQUENCE, 101); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 2)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d30ff597/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyRebindTest.java ---------------------------------------------------------------------- diff --git a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyRebindTest.java b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyRebindTest.java new file mode 100644 index 0000000..f8f200b --- /dev/null +++ b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyRebindTest.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.policy.autoscaling; + +import static org.testng.Assert.assertEquals; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.brooklyn.api.entity.proxying.EntitySpec; +import org.apache.brooklyn.api.event.AttributeSensor; +import org.apache.brooklyn.api.location.LocationSpec; +import org.apache.brooklyn.test.EntityTestUtils; +import org.apache.brooklyn.test.entity.TestApplication; +import org.apache.brooklyn.test.entity.TestEntity; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import brooklyn.entity.basic.EntityInternal; +import brooklyn.entity.group.DynamicCluster; +import brooklyn.entity.rebind.RebindTestFixtureWithApp; +import brooklyn.event.basic.BasicNotificationSensor; +import brooklyn.event.basic.Sensors; + +import org.apache.brooklyn.location.basic.SimulatedLocation; + +import brooklyn.util.time.Duration; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +public class AutoScalerPolicyRebindTest extends RebindTestFixtureWithApp { + + public static BasicNotificationSensor POOL_HOT_SENSOR = new BasicNotificationSensor( + Map.class, "AutoScalerPolicyRebindTest.resizablepool.hot", "Pool is over-utilized; it has insufficient resource for current workload"); + public static BasicNotificationSensor POOL_COLD_SENSOR = new BasicNotificationSensor( + Map.class, "AutoScalerPolicyRebindTest.resizablepool.cold", "Pool is under-utilized; it has too much resource for current workload"); + public static BasicNotificationSensor POOL_OK_SENSOR = new BasicNotificationSensor( + Map.class, "AutoScalerPolicyRebindTest.resizablepool.cold", "Pool utilization is ok; the available resources are fine for the current workload"); + public static BasicNotificationSensor MAX_SIZE_REACHED_SENSOR = new BasicNotificationSensor( + MaxPoolSizeReachedEvent.class, "AutoScalerPolicyRebindTest.maxSizeReached"); + public static AttributeSensor METRIC_SENSOR = Sensors.newIntegerSensor("AutoScalerPolicyRebindTest.metric"); + + private DynamicCluster origCluster; + private SimulatedLocation origLoc; + + @BeforeMethod(alwaysRun=true) + @Override + public void setUp() throws Exception { + super.setUp(); + origLoc = origManagementContext.getLocationManager().createLocation(LocationSpec.create(SimulatedLocation.class)); + origCluster = origApp.createAndManageChild(EntitySpec.create(DynamicCluster.class) + .configure("memberSpec", EntitySpec.create(TestEntity.class))); + } + + @Test + public void testRestoresAutoScalerConfig() throws Exception { + origCluster.addPolicy(AutoScalerPolicy.builder() + .name("myname") + .metric(METRIC_SENSOR) + .entityWithMetric(origCluster) + .metricUpperBound(1) + .metricLowerBound(2) + .minPoolSize(0) + .maxPoolSize(3) + .minPeriodBetweenExecs(Duration.of(4, TimeUnit.MILLISECONDS)) + .resizeUpStabilizationDelay(Duration.of(5, TimeUnit.MILLISECONDS)) + .resizeDownStabilizationDelay(Duration.of(6, TimeUnit.MILLISECONDS)) + .poolHotSensor(POOL_HOT_SENSOR) + .poolColdSensor(POOL_COLD_SENSOR) + .poolOkSensor(POOL_OK_SENSOR) + .maxSizeReachedSensor(MAX_SIZE_REACHED_SENSOR) + .maxReachedNotificationDelay(Duration.of(7, TimeUnit.MILLISECONDS)) + .buildSpec()); + + TestApplication newApp = rebind(); + DynamicCluster newCluster = (DynamicCluster) Iterables.getOnlyElement(newApp.getChildren()); + AutoScalerPolicy newPolicy = (AutoScalerPolicy) Iterables.getOnlyElement(newCluster.getPolicies()); + + assertEquals(newPolicy.getDisplayName(), "myname"); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.METRIC), METRIC_SENSOR); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.ENTITY_WITH_METRIC), newCluster); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.METRIC_UPPER_BOUND), 1); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.METRIC_LOWER_BOUND), 2); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.MIN_POOL_SIZE), (Integer)0); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.MAX_POOL_SIZE), (Integer)3); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.MIN_PERIOD_BETWEEN_EXECS), Duration.of(4, TimeUnit.MILLISECONDS)); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.RESIZE_UP_STABILIZATION_DELAY), Duration.of(5, TimeUnit.MILLISECONDS)); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.RESIZE_DOWN_STABILIZATION_DELAY), Duration.of(6, TimeUnit.MILLISECONDS)); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.POOL_HOT_SENSOR), POOL_HOT_SENSOR); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.POOL_COLD_SENSOR), POOL_COLD_SENSOR); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.POOL_OK_SENSOR), POOL_OK_SENSOR); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.MAX_SIZE_REACHED_SENSOR), MAX_SIZE_REACHED_SENSOR); + assertEquals(newPolicy.getConfig(AutoScalerPolicy.MAX_REACHED_NOTIFICATION_DELAY), Duration.of(7, TimeUnit.MILLISECONDS)); + } + + @Test + public void testAutoScalerResizesAfterRebind() throws Exception { + origCluster.start(ImmutableList.of(origLoc)); + origCluster.addPolicy(AutoScalerPolicy.builder() + .name("myname") + .metric(METRIC_SENSOR) + .entityWithMetric(origCluster) + .metricUpperBound(10) + .metricLowerBound(100) + .minPoolSize(1) + .maxPoolSize(3) + .buildSpec()); + + TestApplication newApp = rebind(); + DynamicCluster newCluster = (DynamicCluster) Iterables.getOnlyElement(newApp.getChildren()); + + assertEquals(newCluster.getCurrentSize(), (Integer)1); + + ((EntityInternal)newCluster).setAttribute(METRIC_SENSOR, 1000); + EntityTestUtils.assertGroupSizeEqualsEventually(newCluster, 3); + + ((EntityInternal)newCluster).setAttribute(METRIC_SENSOR, 1); + EntityTestUtils.assertGroupSizeEqualsEventually(newCluster, 1); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d30ff597/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyReconfigurationTest.java ---------------------------------------------------------------------- diff --git a/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyReconfigurationTest.java b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyReconfigurationTest.java new file mode 100644 index 0000000..f91adee --- /dev/null +++ b/policy/src/test/java/org/apache/brooklyn/policy/autoscaling/AutoScalerPolicyReconfigurationTest.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.policy.autoscaling; + +import static org.apache.brooklyn.policy.autoscaling.AutoScalerPolicyTest.currentSizeAsserter; + +import org.apache.brooklyn.api.entity.proxying.EntitySpec; +import org.apache.brooklyn.api.event.AttributeSensor; +import org.apache.brooklyn.test.entity.TestApplication; +import org.apache.brooklyn.test.entity.TestCluster; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import brooklyn.entity.basic.Entities; +import brooklyn.event.basic.Sensors; +import brooklyn.test.Asserts; +import brooklyn.util.time.Duration; + +import com.google.common.collect.ImmutableMap; + +public class AutoScalerPolicyReconfigurationTest { + + private static long TIMEOUT_MS = 10000; + + private static final AttributeSensor MY_ATTRIBUTE = Sensors.newIntegerSensor("autoscaler.test.intAttrib"); + TestApplication app; + TestCluster tc; + + @BeforeMethod(alwaysRun=true) + public void before() throws Exception { + app = TestApplication.Factory.newManagedInstanceForTests(); + tc = app.createAndManageChild(EntitySpec.create(TestCluster.class) + .configure("initialSize", 1)); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + if (app != null) Entities.destroyAll(app.getManagementContext()); + } + + @Test + public void testIncreaseMinPoolSizeCausesImmediateGrowth() { + tc.resize(2); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .minPoolSize(2) + .build(); + tc.addPolicy(policy); + + policy.config().set(AutoScalerPolicy.MIN_POOL_SIZE, 3); + + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 3)); + } + + @Test + public void testDecreaseMinPoolSizeAllowsSubsequentShrink() { + tc.resize(4); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .minPoolSize(2) + .build(); + tc.addPolicy(policy); + + // 25*4 = 100 -> 2 nodes at 50 each + tc.setAttribute(MY_ATTRIBUTE, 25); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 2)); + + // Decreases to new min-size + policy.config().set(AutoScalerPolicy.MIN_POOL_SIZE, 1); + tc.setAttribute(MY_ATTRIBUTE, 0); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 1)); + } + + @Test + public void testDecreaseMaxPoolSizeCausesImmediateShrink() { + tc.resize(6); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .maxPoolSize(6) + .build(); + tc.addPolicy(policy); + + policy.config().set(AutoScalerPolicy.MAX_POOL_SIZE, 4); + + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 4)); + } + + @Test + public void testIncreaseMaxPoolSizeAllowsSubsequentGrowth() { + tc.resize(3); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .maxPoolSize(6) + .build(); + tc.addPolicy(policy); + + // 200*3 = 600 -> 6 nodes at 100 each + tc.setAttribute(MY_ATTRIBUTE, 200); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 6)); + + policy.config().set(AutoScalerPolicy.MAX_POOL_SIZE, 8); + + // Increases to max-size only + tc.setAttribute(MY_ATTRIBUTE, 100000); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 8)); + } + + @Test + public void testReconfigureMetricLowerBound() { + tc.resize(2); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .build(); + tc.addPolicy(policy); + + policy.config().set(AutoScalerPolicy.METRIC_LOWER_BOUND, 51); + + tc.setAttribute(MY_ATTRIBUTE, 50); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 1)); + } + + @Test + public void testReconfigureMetricUpperBound() { + tc.resize(1); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .build(); + tc.addPolicy(policy); + + policy.config().set(AutoScalerPolicy.METRIC_UPPER_BOUND, 99); + + tc.setAttribute(MY_ATTRIBUTE, 100); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 2)); + } + + @Test + public void testReconfigureResizeUpStabilizationDelay() { + tc.resize(1); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .resizeUpStabilizationDelay(Duration.TWO_MINUTES) + .build(); + tc.addPolicy(policy); + + policy.config().set(AutoScalerPolicy.RESIZE_UP_STABILIZATION_DELAY, Duration.ZERO); + + tc.setAttribute(MY_ATTRIBUTE, 101); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 2)); + } + + @Test + public void testReconfigureResizeDownStabilizationDelay() { + tc.resize(2); + + AutoScalerPolicy policy = new AutoScalerPolicy.Builder().metric(MY_ATTRIBUTE) + .metricLowerBound(50).metricUpperBound(100) + .resizeDownStabilizationDelay(Duration.TWO_MINUTES) + .build(); + tc.addPolicy(policy); + + policy.config().set(AutoScalerPolicy.RESIZE_DOWN_STABILIZATION_DELAY, Duration.ZERO); + + tc.setAttribute(MY_ATTRIBUTE, 1); + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), currentSizeAsserter(tc, 1)); + } +}