/* * Copyright 2008 the original author or authors. * * Licensed 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.rioproject.impl.watch; import org.junit.Assert; import org.junit.Test; import org.rioproject.watch.Calculable; import org.rioproject.watch.ThresholdType; import org.rioproject.watch.ThresholdValues; import java.util.ArrayList; import java.util.List; /** * The class tests the <code>ThresholdWatch</code> part of a class derived from * <code>ThresholdWatch</code>. The class tests the public methods and fields * inherited by the class under test from <code>ThresholdWatch</code>, and also * the public constructors of the class under test. However, testing of the * constructors is actually delegated to <code>WatchTest</code>. Testing of the * methods and fields inherited from <code>Watch</code> is also delegated to * <code>WatchTest</code>. */ public class ThresholdWatchTest extends WatchTest { /** * The logger used by this class. * * @noinspection UNUSED_SYMBOL */ //private static Logger logger = LoggerFactory.getLogger("org.rioproject.watch"); /** * Constructs a <code>ThresholdWatchTest</code>. * * @param clazz the <code>ThresholdWatch</code>-derived class to be tested * @param expectedView the expected default return value of the * <code>getView()</code> method */ public ThresholdWatchTest(Class clazz, String expectedView) { super(clazz, expectedView); } /** * Tests the <code>getThresholdManager()</code> method. * * @throws Exception if the test fails */ @Test public void testGetThresholdManager() throws Exception { ThresholdWatch watch = (ThresholdWatch) construct1("watch"); ThresholdManager mgr = watch.getThresholdManager(); Assert.assertNotNull(mgr); Utils.close(watch.getWatchDataSource()); } /* * Tests the <code>addThresholdListener(ThresholdListener)</code> and * <code>removeThresholdListener(ThresholdListener)</code> methods. * * @throws Exception if the test fails */ @Test public void testAddRemoveThresholdListener() throws Exception { String id = "watch1"; ThresholdWatch watch = (ThresholdWatch) construct1(id); watch.setThresholdValues(new ThresholdValues(0, 1)); // Test adding multiple listeners, with several checkpoints final int[] checkpoints = new int[]{0, 1, 10, 100}; List<LoggingThresholdListener> lnrs = new ArrayList<LoggingThresholdListener>(); List<StringBuffer> logs = new ArrayList<StringBuffer>(); int count = 0; for (int checkpoint : checkpoints) { while (count < checkpoint) { StringBuffer log = new StringBuffer(); LoggingThresholdListener lnr = new LoggingThresholdListener(id, log); lnrs.add(lnr); logs.add(log); watch.addThresholdListener(lnr); count++; } watch.addWatchRecord(new Calculable(id, 0.5)); checkLogs(logs, ""); watch.addWatchRecord(new Calculable(id, -0.1)); checkLogs(logs, "breach(" + id + ",-0.1,0.0,1.0)"); watch.addWatchRecord(new Calculable(id, 1.1)); checkLogs(logs, "clear(" + id + ",1.1,0.0,1.0)" + "breach(" + id + ",1.1,0.0,1.0)"); watch.addWatchRecord(new Calculable(id, 0.5)); checkLogs(logs, "clear(" + id + ",0.5,0.0,1.0)"); } // Test adding the same listeners (should not change anything) for (LoggingThresholdListener lnr : lnrs) { watch.addThresholdListener(lnr); } watch.addWatchRecord(new Calculable(id, -0.1)); checkLogs(logs, "breach(" + id + ",-0.1,0.0,1.0)"); watch.addWatchRecord(new Calculable(id, 1.1)); checkLogs(logs, "clear(" + id + ",1.1,0.0,1.0)" + "breach(" + id + ",1.1,0.0,1.0)"); watch.addWatchRecord(new Calculable(id, 0.5)); checkLogs(logs, "clear(" + id + ",0.5,0.0,1.0)"); // Test removing listeners count = 0; for (int checkpoint : checkpoints) { while (count < checkpoint) { LoggingThresholdListener lnr = lnrs.get(count); watch.removeThresholdListener(lnr); count++; } List<StringBuffer> removedLogs = logs.subList(0, count); List<StringBuffer> remainingLogs = logs.subList(count, logs.size()); watch.addWatchRecord(new Calculable(id, 0.5)); checkLogs(removedLogs, ""); checkLogs(remainingLogs, ""); watch.addWatchRecord(new Calculable(id, -0.1)); checkLogs(removedLogs, ""); checkLogs(remainingLogs, "breach(" + id + ",-0.1,0.0,1.0)"); watch.addWatchRecord(new Calculable(id, 1.1)); checkLogs(removedLogs, ""); checkLogs(remainingLogs, "clear(" + id + ",1.1,0.0,1.0)" + "breach(" + id + ",1.1,0.0,1.0)"); watch.addWatchRecord(new Calculable(id, 0.5)); checkLogs(removedLogs, ""); checkLogs(remainingLogs, "clear(" + id + ",0.5,0.0,1.0)"); } // Test removing the same listeners (should not change anything) for (LoggingThresholdListener lnr : lnrs) { watch.removeThresholdListener(lnr); } watch.addWatchRecord(new Calculable(id, -0.1)); checkLogs(logs, ""); watch.addWatchRecord(new Calculable(id, 1.1)); checkLogs(logs, ""); watch.addWatchRecord(new Calculable(id, 0.5)); checkLogs(logs, ""); // Test adding 1, 10, and 100 listeners again count = 0; for (int checkpoint : checkpoints) { while (count < checkpoint) { LoggingThresholdListener lnr = lnrs.get(count); watch.addThresholdListener(lnr); count++; } List<StringBuffer> addedLogs = logs.subList(0, count); List<StringBuffer> remainingLogs = logs.subList(count, logs.size()); watch.addWatchRecord(new Calculable(id, 0.5)); checkLogs(addedLogs, ""); checkLogs(remainingLogs, ""); watch.addWatchRecord(new Calculable(id, -0.1)); checkLogs(addedLogs, "breach(" + id + ",-0.1,0.0,1.0)"); checkLogs(remainingLogs, ""); watch.addWatchRecord(new Calculable(id, 1.1)); checkLogs(addedLogs, "clear(" + id + ",1.1,0.0,1.0)" + "breach(" + id + ",1.1,0.0,1.0)"); checkLogs(remainingLogs, ""); watch.addWatchRecord(new Calculable(id, 0.5)); checkLogs(addedLogs, "clear(" + id + ",0.5,0.0,1.0)"); checkLogs(remainingLogs, ""); } // Test adding illegal listener try { watch.addThresholdListener(null); Assert.fail("IllegalArgumentException expected but not thrown"); } catch (IllegalArgumentException e) { } // Test removing illegal listener try { watch.removeThresholdListener(null); Assert.fail("IllegalArgumentException expected but not thrown"); } catch (IllegalArgumentException e) { } Utils.close(watch.getWatchDataSource()); } /** * Tests adding a threshold listener after one or more threshold events have * occurred. * * @throws Exception if the test fails */ @Test public void testAddThresholdListenerAfterEvent() throws Exception { String id = "watch"; ThresholdWatch watch = (ThresholdWatch) construct1(id); watch.setThresholdValues(new ThresholdValues(0, 1)); StringBuffer log = new StringBuffer(); LoggingThresholdListener lnr = new LoggingThresholdListener(id, log); watch.addWatchRecord(new Calculable(id, 0.5)); watch.addWatchRecord(new Calculable(id, -0.1)); watch.addWatchRecord(new Calculable(id, 1.1)); watch.addThresholdListener(lnr); Assert.assertEquals("", log.toString()); watch.addWatchRecord(new Calculable(id, 0.5)); Assert.assertEquals("clear(" + id + ",0.5,0.0,1.0)", log.toString()); Utils.close(watch.getWatchDataSource()); } /** * Tests the <code>getThresholdValues()</code> and <code>setThresholdValues(ThresholdValues)</code> * methods. * * @throws Exception if the test fails */ @Test public void testGetSetThresholdValues() throws Exception { // Getting default value String id = "watch"; ThresholdWatch watch = (ThresholdWatch) construct1(id); ThresholdValues values = watch.getThresholdValues(); Assert.assertTrue(Double.isNaN(values.getLowThreshold())); Assert.assertTrue(Double.isNaN(values.getHighThreshold())); // "set" followed by "get" ThresholdValues newValues = new ThresholdValues(7.13, 13.7); watch.setThresholdValues(newValues); values = watch.getThresholdValues(); Assert.assertEquals(newValues.getLowThreshold(), values.getLowThreshold(), 0); Assert.assertEquals(newValues.getHighThreshold(), values.getHighThreshold(), 0); // Check that the watch holds the same object (at the time // of writing this test it does) Assert.assertSame(newValues, values); // Setting illegal value try { watch.setThresholdValues(null); Assert.fail("IllegalArgumentException expected but not thrown"); } catch (IllegalArgumentException e) { } Utils.close(watch.getWatchDataSource()); } /** * Verifies that <code>ThresholdWatch</code> generates threshold events * correctly. The following combinations are tested: <ul> <li>None of the * thresholds is set <li>The lower threshold is set <li>The upper threshold * is set <li>Both thresholds are set </ul> * * @throws Exception if the test fails */ @Test public void testThresholdEvents() throws Exception { testThresholdEvents(NO_THRESHOLDS); testThresholdEvents(LOWER_THRESHOLD); testThresholdEvents(UPPER_THRESHOLD); testThresholdEvents(BOTH_THRESHOLDS); } /** * None of the thresholds is set. */ private static final int NO_THRESHOLDS = 0x0; /** * The lower threshold is set. */ private static final int LOWER_THRESHOLD = 0x1; /** * The upper threshold is set */ private static final int UPPER_THRESHOLD = 0x2; /** * Both thresholds are set. */ private static final int BOTH_THRESHOLDS = 0x3; /* * Verifies that <code>ThresholdWatch</code> generates threshold events * correctly for a given combination of thresholds. */ private void testThresholdEvents(int thresholds) throws Exception { String id = "w"; ThresholdWatch watch = (ThresholdWatch) construct1(id); StringBuffer log = new StringBuffer(); LoggingThresholdListener lnr = new LoggingThresholdListener(id, log); watch.addThresholdListener(lnr); boolean lower = (thresholds & LOWER_THRESHOLD) != 0; boolean upper = (thresholds & UPPER_THRESHOLD) != 0; // logger.info("Lower threshold [" + lower + "]" // + ", upper threshold [" + upper + "]"); double lowerTh = Double.NaN; double upperTh = Double.NaN; if (lower) { lowerTh = -1; } if (upper) { upperTh = 1; } ThresholdValues thValues = new ThresholdValues(lowerTh, upperTh); watch.setThresholdValues(thValues); String suffix = "," + thValues.getLowThreshold() + "," + thValues.getHighThreshold() + ")"; // The idea is to test the most important situations watch.addWatchRecord(new Calculable(id, 0)); // 0 checkLog(log, ""); watch.addWatchRecord(new Calculable(id, -1)); // -1 checkLog(log, ""); watch.addWatchRecord(new Calculable(id, -1.1)); // -1.1 checkLog(log, lower ? "breach(w,-1.1" + suffix : ""); watch.addWatchRecord(new Calculable(id, -1)); // -1 checkLog(log, ""); watch.addWatchRecord(new Calculable(id, 0)); // 0 checkLog(log, lower ? "clear(w,0.0" + suffix : ""); watch.addWatchRecord(new Calculable(id, -1.1)); // -1.1 checkLog(log, lower ? "breach(w,-1.1" + suffix : ""); watch.addWatchRecord(new Calculable(id, 1.1)); // 1.1 if (lower & upper) { checkLog(log, "clear(w,1.1" + suffix + "breach(w,1.1" + suffix); } else if (lower) { checkLog(log, "clear(w,1.1" + suffix); } else if (upper) { checkLog(log, "breach(w,1.1" + suffix); } else { checkLog(log, ""); } watch.addWatchRecord(new Calculable(id, 0)); // 0 checkLog(log, upper ? "clear(w,0.0" + suffix : ""); // The other way around watch.addWatchRecord(new Calculable(id, 1)); // 1 checkLog(log, ""); watch.addWatchRecord(new Calculable(id, 1.1)); // 1.1 checkLog(log, upper ? "breach(w,1.1" + suffix : ""); watch.addWatchRecord(new Calculable(id, 1)); // 1 checkLog(log, ""); watch.addWatchRecord(new Calculable(id, 0)); // 0 checkLog(log, upper ? "clear(w,0.0" + suffix : ""); watch.addWatchRecord(new Calculable(id, 1.1)); // 1.1 checkLog(log, upper ? "breach(w,1.1" + suffix : ""); watch.addWatchRecord(new Calculable(id, -1.1)); // -1.1 if (lower & upper) { checkLog(log, "clear(w,-1.1" + suffix + "breach(w,-1.1" + suffix); } else if (upper) { checkLog(log, "clear(w,-1.1" + suffix); } else if (lower) { checkLog(log, "breach(w,-1.1" + suffix); } else { checkLog(log, ""); } watch.addWatchRecord(new Calculable(id, 0)); // 0 checkLog(log, lower ? "clear(w,0.0" + suffix : ""); Utils.close(watch.getWatchDataSource()); } /** * The class provides a mock implementation of the <code>ThresholdListener</code> * interface. The main function of the class is to receive threshold events * and log them into a string buffer. */ private class LoggingThresholdListener implements ThresholdListener { private String id; StringBuffer log; public LoggingThresholdListener(String id, StringBuffer log) { this.id = id; this.log = log; } public void notify(Calculable calculable, ThresholdValues thresholdValues, ThresholdType type) { /*String status = (type == ThresholdEvent.BREACHED ? "breached" : "cleared"); System.out.println( "Threshold [" + calculable.getId() + "] " + status + " " + "value [" + calculable.getValue() + "] " + "low [" + thresholdValues.getCurrentLowThreshold() + "] " + "high [" + thresholdValues.getCurrentHighThreshold() + "]");*/ StringBuilder buf = new StringBuilder(); buf.append(type == ThresholdType.BREACHED ? "breach(" : "clear("); buf.append(calculable.getId()).append(","); buf.append(calculable.getValue()).append(","); buf.append(thresholdValues.getLowThreshold()).append(","); buf.append(thresholdValues.getHighThreshold()); buf.append(")"); log.append(buf); } public String getID() { return id; } } /* * Checks that a given log consists of a given string, and clears the log. */ private void checkLog(StringBuffer log, String s) { Assert.assertEquals(s, log.toString()); log.delete(0, log.length()); } /* * Checks that each log in a given list consists of a given string, and * clears each log. */ private void checkLogs(List<StringBuffer> logs, String s) { for (StringBuffer log : logs) { checkLog(log, s); } } }