use of io.pravega.client.control.impl.Controller in project pravega by pravega.
the class EventStreamWriterTest method testRetryCloseSegmentSealed.
@Test
public void testRetryCloseSegmentSealed() throws EndOfSegmentException, SegmentTruncatedException {
String scope = "scope";
String streamName = "stream";
StreamImpl stream = new StreamImpl(scope, streamName);
Segment segment1 = new Segment(scope, streamName, 0);
Segment segment2 = new Segment(scope, streamName, 1);
EventWriterConfig config = EventWriterConfig.builder().build();
SegmentOutputStreamFactory streamFactory = Mockito.mock(SegmentOutputStreamFactory.class);
Controller controller = Mockito.mock(Controller.class);
SealedSegmentOutputStream outputStream = new SealedSegmentOutputStream(segment1);
Mockito.when(controller.getCurrentSegments(scope, streamName)).thenReturn(getSegmentsFuture(segment1));
Mockito.when(controller.getSuccessors(segment1)).thenReturn(getReplacement(segment1, segment2));
Mockito.when(streamFactory.createOutputStreamForSegment(eq(segment1), any(), any(), any())).thenAnswer(i -> {
outputStream.callBackForSealed = i.getArgument(1);
return outputStream;
});
JavaSerializer<String> serializer = new JavaSerializer<>();
@Cleanup EventStreamWriter<String> writer = new EventStreamWriterImpl<>(stream, "id", controller, streamFactory, serializer, config, executorService(), executorService(), null);
writer.writeEvent("Foo");
Mockito.verify(controller).getCurrentSegments(any(), any());
assertTrue(outputStream.getUnackedEventsOnSeal().size() > 0);
MockSegmentIoStreams outputStream2 = new MockSegmentIoStreams(segment2, null);
Mockito.when(streamFactory.createOutputStreamForSegment(eq(segment2), any(), any(), any())).thenReturn(outputStream2);
AssertExtensions.assertBlocks(() -> {
// closed invokes flush internally; this call is blocking on flush.
writer.close();
}, () -> {
// trigger release with a segmentSealedException.
outputStream.releaseFlush();
// trigger Sealed Segment call back.
outputStream.invokeSealedCallBack();
});
Mockito.verify(controller, Mockito.times(1)).getCurrentSegments(any(), any());
assertTrue(outputStream2.fetchCurrentSegmentLength().join() > 0);
assertTrue(outputStream2.isClosed());
// the connection to outputStream is closed with the failConnection during SegmentSealed Callback.
assertEquals(serializer.serialize("Foo"), outputStream2.read());
}
use of io.pravega.client.control.impl.Controller in project pravega by pravega.
the class EventStreamWriterTest method testSealInvokesFlushError.
@Test
public void testSealInvokesFlushError() throws SegmentSealedException {
String scope = "scope";
String streamName = "stream";
StreamImpl stream = new StreamImpl(scope, streamName);
Segment segment1 = new Segment(scope, streamName, 0);
Segment segment2 = new Segment(scope, streamName, 1);
EventWriterConfig config = EventWriterConfig.builder().build();
// Setup Mocks.
SegmentOutputStreamFactory streamFactory = Mockito.mock(SegmentOutputStreamFactory.class);
Controller controller = Mockito.mock(Controller.class);
FakeSegmentOutputStream outputStream1 = new FakeSegmentOutputStream(segment1);
SegmentOutputStream outputStream2 = Mockito.mock(SegmentOutputStream.class);
// Simulate a connection failure for inflight event re-write on segment2
RetriesExhaustedException connectionFailure = new RetriesExhaustedException(new ConnectionFailedException("Connection drop"));
Mockito.doAnswer(args -> {
PendingEvent event = args.getArgument(0);
if (event.getAckFuture() != null) {
event.getAckFuture().completeExceptionally(connectionFailure);
}
return null;
}).when(outputStream2).write(any());
// A flush will throw a RetriesExhausted exception.
Mockito.doThrow(connectionFailure).when(outputStream2).flush();
// Enable mocks for the controller calls.
Mockito.when(controller.getCurrentSegments(scope, streamName)).thenReturn(getSegmentsFuture(segment1));
// Successor of segment1 is segment2
Mockito.when(controller.getSuccessors(segment1)).thenReturn(getReplacement(segment1, segment2));
Mockito.when(streamFactory.createOutputStreamForSegment(eq(segment1), any(), any(), any())).thenAnswer(i -> {
outputStream1.callBackForSealed = i.getArgument(1);
return outputStream1;
});
Mockito.when(streamFactory.createOutputStreamForSegment(eq(segment2), any(), any(), any())).thenReturn(outputStream2);
// Start of test
JavaSerializer<String> serializer = new JavaSerializer<>();
@Cleanup EventStreamWriter<String> writer = new EventStreamWriterImpl<>(stream, "id", controller, streamFactory, serializer, config, executorService(), executorService(), null);
// Write an event to the stream.
CompletableFuture<Void> writerFuture = writer.writeEvent("Foo");
Mockito.verify(controller).getCurrentSegments(any(), any());
assertEquals(1, outputStream1.unacked.size());
assertEquals(0, outputStream1.acked.size());
// Simulate segment1 being sealed, now the writer will fetch its successor, segment2, from the Controller
outputStream1.invokeSealedCallBack();
// Verify that the inflight event which is written to segment2 due to sealed segment fails incase of a connection failure.
AssertExtensions.assertThrows(RetriesExhaustedException.class, () -> Futures.getThrowingException(writerFuture));
// Verify that a flush() does indicate this failure.
AssertExtensions.assertThrows(RetriesExhaustedException.class, () -> writer.flush());
}
use of io.pravega.client.control.impl.Controller in project pravega by pravega.
the class PingerTest method startTxnKeepAliveWithLowLeaseValue.
@Test
public void startTxnKeepAliveWithLowLeaseValue() {
final UUID txnID = UUID.randomUUID();
final EventWriterConfig smallTxnLeaseTime = EventWriterConfig.builder().transactionTimeoutTime(SECONDS.toMillis(10)).build();
@Cleanup Pinger pinger = new Pinger(smallTxnLeaseTime.getTransactionTimeoutTime(), stream, controller, executor);
pinger.startPing(txnID);
verify(executor, times(1)).scheduleAtFixedRate(any(Runnable.class), anyLong(), longThat(l -> l > 0 && l <= 10000), eq(TimeUnit.MILLISECONDS));
verify(controller, times(1)).pingTransaction(eq(stream), eq(txnID), eq(smallTxnLeaseTime.getTransactionTimeoutTime()));
}
use of io.pravega.client.control.impl.Controller in project pravega by pravega.
the class PingerTest method startTxnKeepAlive.
@Test
public void startTxnKeepAlive() throws Exception {
final UUID txnID = UUID.randomUUID();
@Cleanup Pinger pinger = new Pinger(config.getTransactionTimeoutTime(), stream, controller, executor);
pinger.startPing(txnID);
verify(executor, times(1)).scheduleAtFixedRate(any(Runnable.class), anyLong(), longThat(i -> i <= config.getTransactionTimeoutTime()), eq(TimeUnit.MILLISECONDS));
verify(controller, times(1)).pingTransaction(eq(stream), eq(txnID), eq(config.getTransactionTimeoutTime()));
}
use of io.pravega.client.control.impl.Controller in project pravega by pravega.
the class ReaderGroupImplTest method testAsyncResetReaderGroup.
@Test(timeout = 10000L)
@SuppressWarnings("unchecked")
public void testAsyncResetReaderGroup() {
UUID rgId = UUID.randomUUID();
ReaderGroupConfig config1 = ReaderGroupConfig.builder().startFromStreamCuts(ImmutableMap.<Stream, StreamCut>builder().put(createStream("s1"), createStreamCut("s1", 2)).build()).build();
config1 = ReaderGroupConfig.cloneConfig(config1, rgId, 0L);
ReaderGroupConfig config2 = ReaderGroupConfig.builder().startFromStreamCuts(ImmutableMap.<Stream, StreamCut>builder().put(createStream("s2"), createStreamCut("s2", 2)).build()).build();
config2 = ReaderGroupConfig.cloneConfig(config2, rgId, 0L);
ReaderGroupConfig config3 = ReaderGroupConfig.builder().startFromStreamCuts(ImmutableMap.<Stream, StreamCut>builder().put(createStream("s3"), createStreamCut("s3", 2)).build()).build();
config3 = ReaderGroupConfig.cloneConfig(config3, rgId, 0L);
AtomicInteger x = new AtomicInteger(0);
CompletableFuture<Void> wait = new CompletableFuture<>();
CompletableFuture<Void> signal = new CompletableFuture<>();
// The client's config.
AtomicReference<ReaderGroupConfig> atomicConfig = new AtomicReference<>(config1);
// The controller's config.
AtomicReference<ReaderGroupConfig> atomicConfigController = new AtomicReference<>(config1);
// return the client's config when calling state.getConfig.
doAnswer(a -> atomicConfig.get()).when(state).getConfig();
when(synchronizer.getState()).thenReturn(state);
// return controllerConfig when calling getReaderGroupConfig.
doAnswer(a -> CompletableFuture.completedFuture(atomicConfigController.get())).when(controller).getReaderGroupConfig(anyString(), anyString());
// update the client config to the controller config whenever we update the StateSync.
doAnswer(a -> {
atomicConfig.set(atomicConfigController.get());
return null;
}).when(synchronizer).updateState(any(StateSynchronizer.UpdateGenerator.class));
// update the controller config with the incremented generation if the generations match.
doAnswer(a -> {
ReaderGroupConfig c = a.getArgument(2);
// the first one to call needs to wait until the second call has been completed.
if (x.getAndIncrement() == 0) {
signal.complete(null);
wait.join();
}
if (c.getGeneration() == atomicConfigController.get().getGeneration()) {
long incGen = c.getGeneration() + 1;
atomicConfigController.set(ReaderGroupConfig.cloneConfig(c, c.getReaderGroupId(), incGen));
return CompletableFuture.completedFuture(incGen);
} else {
CompletableFuture<Long> badFuture = new CompletableFuture<>();
badFuture.completeExceptionally(new ReaderGroupConfigRejectedException("handle"));
return badFuture;
}
}).when(controller).updateReaderGroup(anyString(), anyString(), any(ReaderGroupConfig.class));
// run the first call async.
final ReaderGroupConfig newConf = config2;
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> readerGroup.resetReaderGroup(newConf));
// Once the first call has reached the controller.updateReaderGroup step then signal so he waits.
signal.join();
// start the second call.
readerGroup.resetReaderGroup(config3);
// Once the second is completed stop the wait so the first call can go ahead.
wait.complete(null);
// wait for the first call to complete.
assertTrue(Futures.await(future));
// assert the generation was incremented twice due to two updates.
assertEquals(2L, atomicConfig.get().getGeneration());
assertEquals(2L, atomicConfigController.get().getGeneration());
// assert the first call happened last and the streams are s2.
assertTrue(atomicConfig.get().getStartingStreamCuts().keySet().stream().anyMatch(s -> s.getStreamName().equals("s2")));
assertTrue(atomicConfigController.get().getStartingStreamCuts().keySet().stream().anyMatch(s -> s.getStreamName().equals("s2")));
}
Aggregations