/** * 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.test; import org.diirt.datasource.test.CountDownPVWriterListener; import org.diirt.datasource.test.CountDownPVReaderListener; import org.diirt.datasource.test.CountDownWriteFunction; import org.diirt.datasource.test.TestDataSource; import java.time.Duration; import java.time.Instant; import java.util.Objects; import org.diirt.datasource.DataSource; import static org.diirt.datasource.ExpressionLanguage.*; import org.diirt.datasource.PV; import org.diirt.datasource.PVManager; import org.diirt.datasource.PVReader; import org.diirt.datasource.PVReaderEvent; import org.diirt.datasource.PVWriter; import org.diirt.datasource.TimeoutException; import static java.time.Duration.*; import org.diirt.util.time.TimeInterval; import static org.hamcrest.Matchers.*; import org.junit.After; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; /** * * @author carcassi */ public class TestDataSourceTest { public TestDataSourceTest() { } public static void waitForChannelToClose(DataSource source, String channelName) { Duration timeout = ofMillis(5000); TimeInterval timeoutInterval = TimeInterval.after(timeout, Instant.now()); while (timeoutInterval.contains(Instant.now())) { if (source.getChannels().get(channelName) == null || !source.getChannels().get(channelName).isConnected()) { return; } try { Thread.sleep(100); } catch(Exception ex) { } } fail("Channel " + channelName + " didn't close after 5 seconds"); } private DataSource dataSource; PV<Object, Object> pv; PVReader<Object> pvReader; PVReader<Object> pvReader2; PVWriter<Object> pvWriter; @Before public void setupDataSource() throws Exception { dataSource = new TestDataSource(); } @After public void closePVsAndDataSource() { if (pv != null) { pv.close(); pv = null; } if (pvReader != null) { pvReader.close(); pvReader = null; } if (pvReader2 != null) { pvReader2.close(); pvReader2 = null; } if (pvWriter != null) { pvWriter.close(); pvWriter = null; } waitForChannelToClose(dataSource, "delayedWrite"); waitForChannelToClose(dataSource, "delayedConnection"); dataSource.close(); dataSource = null; } @Test public void channelDoesNotExist1() throws Exception { // Requesting a channel that does not exist // Making sure that the exception is properly notified CountDownPVReaderListener listener = new CountDownPVReaderListener(1); pvReader = PVManager.read(channel("nothing")) .readListener(listener) .from(dataSource).maxRate(ofMillis(10)); listener.await(Duration.ofMillis(100)); RuntimeException ex = (RuntimeException) pvReader.lastException(); assertThat(ex, not(nullValue())); } @Test public void channelDoesNotExist2() throws Exception { // Requesting a channel that does not exist // Making sure that the exception is properly notified CountDownPVWriterListener<Object> listener = new CountDownPVWriterListener<>(1); pvWriter = PVManager.write(channel("nothing")) .writeListener(listener) .from(dataSource).async(); listener.await(Duration.ofMillis(100)); RuntimeException ex = (RuntimeException) pvWriter.lastWriteException(); assertThat(ex, not(nullValue())); } @Test public void channelDoesNotExist3() throws Exception { // Requesting a channel that does not exist // Making sure that the exception is routed CountDownWriteFunction exceptionHandler = new CountDownWriteFunction(1); pvReader = PVManager.read(channel("nothing")) .routeExceptionsTo(exceptionHandler) .from(dataSource).maxRate(ofMillis(10)); exceptionHandler.await(Duration.ofMillis(100)); RuntimeException ex = (RuntimeException) exceptionHandler.getException(); assertThat(ex, not(nullValue())); } @Test public void channelDoesNotExist4() throws Exception { // Requesting a channel that does not exist // Making sure that the exception is properly notified CountDownWriteFunction exceptionHandler = new CountDownWriteFunction(1); pvWriter = PVManager.write(channel("nothing")) .routeExceptionsTo(exceptionHandler) .from(dataSource).async(); exceptionHandler.await(Duration.ofMillis(100)); RuntimeException ex = (RuntimeException) exceptionHandler.getException(); assertThat(ex, not(nullValue())); } @Test public void delayedWrite() throws Exception { CountDownPVWriterListener<Object> listener = new CountDownPVWriterListener<>(1); pvWriter = PVManager.write(channel("delayedWrite")) .writeListener(listener) .from(dataSource).async(); pvWriter.write("test"); listener.await(Duration.ofMillis(15)); assertThat(listener.getCount(), equalTo(1)); RuntimeException ex = (RuntimeException) pvWriter.lastWriteException(); assertThat(ex, nullValue()); listener.await(Duration.ofMillis(1100)); assertThat(listener.getCount(), equalTo(0)); listener.resetCount(1); ex = (RuntimeException) pvWriter.lastWriteException(); assertThat(ex, nullValue()); } @Test public void delayedWriteWithTimeout() throws Exception { CountDownPVWriterListener<Object> writerListener = new CountDownPVWriterListener<>(1); pvWriter = PVManager.write(channel("delayedWrite")) .writeListener(writerListener) .timeout(ofMillis(500)).from(dataSource).async(); pvWriter.write("test"); writerListener.await(Duration.ofMillis(750)); assertThat(writerListener.getCount(), equalTo(0)); writerListener.resetCount(1); Exception ex = pvWriter.lastWriteException(); assertThat(ex, not(nullValue())); assertThat(ex, instanceOf(TimeoutException.class)); writerListener.await(Duration.ofMillis(2000)); assertThat(writerListener.getCount(), equalTo(0)); ex = pvWriter.lastWriteException(); assertThat(ex, nullValue()); } @Test public void delayedWriteWithTimeout2() throws Exception { // Test a write that happens 2 seconds late // Checks whether we get a timeout beforehand CountDownPVWriterListener<Object> writerListener = new CountDownPVWriterListener<>(1); pvWriter = PVManager.write(channel("delayedWrite")).timeout(ofMillis(500)) .writeListener(writerListener) .from(dataSource).async(); pvWriter.write("test"); // Wait for the first notification, should be the timeout writerListener.await(Duration.ofMillis(600)); assertThat(writerListener.getCount(), equalTo(0)); writerListener.resetCount(1); Exception ex = pvWriter.lastWriteException(); assertThat(ex, not(nullValue())); assertThat(ex, instanceOf(TimeoutException.class)); // Wait for the second notification, should be // the success notification writerListener.await(Duration.ofMillis(2000)); assertThat(writerListener.getCount(), equalTo(0)); writerListener.resetCount(1); ex = pvWriter.lastWriteException(); assertThat(ex, nullValue()); // Write again pvWriter.write("test2"); // Wait for a notification: should not come writerListener.await(Duration.ofMillis(400)); assertThat(writerListener.getCount(), equalTo(1)); ex = pvWriter.lastWriteException(); assertThat(ex, nullValue()); writerListener.await(Duration.ofMillis(250)); assertThat(writerListener.getCount(), equalTo(0)); writerListener.resetCount(1); ex = pvWriter.lastWriteException(); assertThat(ex, not(nullValue())); assertThat(ex, instanceOf(TimeoutException.class)); writerListener.await(Duration.ofMillis(2000)); assertThat(writerListener.getCount(), equalTo(0)); ex = pvWriter.lastWriteException(); assertThat(ex, nullValue()); } @Test public void delayedReadConnectionWithTimeout() throws Exception { CountDownPVReaderListener readListener = new CountDownPVReaderListener(1, PVReaderEvent.VALUE_MASK | PVReaderEvent.EXCEPTION_MASK); pvReader = PVManager.read(channel("delayedConnection")).timeout(ofMillis(500)) .readListener(readListener) .from(dataSource).maxRate(ofMillis(50)); readListener.await(Duration.ofMillis(50)); assertThat(readListener.getCount(), equalTo(1)); TimeoutException ex = (TimeoutException) pvReader.lastException(); assertThat(ex, nullValue()); readListener.await(Duration.ofMillis(600)); assertThat(readListener.getCount(), equalTo(0)); readListener.resetCount(1); ex = (TimeoutException) pvReader.lastException(); assertThat(ex, not(nullValue())); readListener.await(Duration.ofMillis(1000)); assertThat(readListener.getCount(), equalTo(0)); ex = (TimeoutException) pvReader.lastException(); assertThat(ex, nullValue()); assertThat((String) pvReader.getValue(), equalTo("Initial value")); } @Test public void delayedReadOnPVWithTimeout() throws Exception { CountDownPVReaderListener readListener = new CountDownPVReaderListener(1, PVReaderEvent.VALUE_MASK | PVReaderEvent.EXCEPTION_MASK); pv = PVManager.readAndWrite(channel("delayedConnection")) .timeout(ofMillis(500)) .readListener(readListener) .from(dataSource) .asynchWriteAndMaxReadRate(ofMillis(50)); readListener.await(Duration.ofMillis(50)); assertThat(readListener.getCount(), equalTo(1)); TimeoutException ex = (TimeoutException) pv.lastException(); assertThat(ex, nullValue()); readListener.await(Duration.ofMillis(600)); assertThat(readListener.getCount(), equalTo(0)); readListener.resetCount(1); ex = (TimeoutException) pv.lastException(); assertThat(ex, not(nullValue())); readListener.await(Duration.ofMillis(600)); assertThat(readListener.getCount(), equalTo(0)); ex = (TimeoutException) pv.lastException(); assertThat(ex, nullValue()); assertThat((String) pv.getValue(), equalTo("Initial value")); } @Test public void delayedReadOnPVWithTimeoutAndCustomMessage() throws Exception { String message = "Ouch! Timeout!"; CountDownPVReaderListener readListener = new CountDownPVReaderListener(1); pv = PVManager.readAndWrite(channel("delayedConnection")) .readListener(readListener) .timeout(ofMillis(500), message) .from(dataSource) .asynchWriteAndMaxReadRate(ofMillis(50)); readListener.await(Duration.ofMillis(50)); assertThat(readListener.getCount(), equalTo(1)); TimeoutException ex = (TimeoutException) pv.lastException(); assertThat(ex, nullValue()); readListener.await(Duration.ofMillis(600)); assertThat(readListener.getCount(), equalTo(0)); readListener.resetCount(2); ex = (TimeoutException) pv.lastException(); assertThat(ex, not(nullValue())); assertThat(ex.getMessage(), equalTo(message)); readListener.await(Duration.ofMillis(1000)); // It may get CONNECTION and VALUE event separate assertThat(readListener.getCount(), lessThanOrEqualTo(1)); ex = (TimeoutException) pv.lastException(); assertThat(ex, nullValue()); assertThat((String) pv.getValue(), equalTo("Initial value")); } @Test public void delayedMultipleReadWithConnectionError() throws Exception { CountDownPVReaderListener readListener1 = new CountDownPVReaderListener(1); CountDownPVReaderListener readListener2 = new CountDownPVReaderListener(1); pvReader = PVManager.read(channel("delayedConnectionError")) .readListener(readListener1) .from(dataSource).maxRate(ofMillis(50)); pvReader2 = PVManager.read(channel("delayedConnectionError")) .readListener(readListener2) .from(dataSource).maxRate(ofMillis(50)); Thread.sleep(50); RuntimeException ex = (RuntimeException) pvReader.lastException(); assertThat(ex, nullValue()); assertThat(readListener1.getCount(), equalTo(1)); ex = (RuntimeException) pvReader2.lastException(); assertThat(ex, nullValue()); assertThat(readListener2.getCount(), equalTo(1)); readListener1.await(Duration.ofMillis(1500)); readListener1.resetCount(1); readListener2.await(Duration.ofMillis(1500)); readListener2.resetCount(1); ex = (RuntimeException) pvReader.lastException(); assertThat(ex, instanceOf(RuntimeException.class)); assertThat(ex.getMessage(), equalTo("Connection error")); ex = (RuntimeException) pvReader2.lastException(); assertThat(ex, instanceOf(RuntimeException.class)); assertThat(ex.getMessage(), equalTo("Connection error")); } }