Skip to content

Commit 6a720a9

Browse files
nebhaleyschimke
authored andcommitted
Exceptions Documentation and Testing (#479)
This change adds Javadocs and tests to the exception hierarchy in rsocket- core. This change introduces the first JUnit 5 tests (and a fancy test interface!) as well as using AssertJ to make the assertions more fluent and understandable.
1 parent 074736e commit 6a720a9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+983
-222
lines changed

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ subprojects {
4444
dependency 'com.netflix.spectator:spectator-api:0.63.0'
4545
dependency 'io.netty:netty-buffer:4.1.21.Final'
4646
dependency 'io.aeron:aeron-all:1.4.1'
47-
dependency 'org.hamcrest:hamcrest-library:1.3'
47+
dependency 'org.assertj:assertj-core:3.9.1'
4848
dependency 'org.hdrhistogram:HdrHistogram:2.1.10'
4949
dependency 'org.jctools:jctools-core:2.1.2'
5050
dependency 'org.mockito:mockito-core:2.16.0'
@@ -57,6 +57,7 @@ subprojects {
5757

5858
// TODO: Remove after JUnit5 migration
5959
dependency 'junit:junit:4.12'
60+
dependency 'org.hamcrest:hamcrest-library:1.3'
6061
dependencySet(group: 'org.junit.vintage', version: '5.1.0') {
6162
entry 'junit-vintage-engine'
6263
}

rsocket-core/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@ dependencies {
3333
implementation 'org.slf4j:slf4j-api'
3434

3535
testImplementation 'io.projectreactor:reactor-test'
36-
testImplementation 'org.hamcrest:hamcrest-library'
36+
testImplementation 'org.assertj:assertj-core'
3737
testImplementation 'org.junit.jupiter:junit-jupiter-api'
3838
testImplementation 'org.mockito:mockito-core'
3939

4040
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
4141

4242
// TODO: Remove after JUnit5 migration
4343
testCompileOnly 'junit:junit'
44+
testImplementation 'org.hamcrest:hamcrest-library'
4445
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'
4546
}
4647

rsocket-core/src/main/java/io/rsocket/RSocketClient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package io.rsocket;
1818

1919
import io.netty.buffer.Unpooled;
20-
import io.rsocket.exceptions.ConnectionException;
20+
import io.rsocket.exceptions.ConnectionErrorException;
2121
import io.rsocket.exceptions.Exceptions;
2222
import io.rsocket.internal.LimitableRequestPublisher;
2323
import io.rsocket.internal.UnboundedProcessor;
@@ -150,7 +150,7 @@ private void sendKeepAlive(long ackTimeoutMs, int missedAcks) {
150150
String.format(
151151
"Missed %d keep-alive acks with a threshold of %d and a ack timeout of %d ms",
152152
count, missedAcks, ackTimeoutMs);
153-
throw new ConnectionException(message);
153+
throw new ConnectionErrorException(message);
154154
}
155155
}
156156

rsocket-core/src/main/java/io/rsocket/RSocketServer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
import io.netty.buffer.ByteBuf;
2424
import io.netty.buffer.Unpooled;
25-
import io.rsocket.exceptions.ApplicationException;
25+
import io.rsocket.exceptions.ApplicationErrorException;
2626
import io.rsocket.internal.LimitableRequestPublisher;
2727
import io.rsocket.internal.UnboundedProcessor;
2828
import java.util.function.Consumer;
@@ -253,7 +253,7 @@ private void handleFrame(Frame frame) {
253253
case ERROR:
254254
receiver = channelProcessors.get(streamId);
255255
if (receiver != null) {
256-
receiver.onError(new ApplicationException(Frame.Error.message(frame)));
256+
receiver.onError(new ApplicationErrorException(Frame.Error.message(frame)));
257257
}
258258
break;
259259
case NEXT_COMPLETE:
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2015-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.rsocket.exceptions;
18+
19+
import io.rsocket.frame.ErrorFrameFlyweight;
20+
21+
/**
22+
* Application layer logic generating a Reactive Streams {@code onError} event.
23+
*
24+
* @see <a href="https://github.com/rsocket/rsocket/blob/master/Protocol.md#error-codes">Error
25+
* Codes</a>
26+
*/
27+
public final class ApplicationErrorException extends RSocketException {
28+
29+
private static final long serialVersionUID = 7873267740343446585L;
30+
31+
/**
32+
* Constructs a new exception with the specified message.
33+
*
34+
* @param message the message
35+
* @throws NullPointerException if {@code message} is {@code null}
36+
*/
37+
public ApplicationErrorException(String message) {
38+
super(message);
39+
}
40+
41+
/**
42+
* Constructs a new exception with the specified message and cause.
43+
*
44+
* @param message the message
45+
* @param cause the cause of this exception
46+
* @throws NullPointerException if {@code message} or {@code cause} is {@code null}
47+
*/
48+
public ApplicationErrorException(String message, Throwable cause) {
49+
super(message, cause);
50+
}
51+
52+
@Override
53+
public int errorCode() {
54+
return ErrorFrameFlyweight.APPLICATION_ERROR;
55+
}
56+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2015-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.rsocket.exceptions;
18+
19+
import io.rsocket.frame.ErrorFrameFlyweight;
20+
21+
/**
22+
* The Responder canceled the request but may have started processing it (similar to REJECTED but
23+
* doesn't guarantee lack of side-effects).
24+
*
25+
* @see <a href="https://github.com/rsocket/rsocket/blob/master/Protocol.md#error-codes">Error
26+
* Codes</a>
27+
*/
28+
public final class CanceledException extends RSocketException {
29+
30+
private static final long serialVersionUID = 5074789326089722770L;
31+
32+
/**
33+
* Constructs a new exception with the specified message.
34+
*
35+
* @param message the message
36+
* @throws NullPointerException if {@code message} is {@code null}
37+
*/
38+
public CanceledException(String message) {
39+
super(message);
40+
}
41+
42+
/**
43+
* Constructs a new exception with the specified message and cause.
44+
*
45+
* @param message the message
46+
* @param cause the cause of this exception
47+
* @throws NullPointerException if {@code message} or {@code cause} is {@code null}
48+
*/
49+
public CanceledException(String message, Throwable cause) {
50+
super(message, cause);
51+
}
52+
53+
@Override
54+
public int errorCode() {
55+
return ErrorFrameFlyweight.CANCELED;
56+
}
57+
}

rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionCloseException.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,34 @@
1818

1919
import io.rsocket.frame.ErrorFrameFlyweight;
2020

21-
public class ConnectionCloseException extends RSocketException {
21+
/**
22+
* The connection is being terminated. Sender or Receiver of this frame MUST wait for outstanding
23+
* streams to terminate before closing the connection. New requests MAY not be accepted.
24+
*
25+
* @see <a href="https://github.com/rsocket/rsocket/blob/master/Protocol.md#error-codes">Error
26+
* Codes</a>
27+
*/
28+
public final class ConnectionCloseException extends RSocketException {
2229

23-
private static final long serialVersionUID = -7659717517940756969L;
30+
private static final long serialVersionUID = -2214953527482377471L;
2431

32+
/**
33+
* Constructs a new exception with the specified message.
34+
*
35+
* @param message the message
36+
* @throws NullPointerException if {@code message} is {@code null}
37+
*/
2538
public ConnectionCloseException(String message) {
2639
super(message);
2740
}
2841

42+
/**
43+
* Constructs a new exception with the specified message and cause.
44+
*
45+
* @param message the message
46+
* @param cause the cause of this exception
47+
* @throws NullPointerException if {@code message} or {@code cause} is {@code null}
48+
*/
2949
public ConnectionCloseException(String message, Throwable cause) {
3050
super(message, cause);
3151
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2015-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.rsocket.exceptions;
18+
19+
import io.rsocket.frame.ErrorFrameFlyweight;
20+
21+
/**
22+
* The connection is being terminated. Sender or Receiver of this frame MAY close the connection
23+
* immediately without waiting for outstanding streams to terminate.
24+
*
25+
* @see <a href="https://github.com/rsocket/rsocket/blob/master/Protocol.md#error-codes">Error
26+
* Codes</a>
27+
*/
28+
public final class ConnectionErrorException extends RSocketException implements Retryable {
29+
30+
private static final long serialVersionUID = 512325887785119744L;
31+
32+
/**
33+
* Constructs a new exception with the specified message.
34+
*
35+
* @param message the message
36+
* @throws NullPointerException if {@code message} is {@code null}
37+
*/
38+
public ConnectionErrorException(String message) {
39+
super(message);
40+
}
41+
42+
/**
43+
* Constructs a new exception with the specified message and cause.
44+
*
45+
* @param message the message
46+
* @param cause the cause of this exception
47+
* @throws NullPointerException if {@code message} or {@code cause} is {@code null}
48+
*/
49+
public ConnectionErrorException(String message, Throwable cause) {
50+
super(message, cause);
51+
}
52+
53+
@Override
54+
public int errorCode() {
55+
return ErrorFrameFlyweight.CONNECTION_ERROR;
56+
}
57+
}

rsocket-core/src/main/java/io/rsocket/exceptions/Exceptions.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,49 @@
1616

1717
package io.rsocket.exceptions;
1818

19-
import static io.rsocket.frame.ErrorFrameFlyweight.*;
19+
import static io.rsocket.frame.ErrorFrameFlyweight.APPLICATION_ERROR;
20+
import static io.rsocket.frame.ErrorFrameFlyweight.CANCELED;
21+
import static io.rsocket.frame.ErrorFrameFlyweight.CONNECTION_CLOSE;
22+
import static io.rsocket.frame.ErrorFrameFlyweight.CONNECTION_ERROR;
23+
import static io.rsocket.frame.ErrorFrameFlyweight.INVALID;
24+
import static io.rsocket.frame.ErrorFrameFlyweight.INVALID_SETUP;
25+
import static io.rsocket.frame.ErrorFrameFlyweight.REJECTED;
26+
import static io.rsocket.frame.ErrorFrameFlyweight.REJECTED_RESUME;
27+
import static io.rsocket.frame.ErrorFrameFlyweight.REJECTED_SETUP;
28+
import static io.rsocket.frame.ErrorFrameFlyweight.UNSUPPORTED_SETUP;
2029

2130
import io.rsocket.Frame;
31+
import java.util.Objects;
2232

23-
public class Exceptions {
33+
/** Utility class that generates an exception from a frame. */
34+
public final class Exceptions {
2435

2536
private Exceptions() {}
2637

38+
/**
39+
* Create a {@link RSocketException} from a {@link Frame} that matches the error code it contains.
40+
*
41+
* @param frame the frame to retrieve the error code and message from
42+
* @return a {@link RSocketException} that matches the error code in the {@link Frame}
43+
* @throws NullPointerException if {@code frame} is {@code null}
44+
*/
2745
public static RuntimeException from(Frame frame) {
28-
final int errorCode = Frame.Error.errorCode(frame);
46+
Objects.requireNonNull(frame, "frame must not be null");
2947

48+
int errorCode = Frame.Error.errorCode(frame);
3049
String message = frame.getDataUtf8();
50+
3151
switch (errorCode) {
3252
case APPLICATION_ERROR:
33-
return new ApplicationException(message);
53+
return new ApplicationErrorException(message);
3454
case CANCELED:
35-
return new CancelException(message);
55+
return new CanceledException(message);
3656
case CONNECTION_CLOSE:
3757
return new ConnectionCloseException(message);
3858
case CONNECTION_ERROR:
39-
return new ConnectionException(message);
59+
return new ConnectionErrorException(message);
4060
case INVALID:
41-
return new InvalidRequestException(message);
61+
return new InvalidException(message);
4262
case INVALID_SETUP:
4363
return new InvalidSetupException(message);
4464
case REJECTED:
@@ -50,8 +70,8 @@ public static RuntimeException from(Frame frame) {
5070
case UNSUPPORTED_SETUP:
5171
return new UnsupportedSetupException(message);
5272
default:
53-
return new InvalidRequestException(
54-
"Invalid Error frame: " + errorCode + " '" + message + "'");
73+
return new IllegalArgumentException(
74+
String.format("Invalid Error frame: %d '%s'", errorCode, message));
5575
}
5676
}
5777
}

0 commit comments

Comments
 (0)