/** * Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT * All rights reserved. Use is subject to license terms. See LICENSE.TXT */ package org.diirt.datasource.timecache.query; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.Duration; import java.time.Instant; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import org.diirt.datasource.timecache.DataChunk; import org.diirt.datasource.timecache.DataRequestListener; import org.diirt.datasource.timecache.DataRequestThread; import org.diirt.datasource.timecache.impl.SimpleFileDataSource; import org.diirt.datasource.timecache.query.Query; import org.diirt.datasource.timecache.query.QueryChunk; import org.diirt.datasource.timecache.query.QueryData; import org.diirt.datasource.timecache.query.QueryImpl; import org.diirt.datasource.timecache.query.QueryParameters; import org.diirt.datasource.timecache.query.QueryResult; import org.diirt.datasource.timecache.source.DataSource; import org.diirt.datasource.timecache.util.IntervalsList; import org.diirt.datasource.timecache.util.PVCacheMock; import org.diirt.util.time.TimeInterval; import org.diirt.util.time.TimeRelativeInterval; import org.junit.Assert; import org.junit.Test; /** * Test {@link QueryImpl}: fills chunks with samples retrieved from sources or * storage. * @author Fred Arnaud (Sopra Group) - ITER */ public class QueryUnitTests { final private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); private static Instant timeOf(String date) throws ParseException { return dateFormat.parse(date).toInstant(); } /** * Test that the right numbers of chunks is created per query. */ @Test public void testUpdateWithoutStorage() { try { PVCacheMock cache = new PVCacheMock(); Instant start = timeOf("2014-11-26 00:00"); Instant end = timeOf("2014-11-27 00:00"); QueryParameters params = new QueryParameters() .timeInterval(TimeRelativeInterval.of(start, end)); // 24 chunk per 1 day query => 1 hour per chunk Query query = new QueryImpl(cache, 24); query.update(params); List<QueryChunk> chunks = ((QueryImpl) query).getChunks(); Assert.assertEquals(24, chunks.size()); for (QueryChunk chunk : chunks) { Duration chunkDuration = Duration.between(chunk.getTimeInterval().getEnd(),chunk.getTimeInterval().getStart()).abs(); Assert.assertEquals(3600, chunkDuration.getSeconds(), 1); } // 100 chunk per 1 day query => 864 seconds per chunk query = new QueryImpl(cache, 100); query.update(params); chunks = ((QueryImpl) query).getChunks(); Assert.assertEquals(100, chunks.size()); for (QueryChunk chunk : chunks) { Duration chunkDuration = Duration.between(chunk.getTimeInterval().getEnd(),chunk.getTimeInterval().getStart()).abs(); Assert.assertEquals(864, chunkDuration.getSeconds(), 1); } } catch (Exception e) { e.printStackTrace(); Assert.fail(e.getMessage()); } } /** * Test that the right numbers of chunks is created per query. * Test that each created chunk is filled properly by samples from a simulated storage. */ @Test public void testUpdateWithStorage() { try { PVCacheMock cache = new PVCacheMock(); Instant start = timeOf("2014-11-26 00:00"); Instant end = timeOf("2014-11-27 00:00"); QueryParameters params = new QueryParameters() .timeInterval(TimeRelativeInterval.of(start, end)); // 100 chunk per 1 day query => 864 seconds per chunk Query query = new QueryImpl(cache, 100); // Simulate data from storage by adding a storage thread to the mock DataSource source = new SimpleFileDataSource("src/test/resources/archive-ramps-1W.csv"); DataRequestThread thread = new DataRequestThread("TEST-BTY0:RAMP2", source, TimeInterval.between(start, end)); final AtomicBoolean intervalCompleted = new AtomicBoolean(false); thread.addListener(new DataRequestListener() { @Override public void newData(DataChunk chunk, DataRequestThread thread) { } @Override public void intervalComplete(DataRequestThread thread) { intervalCompleted.getAndSet(true); } }); cache.setStorageThread(thread); // Start the query query.update(params); int limit = 0; while (!intervalCompleted.get() && limit <= 60) { // 30s try { Thread.sleep(500); } catch (InterruptedException e) { } limit++; } // Check that chunks contains the right number of samples List<QueryChunk> chunks = ((QueryImpl) query).getChunks(); Assert.assertEquals(100, chunks.size()); for (QueryChunk chunk : chunks) { Duration chunkDuration = Duration.between(chunk.getTimeInterval().getEnd(),chunk.getTimeInterval().getStart()).abs(); Assert.assertEquals(864, chunkDuration.getSeconds(), 1); Assert.assertEquals(432, chunk.getDataCount()); } } catch (Exception e) { e.printStackTrace(); Assert.fail(e.getMessage()); } } /** * Test that the right numbers of chunks is created per query. * Test that each created chunk is filled properly by samples from a simulated source. */ @Test public void testNewData() { try { // 24 chunk per 1 day query => 1 hour per chunk => 1800 data subTestNewData(24, 1800); // 100 chunk per 1 day query => 864 seconds per chunk => 423 data subTestNewData(100, 432); } catch (Exception e) { e.printStackTrace(); Assert.fail(e.getMessage()); } } // Subroutine of testNewData private void subTestNewData(int nbOfChunks, int expectedCount) throws Exception { PVCacheMock cache = new PVCacheMock(); final Instant start = timeOf("2014-11-27 00:00"); final Instant end = timeOf("2014-11-28 00:00"); // The query will request for completed intervals in order to mark // chunks as completed, so we define them in the mock cache.addCompletedInterval(TimeInterval.between(start, end)); QueryParameters params = new QueryParameters() .timeInterval(TimeRelativeInterval.of(start, end)); final Query query = new QueryImpl(cache, nbOfChunks); // Start the query query.update(params); // Simulate new data from source DataSource source = new SimpleFileDataSource("src/test/resources/archive-ramps-1W.csv"); DataRequestThread thread = new DataRequestThread("TEST-BTY0:RAMP2", source, TimeInterval.between(start, end)); final IntervalsList completedIntervals = new IntervalsList(); thread.addListener(new DataRequestListener() { @Override public void newData(DataChunk chunk, DataRequestThread thread) { completedIntervals.addToSelf(chunk.getInterval()); ((QueryImpl) query).newDataInCache(chunk.getDatas(), chunk.getInterval(), completedIntervals); } @Override public void intervalComplete(DataRequestThread thread) { ((QueryImpl) query).updatedCompletedIntervals(new IntervalsList(TimeInterval.between(start, end))); } }); thread.run(); // Wait for remaining tasks to be executed in ExecutorService while (((QueryImpl) query).isProcessingData()) Thread.sleep(500); // Check that each chunk contains the expected number of samples List<QueryChunk> chunks = ((QueryImpl) query).getChunks(); for (QueryChunk chunk : chunks) { Assert.assertEquals(expectedCount, chunk.getDataCount()); } QueryResult result = query.getUpdate(); Assert.assertEquals(nbOfChunks, result.getData().size()); for (QueryData data : result.getData()) { Assert.assertEquals(expectedCount, data.getCount()); } // All chunks should have been marked as sent chunks = ((QueryImpl) query).getChunks(); for (QueryChunk chunk : chunks) { Assert.assertTrue(chunk.hasBeenSent()); } } }