use of io.pravega.test.common.ErrorInjector in project pravega by pravega.
the class StorageWriterTests method testWithStorageCorruptionErrors.
/**
* Tests the StorageWriter in a Scenario where the Storage component throws data corruption exceptions (i.e., badOffset,
* and after reconciliation, the data is still corrupt).
*/
@Test
public void testWithStorageCorruptionErrors() throws Exception {
@Cleanup TestContext context = new TestContext(DEFAULT_CONFIG);
// Create a bunch of segments and Transactions.
ArrayList<Long> segmentIds = createSegments(context);
// Append data.
HashMap<Long, ByteArrayOutputStream> segmentContents = new HashMap<>();
appendDataBreadthFirst(segmentIds, segmentContents, context);
// Corrupt (one segment should suffice).
byte[] corruptionData = "foo".getBytes();
SegmentHandle corruptedSegmentHandle = InMemoryStorage.newHandle(context.metadata.getStreamSegmentMetadata(segmentIds.get(0)).getName(), false);
Supplier<Exception> exceptionSupplier = () -> {
// Corrupt data. We use an internal method (append) to atomically write data at the end of the segment.
// GetLength+Write would not work well because there may be concurrent writes that modify the data between
// requesting the length and attempting to write, thus causing the corruption to fail.
// NOTE: this is a synchronous call, but append() is also a sync method. If append() would become async,
// care must be taken not to block a thread while waiting for it.
context.storage.append(corruptedSegmentHandle, new ByteArrayInputStream(corruptionData), corruptionData.length);
// Return some other kind of exception.
return new TimeoutException("Intentional");
};
// We only try to corrupt data once.
AtomicBoolean corruptionHappened = new AtomicBoolean();
context.storage.setWriteAsyncErrorInjector(new ErrorInjector<>(c -> !corruptionHappened.getAndSet(true), exceptionSupplier));
AssertExtensions.assertThrows("StorageWriter did not fail when a fatal data corruption error occurred.", () -> {
// The Corruption may happen early enough so the "awaitRunning" isn't complete yet. In that case,
// the writer will never reach its 'Running' state. As such, we need to make sure at least one of these
// will throw (either start or, if the failure happened after start, make sure it eventually fails and shuts down).
context.writer.startAsync().awaitRunning();
ServiceListeners.awaitShutdown(context.writer, TIMEOUT, true);
}, ex -> ex instanceof IllegalStateException);
ServiceListeners.awaitShutdown(context.writer, TIMEOUT, false);
Assert.assertTrue("Unexpected failure cause for StorageWriter.", Exceptions.unwrap(context.writer.failureCause()) instanceof ReconciliationFailureException);
}
use of io.pravega.test.common.ErrorInjector in project pravega by pravega.
the class OperationProcessorTests method testWithDataLogNotPrimaryException.
/**
* Tests the ability of the OperationProcessor handle a DataLogWriterNotPrimaryException.
*/
@Test
public void testWithDataLogNotPrimaryException() throws Exception {
int streamSegmentCount = 1;
int appendsPerStreamSegment = 1;
@Cleanup TestContext context = new TestContext();
// Generate some test data (no need to complicate ourselves with Transactions here; that is tested in the no-failure test).
HashSet<Long> streamSegmentIds = createStreamSegmentsInMetadata(streamSegmentCount, context.metadata);
List<Operation> operations = generateOperations(streamSegmentIds, new HashMap<>(), appendsPerStreamSegment, METADATA_CHECKPOINT_EVERY, false, false);
// Setup an OperationProcessor and start it.
@Cleanup TestDurableDataLog dataLog = TestDurableDataLog.create(CONTAINER_ID, MAX_DATA_LOG_APPEND_SIZE, executorService());
dataLog.initialize(TIMEOUT);
@Cleanup OperationProcessor operationProcessor = new OperationProcessor(context.metadata, context.stateUpdater, dataLog, getNoOpCheckpointPolicy(), executorService());
operationProcessor.startAsync().awaitRunning();
ErrorInjector<Exception> aSyncErrorInjector = new ErrorInjector<>(count -> true, () -> new CompletionException(new DataLogWriterNotPrimaryException("intentional")));
dataLog.setAppendErrorInjectors(null, aSyncErrorInjector);
// Process all generated operations.
List<OperationWithCompletion> completionFutures = processOperations(operations, operationProcessor);
// Wait for all such operations to complete. We are expecting exceptions, so verify that we do.
AssertExtensions.assertThrows("No operations failed.", OperationWithCompletion.allOf(completionFutures)::join, ex -> ex instanceof IOException || ex instanceof DataLogWriterNotPrimaryException);
// Verify that the OperationProcessor automatically shuts down and that it has the right failure cause.
ServiceListeners.awaitShutdown(operationProcessor, TIMEOUT, false);
Assert.assertEquals("OperationProcessor is not in a failed state after fence-out detected.", Service.State.FAILED, operationProcessor.state());
Assert.assertTrue("OperationProcessor did not fail with the correct exception.", operationProcessor.failureCause() instanceof DataLogWriterNotPrimaryException);
}
Aggregations