/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.bigdata.rdf.sail.webapp.lbs; import java.util.Random; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import junit.framework.TestCase2; import com.bigdata.BigdataStatics; import com.bigdata.util.httpd.Config; /** * Test suite for the basic stochastic load balancing mechanism for LBS policies * based on actual host workloads regardless of how those workload metrics are * obtained. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * * TODO Test load balancing for no hosts, one host (with 1 service, 2 * services, 3 services) and 3 hosts (each with one service). Also test * cases where some hosts have no active services, e.g., 3 hosts but * only one is active or 3 hosts but only 2 are active. */ public class TestAbstractHostLBSPolicy extends TestCase2 { private AtomicInteger nextPort; @Override protected void setUp() throws Exception { nextPort = new AtomicInteger(Config.BLAZEGRAPH_HTTP_PORT); } @Override protected void tearDown() throws Exception { super.tearDown(); nextPort = null; } public TestAbstractHostLBSPolicy() { } public TestAbstractHostLBSPolicy(String name) { super(name); } /** * This test covers the case where there is only one host and it is running * one or more services. */ public void test_lbs_host_policy() { // The hostnames. final String H1 = "H1"; // The load scores for those hosts. final HostScore hostScore1 = new HostScore("H1", 1d); // should sum to 1.0 assertEquals(1d, hostScore1.getAvailability()); final HostScore[] hostScores = new HostScore[] { // hostScore1 // }; { final HostScore actualHost = AbstractHostLBSPolicy.getHost(.0, hostScores); // Only one host. assertSameRef(hostScore1, actualHost); } { final HostScore actualHost = AbstractHostLBSPolicy.getHost(.1, hostScores); // Only one host. assertSameRef(hostScore1, actualHost); } { final HostScore actualHost = AbstractHostLBSPolicy.getHost(.5, hostScores); // Only one host. assertSameRef(hostScore1, actualHost); } { final HostScore actualHost = AbstractHostLBSPolicy.getHost(.9, hostScores); // Only one host. assertSameRef(hostScore1, actualHost); } { try { AbstractHostLBSPolicy.getHost(1d, hostScores); } catch (IllegalArgumentException ex) { // ignore. if (log.isInfoEnabled()) log.info(ex); } } { try { AbstractHostLBSPolicy.getHost(-.00001d, hostScores); } catch (IllegalArgumentException ex) { // ignore. if (log.isInfoEnabled()) log.info(ex); } } // The services. final UUID A = UUID.randomUUID(); final UUID B = UUID.randomUUID(); final UUID C = UUID.randomUUID(); final ServiceScore serviceA = new ServiceScore(A, H1, toRequestURI(H1)); final ServiceScore serviceB = new ServiceScore(B, H1, toRequestURI(H1)); final ServiceScore serviceC = new ServiceScore(C, H1, toRequestURI(H1)); /* * Now check the method to identify a specific joined service known to * be running on that host. */ { { // Run with a known seed. final Random rand = new Random(1L); final ServiceScore[] serviceScores = new ServiceScore[] { // serviceA // }; final ServiceScore actualService = AbstractHostLBSPolicy .getService(rand, hostScore1, serviceScores); assertTrue(actualService == serviceA); } { // Run with a known seed. final Random rand = new Random(1L); final ServiceScore[] serviceScores = new ServiceScore[] { // serviceA, serviceB, serviceC }; final ServiceScore actualService = AbstractHostLBSPolicy .getService(rand, hostScore1, serviceScores); assertTrue(actualService == serviceA); } } } /** * This test covers the case with 3 hosts, each running one service. */ public void test_HA3() { // // /* // * The load scores for those hosts. // * // * Note: These need to be ordered by increasing load. That is how they // * are sorted by the LBS code. The running totals in terms of the // * normalized load. // */ // final double totalRawScore = 1.5d; // final HostScore hostScore0 = new HostScore("H0", .2d); // score=.533 // final HostScore hostScore1 = new HostScore("H1", .5d); // score=.333, total=.866 // final HostScore hostScore2 = new HostScore("H2", .8d); // score=.133, total=1.00 // // /* // * Show scores. Decision is made on the *normalized* score. Since we // * want to assign work based on inverse load, "normalized" is defined as // * (1-load)/total // */ // log.warn("H1=" + hostScore0); // log.warn("H2=" + hostScore1); // log.warn("H3=" + hostScore2); // // // verify total of the raw scores. // assertEquals(totalRawScore, hostScore0.getRawScore() + hostScore1.getRawScore() // + hostScore2.getRawScore()); // // // verify individual normalized scores. // assertEquals(hostScore0.getScore(), (1d-hostScore0.getRawScore()) / totalRawScore); // assertEquals(hostScore1.getScore(), (1d-hostScore1.getRawScore()) / totalRawScore); // assertEquals(hostScore2.getScore(), (1d-hostScore2.getRawScore()) / totalRawScore); // // // verify total of the normalized scores. // assertEquals(1d, hostScore0.getScore() + hostScore1.getScore() + hostScore2.getScore()); // // // Arrange host scores in some perturbed order. // final HostScore[] hostScores = new HostScore[] { hostScore2, // hostScore0, hostScore1 }; // // // Sort by increasing normalized score (decreasing free capacity). // Arrays.sort(hostScores); // // log.warn("hostScores[0]=" + hostScores[0]); // log.warn("hostScores[1]=" + hostScores[1]); // log.warn("hostScores[2]=" + hostScores[2]); // // // verify imposed ordering on (1-load). // assertSameRef(hostScores[2], hostScore0); // most load (1-load = .533) // assertSameRef(hostScores[1], hostScore1); // middle load (1-load = .333) // assertSameRef(hostScores[0], hostScore2); // least load (1-load = .133) // // // Verify ordering (increasing normalized score). // assertTrue(hostScores[0].getScore() < hostScores[1].getScore()); // assertTrue(hostScores[1].getScore() < hostScores[2].getScore()); // // final double threshold0 = 0d; // final double threshold1 = hostScores[0].getScore(); // final double threshold2 = threshold1 + hostScores[1].getScore(); // log.warn("threshold0=" + threshold0); // log.warn("threshold1=" + threshold1); // log.warn("threshold2=" + threshold2); // // { // final HostScore actualHost = AbstractHostLBSPolicy.getHost( // threshold0, hostScores); // // assertSameRef(hostScores[0], actualHost); // } // // { // final HostScore actualHost = AbstractHostLBSPolicy.getHost( // (threshold1 - .001), hostScores); // // assertSameRef(hostScores[0], actualHost); // } // // { // final HostScore actualHost = AbstractHostLBSPolicy.getHost( // threshold1, hostScores); // // assertSameRef(hostScores[1], actualHost); // } // // { // final HostScore actualHost = AbstractHostLBSPolicy.getHost( // (threshold2 - .001), hostScores); // // assertSameRef(hostScores[1], actualHost); // } // // { // final HostScore actualHost = AbstractHostLBSPolicy.getHost( // threshold2, hostScores); // // assertSameRef(hostScores[2], actualHost); // } // // { // final HostScore actualHost = AbstractHostLBSPolicy.getHost( // 1d - .0001, hostScores); // // assertSameRef(hostScores[2], actualHost); // } // // { // try { // AbstractHostLBSPolicy.getHost(1d, hostScores); // } catch (IllegalArgumentException ex) { // // ignore. // if (log.isInfoEnabled()) // log.info(ex); // } // } // // { // try { // AbstractHostLBSPolicy.getHost(-.00001d, hostScores); // } catch (IllegalArgumentException ex) { // // ignore. // if (log.isInfoEnabled()) // log.info(ex); // } // } // // // The services. // final UUID A = UUID.randomUUID(); // final UUID B = UUID.randomUUID(); // final UUID C = UUID.randomUUID(); // // final ServiceScore serviceA = new ServiceScore(A, hostScore0.getHostname(), toRequestURI(hostScore0.getHostname())); // final ServiceScore serviceB = new ServiceScore(B, hostScore1.getHostname(), toRequestURI(hostScore1.getHostname())); // final ServiceScore serviceC = new ServiceScore(C, hostScore2.getHostname(), toRequestURI(hostScore2.getHostname())); // // /* // * Now check the method to identify a specific joined service known to // * be running on that host. // */ // { // { // // // Run with a known seed. // final Random rand = new Random(1L); // // final ServiceScore[] serviceScores = new ServiceScore[] { // // serviceA // // }; // // final ServiceScore actualService = AbstractHostLBSPolicy // .getService(rand, hostScore0, serviceScores); // // assertTrue(actualService == serviceA); // // } // // { // // // Run with a known seed. // final Random rand = new Random(1L); // // final ServiceScore[] serviceScores = new ServiceScore[] { // // serviceA, serviceB, serviceC // }; // // final ServiceScore actualService = AbstractHostLBSPolicy // .getService(rand, hostScore0, serviceScores); // // assertTrue(actualService == serviceA); // // } // // } } /** * Verify that two references are the same reference (<code>==</code>). * * @param expected * The expected reference. * @param actual * The actual reference. */ private <T> void assertSameRef(final T expected, final T actual) { if (expected != actual) { fail("Different reference: expected=" + expected + ", actual=" + actual); } } /** * Hacks together a Request-URI for a service. * * @param hostname * @return */ private String toRequestURI(final String hostname) { return "http://" + hostname + ":" + nextPort.getAndIncrement() + BigdataStatics.getContextPath(); } }