/******************************************************************************* * Mission Control Technologies, Copyright (c) 2009-2012, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * * The MCT platform is 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. * * MCT includes source code licensed under additional open source licenses. See * the MCT Open Source Licenses file included with this distribution or the About * MCT Licenses dialog available at runtime from the MCT Help menu for additional * information. *******************************************************************************/ package gov.nasa.arc.mct.buffer.internal; import gov.nasa.arc.mct.api.feed.BufferFullException; import gov.nasa.arc.mct.api.feed.DataProvider.LOS; import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class DataBufferTest { private DataBuffer dataBuffer; private String testFeedID1 = "TestPui1"; private String testFeedID2 = "TestPui2"; private File bufferLocation; @BeforeMethod public void setup() throws IOException { Properties prop = new Properties(); prop.load(ClassLoader.getSystemResourceAsStream("properties/testFeed.properties")); prop.put("buffer.partitions", "1"); prop.put("buffer.time.millis", "-1"); bufferLocation = File.createTempFile("mct-buffer", ""); bufferLocation.delete(); bufferLocation.mkdir(); prop.put("buffer.disk.loc", bufferLocation.toString()); dataBuffer = DataBufferFactory.getFastDiskDataBuffer(prop); if (dataBuffer.isDataBufferClose()) { dataBuffer.reset(); } } @AfterMethod public void reset() { if (dataBuffer != null) { dataBuffer.closeBuffer(); } DataBufferFactory.reset(); delete(bufferLocation); } private void delete(File f) { if (f.isDirectory()) { for (File f2 : f.listFiles()) { delete(f2); } } f.delete(); } @Test public void fastLOSTest() { Assert.assertEquals(dataBuffer.getLOS(), LOS.medium); } @Test public void putSingleDataTest() throws BufferFullException { Map<String, String> value = new HashMap<String, String>(); value.put("value", "1.3"); value.put("status", "ok"); long time = System.currentTimeMillis(); long nanotime = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS); dataBuffer.putData(testFeedID1, TimeUnit.MILLISECONDS, time, value); List<Map<String, String>> returnData = dataBuffer.getData(Collections.singleton(testFeedID1), TimeUnit.NANOSECONDS, nanotime, nanotime + 100).get(testFeedID1); Assert.assertEquals(returnData.size(), 1); Map<String, String> returnValue = returnData.get(0); Assert.assertNotSame(returnValue, value); assertHasSameValue(returnValue, value); } @Test public void putBulkValueTest() throws BufferFullException { Map<String, String> value = new HashMap<String, String>(); value.put("value", "1.3"); value.put("status", "ok"); long time = System.currentTimeMillis(); long nanotime = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS); final AtomicInteger callbackCount = new AtomicInteger(0); Runnable r = new Runnable() { public void run() { callbackCount.incrementAndGet(); } }; Map<String, Map<Long, Map<String, String>>> bulkValue = new HashMap<String, Map<Long, Map<String, String>>>(); Map<Long, Map<String, String>> aValue = new HashMap<Long, Map<String, String>>(); aValue.put(time, value); bulkValue.put(testFeedID1, aValue); dataBuffer.putData(bulkValue, TimeUnit.MILLISECONDS, r); List<Map<String, String>> returnData = dataBuffer.getData(Collections.singleton(testFeedID1), TimeUnit.NANOSECONDS, nanotime, nanotime + 100).get(testFeedID1); Assert.assertEquals(returnData.size(), 1); Map<String, String> returnValue = returnData.get(0); Assert.assertNotSame(returnValue, value); assertHasSameValue(returnValue, value); } @Test public void notExactTimestampTest() throws BufferFullException { Map<String, String> value = new HashMap<String, String>(); value.put("value", "1.3"); value.put("status", "ok"); long time = System.nanoTime(); dataBuffer.putData(testFeedID1, TimeUnit.NANOSECONDS, time, value); List<Map<String, String>> returnData = dataBuffer.getData(Collections.singleton(testFeedID1), TimeUnit.NANOSECONDS, time - 100, time + 100).get(testFeedID1); Assert.assertEquals(returnData.size(), 1); Map<String, String> returnValue = returnData.get(0); Assert.assertNotSame(returnValue, value); assertHasSameValue(returnValue, value); } @Test public void multipleFeedsTest() throws BufferFullException { Map<String, String> value1 = new HashMap<String, String>(); value1.put("value", "1.3"); value1.put("status", "ok"); long time1 = System.currentTimeMillis(); dataBuffer.putData(testFeedID1, TimeUnit.MILLISECONDS, time1, value1); Map<String, String> value2 = new HashMap<String, String>(); value2.put("value", "2.3"); value2.put("status", "ok2"); long time2 = System.currentTimeMillis(); dataBuffer.putData(testFeedID2, TimeUnit.MILLISECONDS, time2, value2); List<Map<String, String>> returnData = dataBuffer.getData(Collections.singleton(testFeedID1), TimeUnit.MILLISECONDS, time1, time1 + 100).get(testFeedID1); Assert.assertEquals(returnData.size(), 1); Map<String, String> returnValue = returnData.get(0); Assert.assertNotSame(returnValue, value1); assertHasSameValue(returnValue, value1); returnData = dataBuffer.getData(Collections.singleton(testFeedID2), TimeUnit.MILLISECONDS, time2, time2 + 100).get(testFeedID2); Assert.assertEquals(returnData.size(), 1); returnValue = returnData.get(0); Assert.assertNotSame(returnValue, value2); assertHasSameValue(returnValue, value2); } @Test public void isFullyWithinTimeSpanTest() throws BufferFullException { Map<String, String> value1 = new HashMap<String, String>(); value1.put("value", "1.3"); value1.put("status", "ok"); long time1 = System.currentTimeMillis(); dataBuffer.putData(testFeedID1, TimeUnit.MILLISECONDS, time1, value1); Map<String, String> value2 = new HashMap<String, String>(); value2.put("value", "2.3"); value2.put("status", "ok2"); long time2 = time1 + 100; dataBuffer.putData(testFeedID2, TimeUnit.MILLISECONDS, time2, value2); Map<String, String> value3 = new HashMap<String, String>(); value3.put("value", "2.3"); value3.put("status", "ok2"); long time3 = time1 + 200; dataBuffer.putData(testFeedID1, TimeUnit.MILLISECONDS, time3, value3); Map<String, String> value4 = new HashMap<String, String>(); value4.put("value", "2.3"); value4.put("status", "ok2"); long time4 = time1 + 300; dataBuffer.putData(testFeedID2, TimeUnit.MILLISECONDS, time4, value4); Assert.assertTrue(dataBuffer.isFullyWithinTimeSpan(testFeedID1, time1, TimeUnit.MILLISECONDS)); Assert.assertFalse(dataBuffer.isFullyWithinTimeSpan(testFeedID1, time1 - 1, TimeUnit.MILLISECONDS)); Assert.assertTrue(dataBuffer.isFullyWithinTimeSpan(testFeedID2, time2, TimeUnit.MILLISECONDS)); Assert.assertFalse(dataBuffer.isFullyWithinTimeSpan(testFeedID2, time2 - 1, TimeUnit.MILLISECONDS)); } @Test public void multipleFeedsSameTimeTest() throws BufferFullException { Map<String, String> value1 = new HashMap<String, String>(); value1.put("value", "1.3"); value1.put("status", "ok"); long time = System.currentTimeMillis(); dataBuffer.putData(testFeedID1, TimeUnit.MILLISECONDS, time, value1); Map<String, String> value2 = new HashMap<String, String>(); value2.put("value", "2.3"); value2.put("status", "ok2"); dataBuffer.putData(testFeedID2, TimeUnit.MILLISECONDS, time, value2); List<Map<String, String>> returnData = dataBuffer.getData(Collections.singleton(testFeedID1), TimeUnit.MILLISECONDS, time, time + 100).get(testFeedID1); Assert.assertEquals(returnData.size(), 1); Map<String, String> returnValue = returnData.get(0); Assert.assertNotSame(returnValue, value1); assertHasSameValue(returnValue, value1); returnData = dataBuffer.getData(Collections.singleton(testFeedID2), TimeUnit.MILLISECONDS, time, time + 100).get(testFeedID2); Assert.assertEquals(returnData.size(), 1); returnValue = returnData.get(0); Assert.assertNotSame(returnValue, value2); assertHasSameValue(returnValue, value2); } @Test public void putMultipleDataTest() throws InterruptedException, BufferFullException { Map<Long, Map<String, String>> data = new HashMap<Long, Map<String, String>>(); Map<String, String> value1 = new HashMap<String, String>(); value1.put("value", "1.3"); value1.put("status", "ok"); long time1 = System.currentTimeMillis(); data.put(time1, value1); Thread.sleep(200); Map<String, String> value2 = new HashMap<String, String>(); value2.put("value", "1.4"); value2.put("status", "not-ok"); long time2 = System.currentTimeMillis(); data.put(time2, value2); dataBuffer.putData(testFeedID1, TimeUnit.MILLISECONDS, data); List<Map<String, String>> returnData = dataBuffer.getData(Collections.singleton(testFeedID1), TimeUnit.MILLISECONDS, time1, time1 + 100).get(testFeedID1); Assert.assertEquals(returnData.size(), 1); Map<String, String> returnValue = returnData.get(0); Assert.assertNotSame(returnValue, value1); assertHasSameValue(returnValue, value1); returnData = dataBuffer.getData(Collections.singleton(testFeedID1), TimeUnit.MILLISECONDS, time1, time2 + 100).get(testFeedID1); Assert.assertEquals(returnData.size(), 2); returnValue = returnData.get(0); Assert.assertNotSame(returnValue, value1); assertHasSameValue(returnValue, value1); returnValue = returnData.get(1); Assert.assertNotSame(returnValue, value2); assertHasSameValue(returnValue, value2); } @Test (enabled=false) public void longRunningTest() throws InterruptedException, BrokenBarrierException { final CyclicBarrier barrier = new CyclicBarrier(3); final PutDataRunnable putDataTask = new PutDataRunnable(barrier); final GetDataRunnable getDataTask = new GetDataRunnable(barrier); final Thread t1 = new Thread(putDataTask); final Thread t2 = new Thread(getDataTask); t1.start(); t2.start(); Timer timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { putDataTask.interrupt(); getDataTask.interrupt(); } }; timer.schedule(task, 6000); barrier.await(); Assert.assertTrue(getDataTask.isPassed()); } private void assertHasSameValue(Map<String, String> actualValue, Map<String, String> expectedValue) { Assert.assertEquals(actualValue.size(), expectedValue.size()); for (String key : actualValue.keySet()) { Assert.assertEquals(actualValue.get(key), expectedValue.get(key)); } } private final class GetDataRunnable implements Runnable { private boolean stop = false; private CyclicBarrier barrier; private boolean assertPassed = true; public GetDataRunnable(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { List<Map<String, String>> readData = new LinkedList<Map<String, String>>(); long startTime = System.currentTimeMillis(); long endTime = startTime; int oldValue = -1; while (!stop) { List<Map<String, String>> data = dataBuffer.getData(Collections.singleton(testFeedID1), TimeUnit.MILLISECONDS, startTime, endTime).get(testFeedID1); if (data == null) { data = Collections.emptyList(); } int index = 0; for (Map<String, String> record : data) { int value = Integer.parseInt(record.get("value")); long time = Long.parseLong(record.get("time")); assertPassed = assertPassed && time <= endTime; // since this is now COD the last time may be less than the last requested if (index++ > 0) { assertPassed = assertPassed && time >= startTime; } assertPassed = assertPassed && (value >= oldValue); if (!assertPassed) { stop = true; } oldValue = value; } readData.addAll(data); startTime = endTime; endTime = System.currentTimeMillis(); } try { barrier.await(); } catch (InterruptedException e) { throw new AssertionError(e); } catch (BrokenBarrierException e) { throw new AssertionError(e); } } public void interrupt() { this.stop = true; } public boolean isPassed() { return assertPassed; } } private final class PutDataRunnable implements Runnable { private boolean stop = false; private CyclicBarrier barrier; public PutDataRunnable(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { int i = 0; while (!stop) { Map<String, String> value = new HashMap<String, String>(); long time = System.currentTimeMillis(); value.put("value", String.valueOf(i)); value.put("time", String.valueOf(time)); try { dataBuffer.putData(testFeedID1, TimeUnit.MILLISECONDS, time, value); i++; Thread.sleep(100); } catch (InterruptedException e) { // ignore interrupt } catch (BufferFullException e1) { e1.printStackTrace(); } } try { barrier.await(); } catch (InterruptedException e) { throw new AssertionError(e); } catch (BrokenBarrierException e) { throw new AssertionError(e); } } public void interrupt() { stop = true; } } }