package cc.blynk.server.workers; import cc.blynk.server.core.BlockingIOProcessor; import cc.blynk.server.core.dao.ReportingDao; import cc.blynk.server.core.model.AppName; import cc.blynk.server.core.model.auth.User; import cc.blynk.server.core.model.enums.GraphType; import cc.blynk.server.core.model.enums.PinType; import cc.blynk.server.core.protocol.handlers.DefaultExceptionHandler; import cc.blynk.server.core.reporting.average.AggregationKey; import cc.blynk.server.core.reporting.average.AggregationValue; import cc.blynk.server.core.reporting.average.AverageAggregatorProcessor; import cc.blynk.server.db.DBManager; import cc.blynk.utils.ServerProperties; import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; import static cc.blynk.server.core.dao.ReportingDao.generateFilename; import static cc.blynk.utils.ReportingUtil.getReportingFolder; import static org.junit.Assert.*; import static org.mockito.Mockito.when; /** * The Blynk Project. * Created by Dmitriy Dumanskiy. * Created on 11.08.15. */ @RunWith(MockitoJUnitRunner.class) public class ReportingWorkerTest { private final String reportingFolder = getReportingFolder(System.getProperty("java.io.tmpdir")); @Mock public AverageAggregatorProcessor averageAggregator; @InjectMocks public ReportingDao reportingDaoMock; @Mock public ServerProperties properties; private BlockingIOProcessor blockingIOProcessor; @Before public void cleanup() throws IOException { blockingIOProcessor = new BlockingIOProcessor(1, 1); Path dataFolder1 = Paths.get(reportingFolder, "test"); FileUtils.deleteDirectory(dataFolder1.toFile()); createReportingFolder(reportingFolder, "test"); Path dataFolder2 = Paths.get(reportingFolder, "test2"); FileUtils.deleteDirectory(dataFolder2.toFile()); createReportingFolder(reportingFolder, "test2"); reportingDaoMock = new ReportingDao(reportingFolder, averageAggregator, properties); } private static void createReportingFolder(String reportingFolder, String email) { Path reportingPath = Paths.get(reportingFolder, email); if (Files.notExists(reportingPath)) { try { Files.createDirectories(reportingPath); } catch (IOException ioe) { DefaultExceptionHandler.log.error("Error creating report folder. {}", reportingPath); } } } @Test public void testFailure() throws IOException { User user = new User(); user.email = "test"; user.appName = AppName.BLYNK; ReportingWorker reportingWorker = new ReportingWorker(reportingDaoMock, reportingFolder, new DBManager(blockingIOProcessor, true)); ConcurrentHashMap<AggregationKey, AggregationValue> map = new ConcurrentHashMap<>(); long ts = getTS() / AverageAggregatorProcessor.HOUR; AggregationKey aggregationKey = new AggregationKey("ddd\0+123@gmail.com", AppName.BLYNK, 1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, ts); AggregationValue aggregationValue = new AggregationValue(); aggregationValue.update(100); map.put(aggregationKey, aggregationValue); when(averageAggregator.getMinute()).thenReturn(map); reportingWorker.run(); assertTrue(map.isEmpty()); } @Test public void testStore() throws IOException { User user = new User(); user.email = "test"; user.appName = AppName.BLYNK; ReportingWorker reportingWorker = new ReportingWorker(reportingDaoMock, reportingFolder, new DBManager(blockingIOProcessor, true)); ConcurrentHashMap<AggregationKey, AggregationValue> map = new ConcurrentHashMap<>(); long ts = getTS() / AverageAggregatorProcessor.HOUR; AggregationKey aggregationKey = new AggregationKey("test", AppName.BLYNK, 1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, ts); AggregationValue aggregationValue = new AggregationValue(); aggregationValue.update(100); AggregationKey aggregationKey2 = new AggregationKey("test", AppName.BLYNK, 1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, ts - 1); AggregationValue aggregationValue2 = new AggregationValue(); aggregationValue2.update(150.54); AggregationKey aggregationKey3 = new AggregationKey("test2", AppName.BLYNK, 2, 0, PinType.ANALOG.pintTypeChar, (byte) 2, ts); AggregationValue aggregationValue3 = new AggregationValue(); aggregationValue3.update(200); map.put(aggregationKey, aggregationValue); map.put(aggregationKey2, aggregationValue2); map.put(aggregationKey3, aggregationValue3); when(averageAggregator.getMinute()).thenReturn(new ConcurrentHashMap<>()); when(averageAggregator.getHourly()).thenReturn(map); when(averageAggregator.getDaily()).thenReturn(new ConcurrentHashMap<>()); reportingWorker.run(); assertTrue(Files.exists(Paths.get(reportingFolder, "test", generateFilename(1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, GraphType.HOURLY)))); assertTrue(Files.exists(Paths.get(reportingFolder, "test2", generateFilename(2, 0, PinType.ANALOG.pintTypeChar, (byte) 2, GraphType.HOURLY)))); assertTrue(map.isEmpty()); ByteBuffer data = ReportingDao.getByteBufferFromDisk(reportingFolder, user, 1, 0, PinType.ANALOG, (byte) 1, 2, GraphType.HOURLY); assertNotNull(data); data.flip(); assertEquals(32, data.capacity()); assertEquals(150.54, data.getDouble(), 0.001); assertEquals((ts - 1) * AverageAggregatorProcessor.HOUR, data.getLong()); assertEquals(100.0, data.getDouble(), 0.001); assertEquals(ts * AverageAggregatorProcessor.HOUR, data.getLong()); User user2 = new User(); user2.email = "test2"; user2.appName = AppName.BLYNK; data = ReportingDao.getByteBufferFromDisk(reportingFolder, user2, 2, 0, PinType.ANALOG, (byte) 2, 1, GraphType.HOURLY); assertNotNull(data); data.flip(); assertEquals(16, data.capacity()); assertEquals(200.0, data.getDouble(), 0.001); assertEquals(ts * AverageAggregatorProcessor.HOUR, data.getLong()); } @Test public void testStore2() throws IOException { ReportingWorker reportingWorker = new ReportingWorker(reportingDaoMock, reportingFolder, new DBManager(blockingIOProcessor, true)); ConcurrentHashMap<AggregationKey, AggregationValue> map = new ConcurrentHashMap<>(); long ts = getTS() / AverageAggregatorProcessor.HOUR; AggregationKey aggregationKey = new AggregationKey("test", AppName.BLYNK, 1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, ts); AggregationValue aggregationValue = new AggregationValue(); aggregationValue.update(100); AggregationKey aggregationKey2 = new AggregationKey("test", AppName.BLYNK, 1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, ts - 1); AggregationValue aggregationValue2 = new AggregationValue(); aggregationValue2.update(150.54); AggregationKey aggregationKey3 = new AggregationKey("test", AppName.BLYNK, 1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, ts - 2); AggregationValue aggregationValue3 = new AggregationValue(); aggregationValue3.update(200); map.put(aggregationKey, aggregationValue); map.put(aggregationKey2, aggregationValue2); map.put(aggregationKey3, aggregationValue3); when(averageAggregator.getMinute()).thenReturn(new ConcurrentHashMap<>()); when(averageAggregator.getHourly()).thenReturn(map); when(averageAggregator.getDaily()).thenReturn(new ConcurrentHashMap<>()); reportingWorker.run(); assertTrue(Files.exists(Paths.get(reportingFolder, "test", generateFilename(1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, GraphType.HOURLY)))); assertTrue(map.isEmpty()); User user = new User(); user.email = "test"; user.appName = AppName.BLYNK; //take less ByteBuffer data = ReportingDao.getByteBufferFromDisk(reportingFolder, user, 1, 0, PinType.ANALOG, (byte) 1, 1, GraphType.HOURLY); assertNotNull(data); data.flip(); assertEquals(16, data.capacity()); assertEquals(100.0, data.getDouble(), 0.001); assertEquals(ts * AverageAggregatorProcessor.HOUR, data.getLong()); //take more data = ReportingDao.getByteBufferFromDisk(reportingFolder, user, 1, 0, PinType.ANALOG, (byte) 1, 24, GraphType.HOURLY); assertNotNull(data); data.flip(); assertEquals(48, data.capacity()); assertEquals(200.0, data.getDouble(), 0.001); assertEquals((ts - 2) * AverageAggregatorProcessor.HOUR, data.getLong()); assertEquals(150.54, data.getDouble(), 0.001); assertEquals((ts - 1) * AverageAggregatorProcessor.HOUR, data.getLong()); assertEquals(100.0, data.getDouble(), 0.001); assertEquals(ts * AverageAggregatorProcessor.HOUR, data.getLong()); } @Test public void testDeleteCommand() throws IOException { ReportingWorker reportingWorker = new ReportingWorker(reportingDaoMock, reportingFolder, new DBManager(blockingIOProcessor, true)); ConcurrentHashMap<AggregationKey, AggregationValue> map = new ConcurrentHashMap<>(); long ts = getTS() / AverageAggregatorProcessor.HOUR; AggregationKey aggregationKey = new AggregationKey("test", AppName.BLYNK, 1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, ts); AggregationValue aggregationValue = new AggregationValue(); aggregationValue.update(100); AggregationKey aggregationKey2 = new AggregationKey("test", AppName.BLYNK, 1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, ts - 1); AggregationValue aggregationValue2 = new AggregationValue(); aggregationValue2.update(150.54); AggregationKey aggregationKey3 = new AggregationKey("test2", AppName.BLYNK, 2, 0, PinType.ANALOG.pintTypeChar, (byte) 2, ts); AggregationValue aggregationValue3 = new AggregationValue(); aggregationValue3.update(200); map.put(aggregationKey, aggregationValue); map.put(aggregationKey2, aggregationValue2); map.put(aggregationKey3, aggregationValue3); when(averageAggregator.getMinute()).thenReturn(new ConcurrentHashMap<>()); when(averageAggregator.getHourly()).thenReturn(map); when(averageAggregator.getDaily()).thenReturn(new ConcurrentHashMap<>()); when(properties.getProperty("data.folder")).thenReturn(System.getProperty("java.io.tmpdir")); reportingWorker.run(); assertTrue(Files.exists(Paths.get(reportingFolder, "test", generateFilename(1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, GraphType.HOURLY)))); assertTrue(Files.exists(Paths.get(reportingFolder, "test2", generateFilename(2, 0, PinType.ANALOG.pintTypeChar, (byte) 2, GraphType.HOURLY)))); User user = new User(); user.email = "test"; user.appName = AppName.BLYNK; new ReportingDao(reportingFolder, properties).delete(user, 1, 0, PinType.ANALOG, (byte) 1); assertFalse(Files.exists(Paths.get(reportingFolder, "test", generateFilename(1, 0, PinType.ANALOG.pintTypeChar, (byte) 1, GraphType.HOURLY)))); } private long getTS() { SimpleDateFormat formatter = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss"); String dateInString = "Aug 10, 2015 12:10:56"; try { Date date = formatter.parse(dateInString); return date.getTime(); } catch (ParseException e) { e.printStackTrace(); } return 0; } }