/* * Copyright (C) 2012 Facebook, Inc. * * 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 com.facebook.stats.mx; import com.google.common.collect.ImmutableMap; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; public class TestStats { private static final String NOT_INSERTED_KEY = "not Inserted"; private static final String KEY1 = "key1"; private static final String KEY2 = "key2"; private static final String KEY3 = "key3"; private static final String ZERO_COUNTER = "to-0-counter"; private static final String COUNTER_TO_SET = "count-to-set"; private static final String COUNTER_NOT_SET = "counter-not-set"; private Map<String, String> attributeMap = new ImmutableMap.Builder<String, String>() .put(KEY1, KEY2) .put(KEY2, KEY3) .put(KEY3, KEY1) .build(); private Stats stats; @BeforeMethod(alwaysRun = true) void setup() { stats = new Stats(); } public void verifyStatAttributes() { // Test out getAttribute calls Assert.assertEquals(stats.getAttribute(KEY1), KEY2); Assert.assertEquals(stats.getAttribute(KEY2), KEY3); Assert.assertEquals(stats.getAttribute(KEY3), KEY1); Assert.assertNull(stats.getAttribute(NOT_INSERTED_KEY)); stats.setAttribute(KEY1, KEY1); Assert.assertEquals(stats.getAttribute(KEY1), KEY1); stats.setAttribute(KEY1, KEY2); // Test out that the stats attributemap is as expected Map<String, String> statsAttributes = stats.getAttributes(); Assert.assertEquals(attributeMap, statsAttributes); } /** * Test the setAttribute(String, String) function */ @Test(groups = "fast") public void testAttributeString() { for (Map.Entry<String, String> attribute : attributeMap.entrySet()) { stats.setAttribute(attribute.getKey(), attribute.getValue()); } verifyStatAttributes(); } /** * Test the setAttribute(String, Callable <String> ) function */ @Test(groups = "fast") public void testAttributeCallable() { for (final String key: attributeMap.keySet()) { stats.setAttribute(key, new Callable<String>() { @Override public String call() throws Exception { return TestStats.this.attributeMap.get(key); } }); } verifyStatAttributes(); } @Test(groups = "fast") public void testGetEmptyCounter() throws Exception { Assert.assertEquals(stats.getCounter("fuu"), 0); } @Test(groups = "fast") public void testRemoveCounter() throws Exception { stats.incrementCounter("fuu", 1); Assert.assertTrue(stats.removeCounter("fuu")); Assert.assertFalse(stats.removeCounter("fuu")); Map<String, Long> counterMap = new HashMap<>(); stats.exportCounters(counterMap); Assert.assertNull(counterMap.get("fuu")); } @Test(groups = "fast") public void testRemoveAttribute() throws Exception { stats.setAttribute("bar", "bar"); Assert.assertTrue(stats.removeAttribute("bar")); Assert.assertFalse(stats.removeAttribute("bar")); Assert.assertNull(stats.getAttributes().get("bar")); } @Test(groups = "fast") public void testDynamicCounters() throws Exception { LongWrapper longValue = new LongWrapper(1); final String name = "testCounter"; Assert.assertTrue(stats.addDynamicCounter(name, longValue)); final Map<String, Long> exported = new HashMap<>(); stats.exportCounters(exported); Assert.assertEquals(exported.get(name), Long.valueOf(1)); // Test that the value gets exported longValue.setValue(123); exported.clear(); stats.exportCounters(exported); Assert.assertEquals(exported.get(name), Long.valueOf(123)); Assert.assertEquals(stats.getCounter(name), 123L); // Test that a duplicate set fails to override the previous value LongWrapper duplicateValue = new LongWrapper(24); Assert.assertFalse(stats.addDynamicCounter(name, duplicateValue)); exported.clear(); stats.exportCounters(exported); Assert.assertEquals(exported.get(name), Long.valueOf(123)); Assert.assertEquals(stats.getCounter(name), 123L); // Test unset Assert.assertTrue(stats.removeCounter(name)); exported.clear(); stats.exportCounters(exported); Assert.assertFalse(exported.containsKey(name)); Assert.assertEquals(stats.getCounter(name), 0L); // Test unset for non-existent key Assert.assertFalse(stats.removeAttribute(name)); } @Test(groups = "fast") public void testGetDynamicCounters() throws Exception { LongWrapper longValue = new LongWrapper(1); final String name = "testCounter"; Assert.assertTrue(stats.addDynamicCounter(name, longValue)); Callable<Long> dynamicCounter = stats.getDynamicCounter(name); Assert.assertEquals(dynamicCounter.call().longValue(), 1); } @Test(groups = "fast") public void testSetCounterValue() throws Exception { stats.incrementCounter(COUNTER_TO_SET, 2); stats.incrementCounter(COUNTER_TO_SET, 20); stats.incrementCounter(COUNTER_TO_SET, 200); Assert.assertEquals(stats.getCounter(COUNTER_TO_SET), 222); Assert.assertEquals(StatsUtil.setCounterValue(COUNTER_TO_SET, 1001, stats), 222); Assert.assertEquals(stats.getCounter(COUNTER_TO_SET), 1001); } @Test(groups = "fast") public void testReset() throws Exception { Assert.assertEquals(stats.getCounter(ZERO_COUNTER), 0); stats.incrementCounter(ZERO_COUNTER, 1); stats.incrementCounter(ZERO_COUNTER, 10); stats.incrementCounter(ZERO_COUNTER, 100); Assert.assertEquals(stats.resetCounter(ZERO_COUNTER), 111); Assert.assertEquals(stats.getCounter(ZERO_COUNTER), 0); } @Test(groups = "fast") public void testResetBeforeCallingIncrementOrGet() { stats.resetCounter(COUNTER_NOT_SET); Assert.assertEquals(stats.getCounter(COUNTER_NOT_SET), 0); } /** * Helper class for testing dynamic counters. */ private static class LongWrapper implements Callable<Long> { private long value; private LongWrapper(long value) { this.value = value; } public void setValue(long value) { this.value = value; } @Override public Long call() throws Exception { return value; } } }