Search in sources :

Example 11 with ErrorInjector

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);
}
Also used : AssertExtensions(io.pravega.test.common.AssertExtensions) ContainerMetadata(io.pravega.segmentstore.server.ContainerMetadata) TimeoutException(java.util.concurrent.TimeoutException) Cleanup(lombok.Cleanup) UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) SegmentProperties(io.pravega.segmentstore.contracts.SegmentProperties) SegmentHandle(io.pravega.segmentstore.storage.SegmentHandle) ByteArrayInputStream(java.io.ByteArrayInputStream) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Duration(java.time.Duration) Operation(io.pravega.segmentstore.server.logs.operations.Operation) StreamSegmentTruncateOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentTruncateOperation) ServiceListeners(io.pravega.segmentstore.server.ServiceListeners) Collection(java.util.Collection) InMemoryStorage(io.pravega.segmentstore.storage.mocks.InMemoryStorage) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) ErrorInjector(io.pravega.test.common.ErrorInjector) StreamSegmentNameUtils(io.pravega.shared.segment.StreamSegmentNameUtils) List(java.util.List) ThreadPooledTestSuite(io.pravega.test.common.ThreadPooledTestSuite) TestStorage(io.pravega.segmentstore.server.TestStorage) MetadataBuilder(io.pravega.segmentstore.server.MetadataBuilder) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Exceptions(io.pravega.common.Exceptions) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) Function(java.util.function.Function) Supplier(java.util.function.Supplier) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) EvictableMetadata(io.pravega.segmentstore.server.EvictableMetadata) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) SegmentMetadata(io.pravega.segmentstore.server.SegmentMetadata) Timeout(org.junit.rules.Timeout) StreamSegmentMapOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentMapOperation) IntentionalException(io.pravega.test.common.IntentionalException) lombok.val(lombok.val) MetadataCheckpointOperation(io.pravega.segmentstore.server.logs.operations.MetadataCheckpointOperation) IOException(java.io.IOException) Test(org.junit.Test) TimeUnit(java.util.concurrent.TimeUnit) Rule(org.junit.Rule) CachedStreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) DataCorruptionException(io.pravega.segmentstore.server.DataCorruptionException) Assert(org.junit.Assert) MergeTransactionOperation(io.pravega.segmentstore.server.logs.operations.MergeTransactionOperation) StreamSegmentSealOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentSealOperation) HashMap(java.util.HashMap) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Cleanup(lombok.Cleanup) SegmentHandle(io.pravega.segmentstore.storage.SegmentHandle) TimeoutException(java.util.concurrent.TimeoutException) IntentionalException(io.pravega.test.common.IntentionalException) IOException(java.io.IOException) DataCorruptionException(io.pravega.segmentstore.server.DataCorruptionException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ByteArrayInputStream(java.io.ByteArrayInputStream) TimeoutException(java.util.concurrent.TimeoutException) Test(org.junit.Test)

Example 12 with ErrorInjector

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);
}
Also used : DataLogWriterNotPrimaryException(io.pravega.segmentstore.storage.DataLogWriterNotPrimaryException) TestDurableDataLog(io.pravega.segmentstore.server.TestDurableDataLog) ErrorInjector(io.pravega.test.common.ErrorInjector) ProbeOperation(io.pravega.segmentstore.server.logs.operations.ProbeOperation) Operation(io.pravega.segmentstore.server.logs.operations.Operation) StorageOperation(io.pravega.segmentstore.server.logs.operations.StorageOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) IOException(java.io.IOException) Cleanup(lombok.Cleanup) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) CancellationException(java.util.concurrent.CancellationException) CompletionException(java.util.concurrent.CompletionException) DataLogWriterNotPrimaryException(io.pravega.segmentstore.storage.DataLogWriterNotPrimaryException) ObjectClosedException(io.pravega.common.ObjectClosedException) StreamSegmentException(io.pravega.segmentstore.contracts.StreamSegmentException) DurableDataLogException(io.pravega.segmentstore.storage.DurableDataLogException) IntentionalException(io.pravega.test.common.IntentionalException) IOException(java.io.IOException) CompletionException(java.util.concurrent.CompletionException) Test(org.junit.Test)

Aggregations

ErrorInjector (io.pravega.test.common.ErrorInjector)12 IOException (java.io.IOException)12 Test (org.junit.Test)12 IntentionalException (io.pravega.test.common.IntentionalException)10 Cleanup (lombok.Cleanup)10 DataCorruptionException (io.pravega.segmentstore.server.DataCorruptionException)9 Operation (io.pravega.segmentstore.server.logs.operations.Operation)9 StreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation)9 StreamSegmentNotExistsException (io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)8 StorageOperation (io.pravega.segmentstore.server.logs.operations.StorageOperation)8 lombok.val (lombok.val)8 Exceptions (io.pravega.common.Exceptions)7 AssertExtensions (io.pravega.test.common.AssertExtensions)7 ThreadPooledTestSuite (io.pravega.test.common.ThreadPooledTestSuite)7 Duration (java.time.Duration)7 ArrayList (java.util.ArrayList)7 HashSet (java.util.HashSet)7 Assert (org.junit.Assert)7 Rule (org.junit.Rule)7 Timeout (org.junit.rules.Timeout)7