Search in sources :

Example 16 with IntentionalException

use of io.pravega.test.common.IntentionalException in project pravega by pravega.

the class RedirectedReadResultEntryTests method testRequestContent.

/**
 * Tests the ability to retry (and switch base) when a failure occurred in requestContent().
 */
@Test
public void testRequestContent() {
    // More than one retry (by design, it will only retry one time; the next time it will simply throw).
    FailureReadResultEntry f1 = new FailureReadResultEntry(ReadResultEntryType.Cache, 1, 1, () -> {
        throw new ObjectClosedException(this);
    });
    RedirectedReadResultEntry e1 = new TestRedirectedReadResultEntry(f1, 0, (o, l) -> f1, executorService());
    AssertExtensions.assertThrows("requestContent did not throw when attempting to retry more than once.", () -> e1.requestContent(TIMEOUT), ex -> ex instanceof ObjectClosedException);
    // Ineligible exception.
    FailureReadResultEntry f2 = new FailureReadResultEntry(ReadResultEntryType.Cache, 1, 1, () -> {
        throw new IllegalArgumentException();
    });
    RedirectedReadResultEntry e2 = new TestRedirectedReadResultEntry(f1, 0, (o, l) -> f2, executorService());
    AssertExtensions.assertThrows("requestContent did not throw when an ineligible exception got thrown.", () -> e2.requestContent(TIMEOUT), ex -> ex instanceof IllegalArgumentException);
    // Given back another Redirect.
    RedirectedReadResultEntry e3 = new TestRedirectedReadResultEntry(f1, 0, (o, l) -> e1, executorService());
    AssertExtensions.assertThrows("requestContent did not throw when retry yielded another RedirectReadResultEntry.", () -> e3.requestContent(TIMEOUT), ex -> ex instanceof ObjectClosedException);
    // Given redirect function fails.
    RedirectedReadResultEntry e4 = new TestRedirectedReadResultEntry(f1, 0, (o, l) -> {
        throw new IntentionalException();
    }, executorService());
    AssertExtensions.assertThrows("requestContent did not throw when retry failed.", () -> e4.requestContent(TIMEOUT), ex -> ex instanceof IntentionalException);
    // One that works correctly.
    AtomicBoolean requestInvoked = new AtomicBoolean();
    FailureReadResultEntry f5 = new FailureReadResultEntry(ReadResultEntryType.Cache, 2, 1, () -> requestInvoked.set(true));
    f1.setCompletionCallback(i -> {
    // Do nothing.
    });
    RedirectedReadResultEntry e5 = new TestRedirectedReadResultEntry(f1, 1, (o, l) -> f5, executorService());
    e5.requestContent(TIMEOUT);
    Assert.assertTrue("requestTimeout was not invoked for successful redirect.", requestInvoked.get());
    Assert.assertEquals("Unexpected result from getCompletionCallback after successful redirect.", f5.getCompletionCallback(), f1.getCompletionCallback());
    Assert.assertEquals("Unexpected result from getRequestedReadLength after successful redirect.", f5.getRequestedReadLength(), e5.getRequestedReadLength());
    Assert.assertEquals("Unexpected result from getStreamSegmentOffset after successful redirect.", f5.getStreamSegmentOffset(), e5.getStreamSegmentOffset());
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ObjectClosedException(io.pravega.common.ObjectClosedException) IntentionalException(io.pravega.test.common.IntentionalException) Test(org.junit.Test)

Example 17 with IntentionalException

use of io.pravega.test.common.IntentionalException in project pravega by pravega.

the class StreamSegmentContainerRegistryTests method testContainerFailureWhileRunning.

/**
 * Tests the ability to detect a container failure and unregister the container in case the container fails while running.
 */
@Test
public void testContainerFailureWhileRunning() throws Exception {
    final int containerId = 123;
    TestContainerFactory factory = new TestContainerFactory();
    @Cleanup StreamSegmentContainerRegistry registry = new StreamSegmentContainerRegistry(factory, executorService());
    ContainerHandle handle = registry.startContainer(containerId, TIMEOUT).join();
    // Register a Listener for the Container.Stop event. Make this a Future since these callbacks are invoked async
    // so they may finish executing after stop() finished.
    CompletableFuture<Integer> stopListenerCallback = new CompletableFuture<>();
    handle.setContainerStoppedListener(stopListenerCallback::complete);
    TestContainer container = (TestContainer) registry.getContainer(handle.getContainerId());
    // Fail the container and wait for it to properly terminate.
    container.fail(new IntentionalException());
    ServiceListeners.awaitShutdown(container, false);
    Assert.assertEquals("Unexpected value passed to Handle.stopListenerCallback or callback was not invoked.", containerId, (int) stopListenerCallback.join());
    AssertExtensions.assertThrows("Container is still registered after failure.", () -> registry.getContainer(containerId), ex -> ex instanceof ContainerNotFoundException);
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) Cleanup(lombok.Cleanup) ContainerNotFoundException(io.pravega.segmentstore.contracts.ContainerNotFoundException) IntentionalException(io.pravega.test.common.IntentionalException) ContainerHandle(io.pravega.segmentstore.server.ContainerHandle) Test(org.junit.Test)

Example 18 with IntentionalException

use of io.pravega.test.common.IntentionalException in project pravega by pravega.

the class WriteQueueTests method testRemoveFinishedWrites.

/**
 * Tests the removeFinishedWrites() method.
 */
@Test
public void testRemoveFinishedWrites() {
    // Just over 1ms.
    final int timeIncrement = 1234 * 1000;
    AtomicLong time = new AtomicLong();
    val q = new WriteQueue(time::get);
    val writes = new ArrayDeque<Write>();
    for (int i = 0; i < ITEM_COUNT; i++) {
        time.addAndGet(timeIncrement);
        val w = new Write(new ByteArraySegment(new byte[i]), new TestWriteLedger(i), new CompletableFuture<>());
        if (i % 2 == 0) {
            // Complete 1 out of two writes.
            w.setEntryId(i);
            w.complete();
        }
        q.add(w);
        writes.addLast(w);
    }
    while (!writes.isEmpty()) {
        val write = writes.pollFirst();
        if (!write.isDone()) {
            val result1 = q.removeFinishedWrites();
            AssertExtensions.assertContainsSameElements("Unexpected value from removeFinishedWrites when there were writes left in the queue.", EnumSet.of(WriteQueue.CleanupStatus.QueueNotEmpty), result1);
            val stats1 = q.getStatistics();
            Assert.assertEquals("Unexpected size after removeFinishedWrites with no effect.", writes.size() + 1, stats1.getSize());
            // Complete this write.
            write.setEntryId(time.get());
            write.complete();
        }
        // Estimate the Expected elapsed time based on the removals.
        long expectedElapsed = write.getQueueAddedTimestamp();
        int removed = 1;
        while (!writes.isEmpty() && writes.peekFirst().isDone()) {
            expectedElapsed += writes.pollFirst().getQueueAddedTimestamp();
            removed++;
        }
        expectedElapsed = (time.get() * removed - expectedElapsed) / AbstractTimer.NANOS_TO_MILLIS / removed;
        val result2 = q.removeFinishedWrites();
        val expectedResult = EnumSet.of(writes.isEmpty() ? WriteQueue.CleanupStatus.QueueEmpty : WriteQueue.CleanupStatus.QueueNotEmpty);
        AssertExtensions.assertContainsSameElements("Unexpected result from removeFinishedWrites.", expectedResult, result2);
        val stats2 = q.getStatistics();
        Assert.assertEquals("Unexpected size after removeFinishedWrites.", writes.size(), stats2.getSize());
        Assert.assertEquals("Unexpected getExpectedProcessingTimeMillis after clear.", expectedElapsed, stats2.getExpectedProcessingTimeMillis());
    }
    // Verify that it does report failed writes when encountered.
    val w3 = new Write(new ByteArraySegment(new byte[1]), new TestWriteLedger(0), new CompletableFuture<>());
    q.add(w3);
    w3.fail(new IntentionalException(), true);
    val result3 = q.removeFinishedWrites();
    AssertExtensions.assertContainsSameElements("Unexpected value from removeFinishedWrites when there were failed writes.", EnumSet.of(WriteQueue.CleanupStatus.QueueEmpty, WriteQueue.CleanupStatus.WriteFailed), result3);
}
Also used : lombok.val(lombok.val) AtomicLong(java.util.concurrent.atomic.AtomicLong) ByteArraySegment(io.pravega.common.util.ByteArraySegment) ArrayDeque(java.util.ArrayDeque) IntentionalException(io.pravega.test.common.IntentionalException) Test(org.junit.Test)

Example 19 with IntentionalException

use of io.pravega.test.common.IntentionalException in project pravega by pravega.

the class DataFrameBuilderTests method testAppendWithCommitFailure.

/**
 * Tests the case when the DataLog fails to commit random frames.
 * Commit errors should affect only the LogItems that were part of it. It should cause data to be dropped
 * and affected appends failed.
 * This should be done both with large and with small LogItems. Large items span multiple frames.
 */
@Test
public void testAppendWithCommitFailure() throws Exception {
    // Fail the commit to DurableDataLog after this many writes.
    int failAt = 7;
    List<TestLogItem> records = DataFrameTestHelpers.generateLogItems(RECORD_COUNT / 2, SMALL_RECORD_MIN_SIZE, SMALL_RECORD_MAX_SIZE, 0);
    records.addAll(DataFrameTestHelpers.generateLogItems(RECORD_COUNT / 2, LARGE_RECORD_MIN_SIZE, LARGE_RECORD_MAX_SIZE, records.size()));
    @Cleanup TestDurableDataLog dataLog = TestDurableDataLog.create(CONTAINER_ID, FRAME_SIZE, executorService());
    dataLog.initialize(TIMEOUT);
    val asyncInjector = new ErrorInjector<Exception>(count -> count >= failAt, IntentionalException::new);
    dataLog.setAppendErrorInjectors(null, asyncInjector);
    AtomicInteger failCount = new AtomicInteger();
    List<DataFrameBuilder.CommitArgs> successCommits = Collections.synchronizedList(new ArrayList<>());
    // Keep a reference to the builder (once created) so we can inspect its failure cause).
    val builderRef = new AtomicReference<DataFrameBuilder>();
    val attemptCount = new AtomicInteger();
    BiConsumer<Throwable, DataFrameBuilder.CommitArgs> errorCallback = (ex, a) -> {
        attemptCount.decrementAndGet();
        // Check that we actually did want an exception to happen.
        Throwable expectedError = Exceptions.unwrap(asyncInjector.getLastCycleException());
        Assert.assertNotNull("An error happened but none was expected: " + ex, expectedError);
        Throwable actualError = Exceptions.unwrap(ex);
        if (!(ex instanceof ObjectClosedException)) {
            // First failure.
            Assert.assertEquals("Unexpected error occurred upon commit.", expectedError, actualError);
        }
        if (builderRef.get().failureCause() != null) {
            checkFailureCause(builderRef.get(), ce -> ce instanceof IntentionalException);
        }
        failCount.incrementAndGet();
    };
    val args = new DataFrameBuilder.Args(ca -> attemptCount.incrementAndGet(), successCommits::add, errorCallback, executorService());
    try (DataFrameBuilder<TestLogItem> b = new DataFrameBuilder<>(dataLog, SERIALIZER, args)) {
        builderRef.set(b);
        try {
            for (val r : records) {
                b.append(r);
            }
            b.close();
        } catch (ObjectClosedException ex) {
            await(() -> b.failureCause() != null, 20);
            // If DataFrameBuilder is closed, then we must have had an exception thrown via the callback before.
            Assert.assertNotNull("DataFrameBuilder is closed, yet failure cause is not set yet.", b.failureCause());
            checkFailureCause(b, ce -> ce instanceof IntentionalException);
        }
    }
    await(() -> successCommits.size() >= attemptCount.get(), 20);
    // Read all committed items.
    val reader = new DataFrameReader<TestLogItem>(dataLog, new TestSerializer(), CONTAINER_ID);
    val readItems = new ArrayList<TestLogItem>();
    DataFrameRecord<TestLogItem> readItem;
    while ((readItem = reader.getNext()) != null) {
        readItems.add(readItem.getItem());
    }
    val lastCommitSeqNo = successCommits.stream().mapToLong(DataFrameBuilder.CommitArgs::getLastFullySerializedSequenceNumber).max().orElse(-1);
    val expectedItems = records.stream().filter(r -> r.getSequenceNumber() <= lastCommitSeqNo).collect(Collectors.toList());
    AssertExtensions.assertListEquals("Items read back do not match expected values.", expectedItems, readItems, TestLogItem::equals);
    // Read all entries in the Log and interpret them as DataFrames, then verify the records can be reconstructed.
    val frames = dataLog.getAllEntries(ri -> DataFrame.read(ri.getPayload(), ri.getLength(), ri.getAddress()));
    // Check the correctness of the commit callback.
    AssertExtensions.assertGreaterThan("Not enough Data Frames were generated.", 1, frames.size());
    Assert.assertEquals("Unexpected number of frames generated.", successCommits.size(), frames.size());
}
Also used : ObjectClosedException(io.pravega.common.ObjectClosedException) AssertExtensions(io.pravega.test.common.AssertExtensions) Exceptions(io.pravega.common.Exceptions) TimeoutException(java.util.concurrent.TimeoutException) Cleanup(lombok.Cleanup) HashMap(java.util.HashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) Supplier(java.util.function.Supplier) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Duration(java.time.Duration) BiConsumer(java.util.function.BiConsumer) Timeout(org.junit.rules.Timeout) Callbacks(io.pravega.common.function.Callbacks) Predicate(java.util.function.Predicate) IntentionalException(io.pravega.test.common.IntentionalException) lombok.val(lombok.val) IOException(java.io.IOException) Test(org.junit.Test) TestDurableDataLog(io.pravega.segmentstore.server.TestDurableDataLog) Collectors(java.util.stream.Collectors) ErrorInjector(io.pravega.test.common.ErrorInjector) List(java.util.List) Rule(org.junit.Rule) ByteArraySegment(io.pravega.common.util.ByteArraySegment) ThreadPooledTestSuite(io.pravega.test.common.ThreadPooledTestSuite) Comparator(java.util.Comparator) Assert(org.junit.Assert) Collections(java.util.Collections) TestDurableDataLog(io.pravega.segmentstore.server.TestDurableDataLog) ArrayList(java.util.ArrayList) Cleanup(lombok.Cleanup) IntentionalException(io.pravega.test.common.IntentionalException) lombok.val(lombok.val) ErrorInjector(io.pravega.test.common.ErrorInjector) AtomicReference(java.util.concurrent.atomic.AtomicReference) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ObjectClosedException(io.pravega.common.ObjectClosedException) Test(org.junit.Test)

Example 20 with IntentionalException

use of io.pravega.test.common.IntentionalException in project pravega by pravega.

the class DataFrameOutputStreamTests method testCommitFailure.

/**
 * Tests the behavior of startNewRecord(), write(byte) and write(byte[]) when the commit callback throws an exception.
 */
@Test
public void testCommitFailure() throws Exception {
    int maxFrameSize = 50;
    // Callback for when a frame is written. If we need to throw an exception, do it; otherwise just remember the frame.
    AtomicReference<DataFrame> writtenFrame = new AtomicReference<>();
    AtomicBoolean throwException = new AtomicBoolean();
    Consumer<DataFrame> callback = df -> {
        if (throwException.get()) {
            throw new IntentionalException();
        }
        writtenFrame.set(df);
    };
    // Test #1: write(byte)
    AtomicInteger usableSpace = new AtomicInteger();
    ByteArrayOutputStream writtenData1 = new ByteArrayOutputStream();
    try (DataFrameOutputStream s = new DataFrameOutputStream(maxFrameSize, callback)) {
        // 1. Call write(byte) until it fails. Check that the correct exception is thrown.
        s.startNewRecord();
        throwException.set(true);
        AssertExtensions.assertThrows("write() did not throw when the commit callback threw an exception.", () -> {
            for (int i = 0; i < maxFrameSize; i++) {
                s.write((byte) usableSpace.get());
                writtenData1.write((byte) usableSpace.get());
                usableSpace.incrementAndGet();
            }
        }, ex -> ex instanceof IntentionalException);
        // 2. Call write(byte) again and verify it fails. But this should fail because the DataFrame is sealed
        // (it was sealed prior to the current commit attempt).
        AssertExtensions.assertThrows("write() did not throw when the frame was sealed post-commit failure.", () -> s.write((byte) 1), ex -> ex instanceof IllegalStateException);
        // 3. Allow the commit to succeed. Verify a frame has been committed with the correct content.
        throwException.set(false);
        s.flush();
        Assert.assertNotNull("No frame has been created when a frame was filled.", writtenFrame.get());
        ArrayList<byte[]> records = new ArrayList<>();
        records.add(writtenData1.toByteArray());
        DataFrameTestHelpers.checkReadRecords(readFrame(writtenFrame.get()), records, ByteArraySegment::new);
    }
    // Test #2: startNewRecord()
    ByteArrayOutputStream writtenData2 = new ByteArrayOutputStream();
    writtenFrame.set(null);
    try (DataFrameOutputStream s = new DataFrameOutputStream(maxFrameSize, callback)) {
        // 1. Call write(byte) until we fill up the frame
        throwException.set(false);
        s.startNewRecord();
        for (int i = 0; i < usableSpace.get(); i++) {
            s.write((byte) i);
            writtenData2.write((byte) i);
        }
        // 2. Call startNewRecord(). This should fail because it will try to commit the frame.
        throwException.set(true);
        AssertExtensions.assertThrows("startNewRecord() did not throw when the commit callback threw an exception.", s::startNewRecord, ex -> ex instanceof IntentionalException);
        // 3. Allow the commit to succeed. Verify a frame has been committed with the correct content.
        throwException.set(false);
        s.flush();
        Assert.assertNotNull("No frame has been created when a frame was filled.", writtenFrame.get());
        ArrayList<byte[]> records = new ArrayList<>();
        records.add(writtenData2.toByteArray());
        DataFrameTestHelpers.checkReadRecords(readFrame(writtenFrame.get()), records, ByteArraySegment::new);
    }
    // Test #3: write(byte[])
    writtenFrame.set(null);
    try (DataFrameOutputStream s = new DataFrameOutputStream(maxFrameSize, callback)) {
        // 1. Call write(byte) until we fill up the frame
        throwException.set(false);
        s.startNewRecord();
        for (int i = 0; i < usableSpace.get(); i++) {
            // writtenData2 already contains this.
            s.write((byte) i);
        }
        // 2. Call write(byte[]). This should fail because it will try to commit the frame.
        throwException.set(true);
        AssertExtensions.assertThrows("write(byte[]) did not throw when the commit callback threw an exception.", () -> s.write(new byte[10]), ex -> ex instanceof IntentionalException);
        // 3. Allow the commit to succeed. Verify a frame has been committed with the correct content.
        throwException.set(false);
        s.flush();
        Assert.assertNotNull("No frame has been created when a frame was filled.", writtenFrame.get());
        ArrayList<byte[]> records = new ArrayList<>();
        records.add(writtenData2.toByteArray());
        DataFrameTestHelpers.checkReadRecords(readFrame(writtenFrame.get()), records, ByteArraySegment::new);
    }
}
Also used : ByteArrayOutputStream(java.io.ByteArrayOutputStream) SneakyThrows(lombok.SneakyThrows) AssertExtensions(io.pravega.test.common.AssertExtensions) IntentionalException(io.pravega.test.common.IntentionalException) lombok.val(lombok.val) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Cleanup(lombok.Cleanup) IOException(java.io.IOException) Test(org.junit.Test) AtomicReference(java.util.concurrent.atomic.AtomicReference) Collectors(java.util.stream.Collectors) ArrayList(java.util.ArrayList) Consumer(java.util.function.Consumer) ArrayView(io.pravega.common.util.ArrayView) Rule(org.junit.Rule) ByteArraySegment(io.pravega.common.util.ByteArraySegment) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Timeout(org.junit.rules.Timeout) Assert(org.junit.Assert) ByteArraySegment(io.pravega.common.util.ByteArraySegment) ArrayList(java.util.ArrayList) AtomicReference(java.util.concurrent.atomic.AtomicReference) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IntentionalException(io.pravega.test.common.IntentionalException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) SneakyThrows(lombok.SneakyThrows) AssertExtensions(io.pravega.test.common.AssertExtensions) Collectors(java.util.stream.Collectors) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Test(org.junit.Test)

Aggregations

IntentionalException (io.pravega.test.common.IntentionalException)40 Test (org.junit.Test)39 lombok.val (lombok.val)26 Cleanup (lombok.Cleanup)25 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)16 AtomicReference (java.util.concurrent.atomic.AtomicReference)14 Assert (org.junit.Assert)11 AssertExtensions (io.pravega.test.common.AssertExtensions)10 ArrayList (java.util.ArrayList)10 CompletableFuture (java.util.concurrent.CompletableFuture)10 ByteArrayOutputStream (java.io.ByteArrayOutputStream)9 Duration (java.time.Duration)9 Rule (org.junit.Rule)9 Timeout (org.junit.rules.Timeout)9 StreamSegmentNotExistsException (io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)8 StorageOperation (io.pravega.segmentstore.server.logs.operations.StorageOperation)8 ThreadPooledTestSuite (io.pravega.test.common.ThreadPooledTestSuite)8 HashSet (java.util.HashSet)8 Random (java.util.Random)8 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)8