Skip to content

Commit 2985bfa

Browse files
committed
Enhanced assertions on thrown exceptions
1 parent 449dd8c commit 2985bfa

File tree

1 file changed

+68
-14
lines changed

1 file changed

+68
-14
lines changed

hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/TestHFileBlockHeaderCorruption.java

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,27 @@
1818
package org.apache.hadoop.hbase.io.hfile;
1919

2020
import static org.hamcrest.MatcherAssert.assertThat;
21+
import static org.hamcrest.Matchers.allOf;
22+
import static org.hamcrest.Matchers.hasProperty;
2123
import static org.hamcrest.Matchers.instanceOf;
2224
import static org.hamcrest.Matchers.startsWith;
2325
import static org.junit.Assert.assertEquals;
2426
import static org.junit.Assert.assertTrue;
2527
import static org.junit.Assert.fail;
2628

29+
import java.io.ByteArrayOutputStream;
2730
import java.io.Closeable;
2831
import java.io.IOException;
32+
import java.io.PrintStream;
2933
import java.nio.ByteBuffer;
3034
import java.nio.channels.SeekableByteChannel;
35+
import java.nio.charset.StandardCharsets;
3136
import java.nio.file.FileSystems;
3237
import java.nio.file.Files;
3338
import java.nio.file.StandardOpenOption;
3439
import java.time.Instant;
40+
import java.util.LinkedList;
41+
import java.util.List;
3542
import java.util.NoSuchElementException;
3643
import java.util.Random;
3744
import org.apache.hadoop.conf.Configuration;
@@ -47,7 +54,9 @@
4754
import org.apache.hadoop.hbase.testclassification.IOTests;
4855
import org.apache.hadoop.hbase.testclassification.SmallTests;
4956
import org.apache.hadoop.hbase.util.Bytes;
50-
import org.hamcrest.Matchers;
57+
import org.hamcrest.Description;
58+
import org.hamcrest.Matcher;
59+
import org.hamcrest.TypeSafeMatcher;
5160
import org.junit.ClassRule;
5261
import org.junit.Rule;
5362
import org.junit.Test;
@@ -106,8 +115,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionFirstBlock() throws Exception {
106115
consumer.readFully();
107116
fail();
108117
} catch (Exception e) {
109-
assertThat(e, instanceOf(IOException.class));
110-
assertThat(e.getMessage(), startsWith("Invalid onDiskSizeWithHeader="));
118+
assertThat(e, new IsThrowableMatching().withInstanceOf(IOException.class)
119+
.withMessage(startsWith("Invalid onDiskSizeWithHeader=")));
111120
}
112121
assertEquals(0, consumer.getItemsRead());
113122
}
@@ -123,8 +132,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionFirstBlock() throws Exception {
123132
consumer.readFully();
124133
fail();
125134
} catch (Exception e) {
126-
assertThat(e, instanceOf(IllegalArgumentException.class));
127-
assertThat(e.getMessage(), startsWith("newLimit > capacity"));
135+
assertThat(e, new IsThrowableMatching().withInstanceOf(IllegalArgumentException.class)
136+
.withMessage(startsWith("newLimit > capacity")));
128137
}
129138
assertEquals(0, consumer.getItemsRead());
130139
}
@@ -140,8 +149,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionFirstBlock() throws Exception {
140149
consumer.readFully();
141150
fail();
142151
} catch (Exception e) {
143-
assertThat(e, instanceOf(IOException.class));
144-
assertThat(e.getMessage(), Matchers.startsWith("Invalid onDiskSizeWithHeader="));
152+
assertThat(e, new IsThrowableMatching().withInstanceOf(IOException.class)
153+
.withMessage(startsWith("Invalid onDiskSizeWithHeader=")));
145154
}
146155
assertEquals(0, consumer.getItemsRead());
147156
}
@@ -177,8 +186,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionSecondBlock() throws Exception
177186
consumer.readFully();
178187
fail();
179188
} catch (Exception e) {
180-
assertThat(e, instanceOf(IOException.class));
181-
assertThat(e.getMessage(), Matchers.startsWith("Invalid onDiskSizeWithHeader="));
189+
assertThat(e, new IsThrowableMatching().withInstanceOf(IOException.class)
190+
.withMessage(startsWith("Invalid onDiskSizeWithHeader=")));
182191
}
183192
assertEquals(1, consumer.getItemsRead());
184193
}
@@ -194,8 +203,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionSecondBlock() throws Exception
194203
consumer.readFully();
195204
fail();
196205
} catch (Exception e) {
197-
assertTrue(e instanceof IllegalArgumentException);
198-
assertTrue(e.getMessage().startsWith("newLimit > capacity"));
206+
assertThat(e, new IsThrowableMatching().withInstanceOf(IllegalArgumentException.class)
207+
.withMessage(startsWith("newLimit > capacity")));
199208
}
200209
assertEquals(1, consumer.getItemsRead());
201210
}
@@ -211,8 +220,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionSecondBlock() throws Exception
211220
consumer.readFully();
212221
fail();
213222
} catch (Exception e) {
214-
assertTrue(e instanceof IOException);
215-
assertTrue(e.getMessage().startsWith("Invalid onDiskSizeWithHeader="));
223+
assertThat(e, new IsThrowableMatching().withInstanceOf(IOException.class)
224+
.withMessage(startsWith("Invalid onDiskSizeWithHeader=")));
216225
}
217226
assertEquals(1, consumer.getItemsRead());
218227
}
@@ -367,7 +376,7 @@ private interface CloseMethod {
367376
void run() throws IOException;
368377
}
369378

370-
private static <T extends Throwable> void closeQuietly(CloseMethod closeMethod) {
379+
private static void closeQuietly(CloseMethod closeMethod) {
371380
try {
372381
closeMethod.run();
373382
} catch (Throwable e) {
@@ -474,4 +483,49 @@ protected void before() throws Throwable {
474483
}
475484
}
476485
}
486+
487+
/**
488+
* A Matcher implementation that can make basic assertions over a provided {@link Throwable}.
489+
* Assertion failures include the full stacktrace in their description.
490+
*/
491+
private static final class IsThrowableMatching extends TypeSafeMatcher<Throwable> {
492+
493+
private final List<Matcher<? super Throwable>> requirements = new LinkedList<>();
494+
495+
public IsThrowableMatching withInstanceOf(Class<?> type) {
496+
requirements.add(instanceOf(type));
497+
return this;
498+
}
499+
500+
public IsThrowableMatching withMessage(Matcher<String> matcher) {
501+
requirements.add(hasProperty("message", matcher));
502+
return this;
503+
}
504+
505+
@Override
506+
protected boolean matchesSafely(Throwable throwable) {
507+
return allOf(requirements).matches(throwable);
508+
}
509+
510+
@Override
511+
protected void describeMismatchSafely(Throwable item, Description mismatchDescription) {
512+
allOf(requirements).describeMismatch(item, mismatchDescription);
513+
// would be nice if `item` could be provided as the cause of the AssertionError instead.
514+
mismatchDescription.appendText(String.format("%nProvided: "));
515+
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
516+
try (PrintStream ps = new PrintStream(baos, false, StandardCharsets.UTF_8.name())) {
517+
item.printStackTrace(ps);
518+
ps.flush();
519+
}
520+
mismatchDescription.appendText(baos.toString(StandardCharsets.UTF_8.name()));
521+
} catch (Exception e) {
522+
throw new RuntimeException(e);
523+
}
524+
}
525+
526+
@Override
527+
public void describeTo(Description description) {
528+
description.appendDescriptionOf(allOf(requirements));
529+
}
530+
}
477531
}

0 commit comments

Comments
 (0)