// This file is part of OpenTSDB. // Copyright (C) 2015 The OpenTSDB Authors. // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 2.1 of the License, or (at your // option) any later version. 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 Lesser // General Public License for more details. You should have received a copy // of the GNU Lesser General Public License along with this program. If not, // see <http://www.gnu.org/licenses/>. package net.opentsdb.core; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.util.Collection; import java.util.Iterator; import net.opentsdb.core.Internal.Cell; import net.opentsdb.storage.MockBase; import org.hbase.async.HBaseClient; import org.hbase.async.KeyValue; import org.hbase.async.PutRequest; import org.junit.Test; import org.powermock.reflect.Whitebox; public class TestAppendDataPoints extends BaseTsdbTest { private static final byte[] CF = "t".getBytes(); private static final byte[] DPQ_S = new byte[] { 0, 0x20 }; private static final byte[] DPQ_MS = new byte[] { (byte) 0xF0, 0, 0x20, 0 }; private static final byte[] DPV = new byte[] { 42 }; private static final byte[] DPV2 = new byte[] { 24 }; private static final byte[] ROW_KEY = new byte[] { 0, 0, 1, 0x50, (byte) 0xE2, 0x27, 0, 0, 0, 1, 0, 0, 1 }; @Test public void ctorForWrites() throws Exception { assertNotNull(new AppendDataPoints(DPQ_S, DPV)); assertNotNull(new AppendDataPoints(DPQ_MS, DPV)); try { assertNotNull(new AppendDataPoints(DPQ_S, null)); fail("Expected an IllegalArgumentException"); } catch (IllegalArgumentException iae) { } try { assertNotNull(new AppendDataPoints(null, DPV)); fail("Expected an IllegalArgumentException"); } catch (IllegalArgumentException iae) { } try { assertNotNull(new AppendDataPoints(null, null)); fail("Expected an IllegalArgumentException"); } catch (IllegalArgumentException iae) { } } @Test public void toByteArray() throws Exception { AppendDataPoints adp = new AppendDataPoints(DPQ_S, DPV); assertArrayEquals(MockBase.concatByteArrays(DPQ_S, DPV), adp.getBytes()); adp = new AppendDataPoints(DPQ_MS, DPV); assertArrayEquals(MockBase.concatByteArrays(DPQ_MS, DPV), adp.getBytes()); adp = new AppendDataPoints(MockBase.concatByteArrays(DPQ_MS, DPV), MockBase.concatByteArrays(DPQ_S, DPV2)); assertArrayEquals(MockBase.concatByteArrays(DPQ_MS, DPV, DPQ_S, DPV2), adp.getBytes()); } @Test public void parseKeyValue() throws Exception { KeyValue kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_S, DPV)); AppendDataPoints adp = new AppendDataPoints(); Collection<Cell> cells = adp.parseKeyValue(tsdb, kv); assertEquals(1, cells.size()); Cell cell = cells.iterator().next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998402000L, cell.timestamp(1356998400)); assertArrayEquals(DPQ_S, adp.qualifier()); assertArrayEquals(DPV, adp.value()); verify(client, never()).put(any(PutRequest.class)); kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_MS, DPV)); adp = new AppendDataPoints(); cells = adp.parseKeyValue(tsdb, kv); assertEquals(1, cells.size()); cell = cells.iterator().next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998400128L, cell.timestamp(1356998400)); assertArrayEquals(DPQ_MS, adp.qualifier()); assertArrayEquals(DPV, adp.value()); verify(client, never()).put(any(PutRequest.class)); // some odd offset kv = new KeyValue(ROW_KEY, CF, new byte[] { AppendDataPoints.APPEND_COLUMN_PREFIX, 42, 42 }, MockBase.concatByteArrays(DPQ_MS, DPV)); adp = new AppendDataPoints(); cells = adp.parseKeyValue(tsdb, kv); assertEquals(1, cells.size()); cell = cells.iterator().next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998400128L, cell.timestamp(1356998400)); assertArrayEquals(DPQ_MS, adp.qualifier()); assertArrayEquals(DPV, adp.value()); verify(client, never()).put(any(PutRequest.class)); kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_MS, DPV, DPQ_S, DPV2)); adp = new AppendDataPoints(); cells = adp.parseKeyValue(tsdb, kv); assertEquals(2, cells.size()); Iterator<Cell> iterator = cells.iterator(); cell = iterator.next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998400128L, cell.timestamp(1356998400)); cell = iterator.next(); assertArrayEquals(DPV2, cell.value); assertEquals(1356998402000L, cell.timestamp(1356998400)); assertArrayEquals(MockBase.concatByteArrays(DPQ_MS, DPQ_S), adp.qualifier()); assertArrayEquals(MockBase.concatByteArrays(DPV, DPV2), adp.value()); verify(client, never()).put(any(PutRequest.class)); // out of order kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_S, DPV2, DPQ_MS, DPV)); adp = new AppendDataPoints(); cells = adp.parseKeyValue(tsdb, kv); assertEquals(2, cells.size()); iterator = cells.iterator(); cell = iterator.next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998400128L, cell.timestamp(1356998400)); cell = iterator.next(); assertArrayEquals(DPV2, cell.value); assertEquals(1356998402000L, cell.timestamp(1356998400)); assertArrayEquals(MockBase.concatByteArrays(DPQ_MS, DPQ_S), adp.qualifier()); assertArrayEquals(MockBase.concatByteArrays(DPV, DPV2), adp.value()); verify(client, never()).put(any(PutRequest.class)); // duplicates kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_MS, DPV, DPQ_S, DPV2, DPQ_S, DPV2)); adp = new AppendDataPoints(); cells = adp.parseKeyValue(tsdb, kv); assertEquals(2, cells.size()); iterator = cells.iterator(); cell = iterator.next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998400128L, cell.timestamp(1356998400)); cell = iterator.next(); assertArrayEquals(DPV2, cell.value); assertEquals(1356998402000L, cell.timestamp(1356998400)); assertArrayEquals(MockBase.concatByteArrays(DPQ_MS, DPQ_S), adp.qualifier()); assertArrayEquals(MockBase.concatByteArrays(DPV, DPV2), adp.value()); verify(client, never()).put(any(PutRequest.class)); // duplicates AND out of order, just a mess kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays( DPQ_S, DPV2, DPQ_MS, DPV, DPQ_MS, DPV, DPQ_S, DPV2, DPQ_MS, DPV)); adp = new AppendDataPoints(); cells = adp.parseKeyValue(tsdb, kv); assertEquals(2, cells.size()); iterator = cells.iterator(); cell = iterator.next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998400128L, cell.timestamp(1356998400)); cell = iterator.next(); assertArrayEquals(DPV2, cell.value); assertEquals(1356998402000L, cell.timestamp(1356998400)); assertArrayEquals(MockBase.concatByteArrays(DPQ_MS, DPQ_S), adp.qualifier()); assertArrayEquals(MockBase.concatByteArrays(DPV, DPV2), adp.value()); verify(client, never()).put(any(PutRequest.class)); } @Test public void parseKeyValueNotAppends() throws Exception { // regular data points try { KeyValue kv = new KeyValue(ROW_KEY, CF, DPQ_S, DPV); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an IllegalArgumentException"); } catch (IllegalArgumentException iae) { } try { KeyValue kv = new KeyValue(ROW_KEY, CF, DPQ_MS, DPV); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an IllegalArgumentException"); } catch (IllegalArgumentException iae) { } // different object try { KeyValue kv = new KeyValue(ROW_KEY, CF, new byte[] { 1, 0, 0 }, DPV); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an IllegalArgumentException"); } catch (IllegalArgumentException iae) { } // bad coder! try { new AppendDataPoints().parseKeyValue(tsdb, null); fail("Expected an NullPointerException"); } catch (NullPointerException iae) { } } @Test public void parseKeyValueCorrupt() throws Exception { // shouldn't happen, but who knows? try { KeyValue kv = new KeyValue(ROW_KEY, CF, null, DPV); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an NullPointerException"); } catch (NullPointerException iae) { } try { KeyValue kv = new KeyValue(ROW_KEY, CF, HBaseClient.EMPTY_ARRAY, DPV); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an IllegalArgumentException"); } catch (IllegalArgumentException iae) { } try { KeyValue kv = new KeyValue(ROW_KEY, CF, DPQ_S, null); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an NullPointerException"); } catch (NullPointerException iae) { } try { KeyValue kv = new KeyValue(ROW_KEY, CF, DPQ_S, HBaseClient.EMPTY_ARRAY); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an IllegalArgumentException"); } catch (IllegalArgumentException iae) { } try { KeyValue kv = new KeyValue(null, CF, DPQ_S, DPV); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an NullPointerException"); } catch (NullPointerException iae) { } try { KeyValue kv = new KeyValue(METRIC_BYTES, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_S, DPV2)); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an IllegalDataException"); } catch (IllegalDataException iae) { } // bad values try { KeyValue kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_MS, /*DPV, oops*/ DPQ_S, DPV2)); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an IllegalDataException"); } catch (IllegalDataException iae) { } try { KeyValue kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_MS, DPV2, new byte[] { 0, 0, 0, 0, })); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an IllegalDataException"); } catch (IllegalDataException iae) { } try { KeyValue kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPV2, DPQ_MS)); new AppendDataPoints().parseKeyValue(tsdb, kv); fail("Expected an IllegalDataException"); } catch (IllegalDataException iae) { } } @Test public void repairDuplicates() throws Exception { setDataPointStorage(); Whitebox.setInternalState(config, "repair_appends", true); final KeyValue kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_MS, DPV, DPQ_S, DPV2, DPQ_S, DPV2)); final AppendDataPoints adp = new AppendDataPoints(); final Collection<Cell>cells = adp.parseKeyValue(tsdb, kv); assertEquals(2, cells.size()); final Iterator<Cell> iterator = cells.iterator(); Cell cell = iterator.next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998400128L, cell.timestamp(1356998400)); cell = iterator.next(); assertArrayEquals(DPV2, cell.value); assertEquals(1356998402000L, cell.timestamp(1356998400)); assertArrayEquals(MockBase.concatByteArrays(DPQ_MS, DPQ_S), adp.qualifier()); assertArrayEquals(MockBase.concatByteArrays(DPV, DPV2), adp.value()); verify(client, times(1)).put(any(PutRequest.class)); adp.repairedDeferred().join(); assertArrayEquals( MockBase.concatByteArrays(DPQ_MS, DPV, DPQ_S, DPV2), storage.getColumn(ROW_KEY, AppendDataPoints.APPEND_COLUMN_QUALIFIER)); } @Test public void repairOutOfOrder() throws Exception { setDataPointStorage(); Whitebox.setInternalState(config, "repair_appends", true); final KeyValue kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays(DPQ_S, DPV2, DPQ_MS, DPV)); final AppendDataPoints adp = new AppendDataPoints(); final Collection<Cell>cells = adp.parseKeyValue(tsdb, kv); assertEquals(2, cells.size()); final Iterator<Cell> iterator = cells.iterator(); Cell cell = iterator.next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998400128L, cell.timestamp(1356998400)); cell = iterator.next(); assertArrayEquals(DPV2, cell.value); assertEquals(1356998402000L, cell.timestamp(1356998400)); assertArrayEquals(MockBase.concatByteArrays(DPQ_MS, DPQ_S), adp.qualifier()); assertArrayEquals(MockBase.concatByteArrays(DPV, DPV2), adp.value()); verify(client, times(1)).put(any(PutRequest.class)); adp.repairedDeferred().join(); assertArrayEquals( MockBase.concatByteArrays(DPQ_MS, DPV, DPQ_S, DPV2), storage.getColumn(ROW_KEY, AppendDataPoints.APPEND_COLUMN_QUALIFIER)); } @Test public void repairOutOfOrderAndDuplicates() throws Exception { setDataPointStorage(); Whitebox.setInternalState(config, "repair_appends", true); final KeyValue kv = new KeyValue(ROW_KEY, CF, AppendDataPoints.APPEND_COLUMN_QUALIFIER, MockBase.concatByteArrays( DPQ_S, DPV2, DPQ_MS, DPV, DPQ_MS, DPV, DPQ_S, DPV2, DPQ_MS, DPV)); final AppendDataPoints adp = new AppendDataPoints(); final Collection<Cell>cells = adp.parseKeyValue(tsdb, kv); assertEquals(2, cells.size()); final Iterator<Cell> iterator = cells.iterator(); Cell cell = iterator.next(); assertArrayEquals(DPV, cell.value); assertEquals(1356998400128L, cell.timestamp(1356998400)); cell = iterator.next(); assertArrayEquals(DPV2, cell.value); assertEquals(1356998402000L, cell.timestamp(1356998400)); assertArrayEquals(MockBase.concatByteArrays(DPQ_MS, DPQ_S), adp.qualifier()); assertArrayEquals(MockBase.concatByteArrays(DPV, DPV2), adp.value()); verify(client, times(1)).put(any(PutRequest.class)); adp.repairedDeferred().join(); assertArrayEquals( MockBase.concatByteArrays(DPQ_MS, DPV, DPQ_S, DPV2), storage.getColumn(ROW_KEY, AppendDataPoints.APPEND_COLUMN_QUALIFIER)); } }