/** * The MIT License * Copyright © 2010 JmxTrans team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.googlecode.jmxtrans.model.output; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.inject.Injector; import com.googlecode.jmxtrans.cli.JmxTransConfiguration; import com.googlecode.jmxtrans.guice.JmxTransModule; import com.googlecode.jmxtrans.model.JmxProcess; import com.googlecode.jmxtrans.model.Result; import com.googlecode.jmxtrans.model.ResultAttribute; import com.googlecode.jmxtrans.util.JsonUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.WordUtils; import org.influxdb.InfluxDB; import org.influxdb.InfluxDB.ConsistencyLevel; import org.influxdb.dto.BatchPoints; import org.influxdb.dto.Point; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.TreeMap; import static com.google.common.collect.Sets.immutableEnumSet; import static com.googlecode.jmxtrans.model.QueryFixtures.dummyQuery; import static com.googlecode.jmxtrans.model.ServerFixtures.dummyServer; import static com.googlecode.jmxtrans.model.output.InfluxDbWriter.TAG_HOSTNAME; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; /** * Tests for {@link InfluxDbWriter}. * * @author <a href="https://github.com/sihutch">github.com/sihutch</a> */ @RunWith(MockitoJUnitRunner.class) public class InfluxDbWriterTests { private static final String DATABASE_NAME = "database"; private static final String HOST = "host.example.net"; private static final ImmutableMap<String, String> DEFAULT_CUSTOM_TAGS = ImmutableMap.of(); private static final ImmutableList<String> DEFAULT_TYPE_NAMES = ImmutableList.of(); @Mock private InfluxDB influxDB; @Captor private ArgumentCaptor<BatchPoints> messageCaptor; private static final ConsistencyLevel DEFAULT_CONSISTENCY_LEVEL = ConsistencyLevel.ALL; private static final String DEFAULT_RETENTION_POLICY = "default"; private static final ImmutableSet<ResultAttribute> DEFAULT_RESULT_ATTRIBUTES = immutableEnumSet(EnumSet.allOf(ResultAttribute.class)); Result result = new Result(2l, "attributeName", "className", "objDomain", "keyAlias", "type=test,name=name", ImmutableMap.of("key", (Object) 1)); ImmutableList<Result> results = ImmutableList.of(result); @Test public void pointsAreWrittenToInfluxDb() throws Exception { InfluxDbWriter writer = getTestInfluxDbWriterWithDefaultSettings(); writer.doWrite(dummyServer(), dummyQuery(), results); verify(influxDB).write(messageCaptor.capture()); BatchPoints batchPoints = messageCaptor.getValue(); assertThat(batchPoints.getDatabase()).isEqualTo(DATABASE_NAME); // Point only exposes its state via a line protocol so we have to // make assertions against this. // Format is: // measurement,<comma separated key=val tags>" " <comma separated // key=val fields> Map<String, String> expectedTags = new TreeMap<String, String>(); expectedTags.put(enumValueToAttribute(ResultAttribute.ATTRIBUTE_NAME), result.getAttributeName()); expectedTags.put(enumValueToAttribute(ResultAttribute.CLASS_NAME), result.getClassName()); expectedTags.put(enumValueToAttribute(ResultAttribute.OBJ_DOMAIN), result.getObjDomain()); expectedTags.put(TAG_HOSTNAME, HOST); String lineProtocol = buildLineProtocol(result.getKeyAlias(), expectedTags); List<Point> points = batchPoints.getPoints(); assertThat(points).hasSize(1); Point point = points.get(0); assertThat(point.lineProtocol()).startsWith(lineProtocol); } @Test public void emptyCustomTagsDoesntBotherWrite() throws Exception { InfluxDbWriter writer = getTestInfluxDbWriterWithDefaultSettings(); writer.doWrite(dummyServer(), dummyQuery(), results); verify(influxDB).write(messageCaptor.capture()); BatchPoints batchPoints = messageCaptor.getValue(); assertThat(batchPoints.getDatabase()).isEqualTo(DATABASE_NAME); List<Point> points = batchPoints.getPoints(); assertThat(points).hasSize(1); } @Test public void customTagsAreWrittenToDb() throws Exception { ImmutableMap<String, String> tags = ImmutableMap.of("customTag", "customValue"); InfluxDbWriter writer = getTestInfluxDbWriterWithCustomTags(tags); writer.doWrite(dummyServer(), dummyQuery(), results); verify(influxDB).write(messageCaptor.capture()); BatchPoints batchPoints = messageCaptor.getValue(); assertThat(batchPoints.getDatabase()).isEqualTo(DATABASE_NAME); List<Point> points = batchPoints.getPoints(); assertThat(points).hasSize(1); Point point = points.get(0); assertThat(point.lineProtocol()).contains("customTag=customValue"); } @Test public void attributeNameIncludesTypeNames() throws Exception { ImmutableList<String> typeNames = ImmutableList.of("name"); InfluxDbWriter writer = getTestInfluxDbWriterWithTypeNames(typeNames); writer.doWrite(dummyServer(), dummyQuery(), results); verify(influxDB).write(messageCaptor.capture()); BatchPoints batchPoints = messageCaptor.getValue(); assertThat(batchPoints.getDatabase()).isEqualTo(DATABASE_NAME); List<Point> points = batchPoints.getPoints(); assertThat(points).hasSize(1); Point point = points.get(0); assertThat(point.lineProtocol()).contains("name.key"); } @Test public void writeConsistencyLevelsAreAppliedToBatchPointsBeingWritten() throws Exception { for (ConsistencyLevel consistencyLevel : ConsistencyLevel.values()) { InfluxDbWriter writer = getTestInfluxDbWriterWithWriteConsistency(consistencyLevel); writer.doWrite(dummyServer(), dummyQuery(), results); verify(influxDB, atLeastOnce()).write(messageCaptor.capture()); BatchPoints batchPoints = messageCaptor.getValue(); assertThat(batchPoints.getConsistency()).isEqualTo(consistencyLevel); } } @Test public void onlyRequestedResultPropertiesAreAppliedAsTags() throws Exception { for (ResultAttribute expectedResultTag : ResultAttribute.values()) { ImmutableSet<ResultAttribute> expectedResultTags = ImmutableSet.of(expectedResultTag); InfluxDbWriter writer = getTestInfluxDbWriterWithResultTags(expectedResultTags); writer.doWrite(dummyServer(), dummyQuery(), results); verify(influxDB, atLeastOnce()).write(messageCaptor.capture()); BatchPoints batchPoints = messageCaptor.getValue(); String lineProtocol = batchPoints.getPoints().get(0).lineProtocol(); assertThat(lineProtocol).contains(enumValueToAttribute(expectedResultTag)); EnumSet<ResultAttribute> unexpectedResultTags = EnumSet.complementOf(EnumSet.of(expectedResultTag)); for (ResultAttribute unexpectedResultTag : unexpectedResultTags) { assertThat(lineProtocol).doesNotContain(enumValueToAttribute(unexpectedResultTag)); } } } @Test public void databaseIsCreated() throws Exception { InfluxDbWriter writer = getTestInfluxDbWriterWithDefaultSettings(); writer.doWrite(dummyServer(), dummyQuery(), results); verify(influxDB).createDatabase(DATABASE_NAME); } @Test public void databaseIsNotCreated() throws Exception { InfluxDbWriter writer = getTestInfluxDbWriterNoDatabaseCreation(); writer.doWrite(dummyServer(), dummyQuery(), results); verify(influxDB, never()).createDatabase(anyString()); } @Test public void loadingFromFile() throws URISyntaxException, IOException { File input = new File(InfluxDbWriterTests.class.getResource("/influxDB.json").toURI()); Injector injector = JmxTransModule.createInjector(new JmxTransConfiguration()); JsonUtils jsonUtils = injector.getInstance(JsonUtils.class); JmxProcess process = jsonUtils.parseProcess(input); assertThat(process.getName()).isEqualTo("influxDB.json"); } private String buildLineProtocol(String measurement, Map<String, String> expectedTags) { StringBuilder sb = new StringBuilder(measurement).append(","); int loops = 0; int tagCount = expectedTags.size(); for (Map.Entry<String, String> entry : expectedTags.entrySet()) { loops++; sb.append(entry.getKey()).append("=").append(entry.getValue()); if (loops < tagCount) { sb.append(","); } } return sb.toString(); } private InfluxDbWriter getTestInfluxDbWriterWithDefaultSettings() { return getTestInfluxDbWriter(DEFAULT_CONSISTENCY_LEVEL, DEFAULT_RETENTION_POLICY, DEFAULT_CUSTOM_TAGS, DEFAULT_RESULT_ATTRIBUTES, DEFAULT_TYPE_NAMES,true); } private InfluxDbWriter getTestInfluxDbWriterWithResultTags(ImmutableSet<ResultAttribute> resultTags) { return getTestInfluxDbWriter(DEFAULT_CONSISTENCY_LEVEL, DEFAULT_RETENTION_POLICY, DEFAULT_CUSTOM_TAGS, resultTags, DEFAULT_TYPE_NAMES,true); } private InfluxDbWriter getTestInfluxDbWriterWithCustomTags(ImmutableMap<String, String> tags) { return getTestInfluxDbWriter(DEFAULT_CONSISTENCY_LEVEL, DEFAULT_RETENTION_POLICY, tags, DEFAULT_RESULT_ATTRIBUTES, DEFAULT_TYPE_NAMES,true); } private InfluxDbWriter getTestInfluxDbWriterWithTypeNames(ImmutableList<String> typeNames) { return getTestInfluxDbWriter(DEFAULT_CONSISTENCY_LEVEL, DEFAULT_RETENTION_POLICY, DEFAULT_CUSTOM_TAGS, DEFAULT_RESULT_ATTRIBUTES, typeNames,true); } private InfluxDbWriter getTestInfluxDbWriterWithWriteConsistency(ConsistencyLevel consistencyLevel) { return getTestInfluxDbWriter(consistencyLevel, DEFAULT_RETENTION_POLICY, DEFAULT_CUSTOM_TAGS, DEFAULT_RESULT_ATTRIBUTES, DEFAULT_TYPE_NAMES,true); } private InfluxDbWriter getTestInfluxDbWriterNoDatabaseCreation() { return getTestInfluxDbWriter(DEFAULT_CONSISTENCY_LEVEL, DEFAULT_RETENTION_POLICY, DEFAULT_CUSTOM_TAGS, DEFAULT_RESULT_ATTRIBUTES, DEFAULT_TYPE_NAMES,false); } private InfluxDbWriter getTestInfluxDbWriter(ConsistencyLevel consistencyLevel, String retentionPolicy, ImmutableMap<String, String> tags, ImmutableSet<ResultAttribute> resultTags, ImmutableList<String> typeNames, boolean createDatabase) { return new InfluxDbWriter(influxDB, DATABASE_NAME, consistencyLevel, retentionPolicy, tags, resultTags, typeNames, createDatabase); } private String enumValueToAttribute(ResultAttribute attribute) { String[] split = attribute.name().split("_"); return StringUtils.lowerCase(split[0]) + WordUtils.capitalizeFully(split[1]); } }