Skip to content

Commit

Permalink
feat: add HTTP status code to detail message of InfluxException, add …
Browse files Browse the repository at this point in the history
…`GatewayTimeoutException` for `504` (#367)
  • Loading branch information
bednar authored Jun 24, 2022
1 parent 65d0398 commit 6bdad46
Show file tree
Hide file tree
Showing 31 changed files with 154 additions and 100 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## 6.3.0 [unreleased]

### Features
1. [#367](https://github.com/influxdata/influxdb-client-java/pull/367): Add HTTP status code to detail message of `InfluxException`
1. [#367](https://github.com/influxdata/influxdb-client-java/pull/367): Add `GatewayTimeoutException` for HTTP status code 504

## 6.2.0 [2022-06-24]

### Features
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.influxdb.exceptions;

import org.jetbrains.annotations.Nullable;
import retrofit2.Response;

/**
* The exception is thrown if an HTTP 504 response code arrived - Gateway Timeout.
*
* @author Jakub Bednar (bednar@github) (06/23/2022 13:16)
*/
public class GatewayTimeoutException extends InfluxException {

public GatewayTimeoutException(@Nullable final Response<?> cause) {
super(cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
public class InfluxException extends RuntimeException {

private static final Logger LOG = Logger.getLogger(InfluxException.class.getName());
private static final String HTTP_STATUS_CODE_MESSAGE = "HTTP status code: %d; Message: %s";

private final Response<?> response;
private final String message;
Expand Down Expand Up @@ -88,7 +89,7 @@ public String getMessage() {
}

/**
* Gets the reference code unique to the error type. If the reference code is not present than return "0".
* Gets the reference code unique to the error type. If the reference code is not present then return "0".
*
* @return reference code unique to the error type
*/
Expand All @@ -108,7 +109,7 @@ public int reference() {

/**
* Gets the HTTP status code of the unsuccessful response.
* If the response is not present than return "0".
* If the response is not present then return "0".
*
* @return HTTP status code
*/
Expand All @@ -123,7 +124,7 @@ public int status() {

/**
* Gets the HTTP headers from the unsuccessful response.
* If the response is not present than return empty {@code Map}.
* If the response is not present then return empty {@code Map}.
*
* @return HTTP headers
*/
Expand Down Expand Up @@ -155,6 +156,7 @@ public Map<String, Object> errorBody() {
@Nullable
private String messageFromResponse() {
if (response != null) {
int code = response.code();
try {
ResponseBody body = response.errorBody();
if (body != null) {
Expand All @@ -163,7 +165,7 @@ private String messageFromResponse() {
errorBody = new Gson().fromJson(json, new TypeToken<Map<String, Object>>() {
}.getType());
if (errorBody.containsKey("message")) {
return errorBody.get("message").toString();
return String.format(HTTP_STATUS_CODE_MESSAGE, code, errorBody.get("message").toString());
}
}
}
Expand All @@ -177,7 +179,7 @@ private String messageFromResponse() {
.orElse(null);

if (value != null) {
return value;
return String.format(HTTP_STATUS_CODE_MESSAGE, code, value);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.influxdb.exceptions.BadGatewayException;
import com.influxdb.exceptions.BadRequestException;
import com.influxdb.exceptions.ForbiddenException;
import com.influxdb.exceptions.GatewayTimeoutException;
import com.influxdb.exceptions.InfluxException;
import com.influxdb.exceptions.InternalServerErrorException;
import com.influxdb.exceptions.MethodNotAllowedException;
Expand Down Expand Up @@ -138,6 +139,8 @@ protected InfluxException responseToError(@Nonnull final Response<?> response) {
return new BadGatewayException(response);
case 503:
return new ServiceUnavailableException(response);
case 504:
return new GatewayTimeoutException(response);
default:
return new InfluxException(response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void retrofitHttpException() {
})
.isInstanceOf(InfluxException.class)
.hasCauseInstanceOf(HttpException.class)
.hasMessage("Wrong query");
.hasMessage("HTTP status code: 500; Message: Wrong query");
}

@Test
Expand Down Expand Up @@ -172,7 +172,7 @@ void errorBodyInfluxDB() {
Response<Object> response = errorResponse("not found", 404, 15, "{\"code\":\"not found\",\"message\":\"user not found\"}", "X-Platform-Error-Code");
throw new InfluxException(new HttpException(response));
})
.matches((Predicate<Throwable>) throwable -> throwable.getMessage().equals("user not found"));
.matches((Predicate<Throwable>) throwable -> throwable.getMessage().equals("HTTP status code: 404; Message: user not found"));
}

@Test
Expand All @@ -182,7 +182,7 @@ void errorBodyInfluxDBWithoutMsg() {
Response<Object> response = errorResponse("not found", 404, 15, "{\"code\":\"not found\"}", "X-Platform-Error-Code");
throw new InfluxException(new HttpException(response));
})
.matches((Predicate<Throwable>) throwable -> throwable.getMessage().equals("not found"));
.matches((Predicate<Throwable>) throwable -> throwable.getMessage().equals("HTTP status code: 404; Message: not found"));
}

@Test
Expand All @@ -192,7 +192,7 @@ void errorBodyInfluxDBNotJson() {
Response<Object> response = errorResponse("not found", 404, 15, "not-json", "X-Platform-Error-Code");
throw new InfluxException(new HttpException(response));
})
.matches((Predicate<Throwable>) throwable -> throwable.getMessage().equals("not found"));
.matches((Predicate<Throwable>) throwable -> throwable.getMessage().equals("HTTP status code: 404; Message: not found"));
}

@Test
Expand Down Expand Up @@ -314,6 +314,17 @@ void nullResponse() {
.matches((Predicate<Throwable>) throwable -> ((InfluxException) throwable).errorBody().isEmpty());
}

@Test
void messageContainsHttpErrorCode() {
Assertions
.assertThatThrownBy(() -> {
Response<Object> response = errorResponse("Wrong query", 501, 15, "{\"error\": \"error-body\"}");
throw new InfluxException(new HttpException(response));
})
.matches((Predicate<Throwable>) throwable -> throwable.getMessage().equals("HTTP status code: 501; Message: Wrong query"))
.matches((Predicate<Throwable>) throwable -> throwable.toString().equals("com.influxdb.exceptions.InfluxException: HTTP status code: 501; Message: Wrong query"));
}

@Nonnull
private Response<Object> errorResponse(@Nullable final String influxError) {
return errorResponse(influxError, 500);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ void queryError() {
Assertions.assertThatThrownBy(() -> queryClient.query(createCall(), consumer, AbstractQueryApi.ERROR_CONSUMER, () -> {
}, false))
.isInstanceOf(InfluxException.class)
.hasMessage("Flux query is not valid");
.hasMessage("HTTP status code: 500; Message: Flux query is not valid");
}

@Test
Expand Down Expand Up @@ -238,7 +238,7 @@ void queryRawError() {
Assertions.assertThatThrownBy(() -> queryClient.queryRaw(createCall(), consumer, AbstractQueryApi.ERROR_CONSUMER, () -> {
}, false))
.isInstanceOf(InfluxException.class)
.hasMessage("Flux query is not valid");
.hasMessage("HTTP status code: 500; Message: Flux query is not valid");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.influxdb.exceptions.BadGatewayException;
import com.influxdb.exceptions.BadRequestException;
import com.influxdb.exceptions.ForbiddenException;
import com.influxdb.exceptions.GatewayTimeoutException;
import com.influxdb.exceptions.InfluxException;
import com.influxdb.exceptions.InternalServerErrorException;
import com.influxdb.exceptions.MethodNotAllowedException;
Expand Down Expand Up @@ -114,6 +115,7 @@ void exceptionType() {
Assertions.assertThatThrownBy(() -> errorResponse(501)).isInstanceOf(NotImplementedException.class);
Assertions.assertThatThrownBy(() -> errorResponse(502)).isInstanceOf(BadGatewayException.class);
Assertions.assertThatThrownBy(() -> errorResponse(503)).isInstanceOf(ServiceUnavailableException.class);
Assertions.assertThatThrownBy(() -> errorResponse(504)).isInstanceOf(GatewayTimeoutException.class);
Assertions.assertThatThrownBy(() -> errorResponse(550)).isInstanceOf(InfluxException.class);
}

Expand Down Expand Up @@ -202,7 +204,7 @@ void restCallError() {

Assertions.assertThatThrownBy(() -> restClient.execute(call))
.isInstanceOf(InfluxException.class)
.hasMessage("flower not found");
.hasMessage("HTTP status code: 500; Message: flower not found");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class WriteKotlinApiTest : AbstractMockServerTest() {
runBlocking {
writeApi.writeRecord("h2o_feet,location=coyote_creek water_level=1.0 1", WritePrecision.S)
}
}.hasMessageStartingWith("token does not have sufficient permissions")
}.hasMessageStartingWith("HTTP status code: 401; Message: token does not have sufficient permissions")
.isInstanceOf(UnauthorizedException::class.java)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void queryRawError() {
mockServer.enqueue(createErrorResponse());

Assertions.assertThatThrownBy(() -> fluxClient.queryRaw("from(bucket:\"telegraf\")"))
.hasMessage("Flux query is not valid")
.hasMessage("HTTP status code: 500; Message: Flux query is not valid")
.isInstanceOf(InfluxException.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ void queryError() {

Assertions.assertThatThrownBy(() -> fluxClient.query("from(bucket:\"telegraf\")"))
.isInstanceOf(InfluxException.class)
.hasMessage("Flux query is not valid");
.hasMessage("HTTP status code: 500; Message: Flux query is not valid");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ void error() {

Assertions.assertThatThrownBy(() -> fluxClient.query("from(bucket:\"telegraf\")"))
.isInstanceOf(InfluxException.class)
.hasMessageStartingWith("error in building plan while starting program:")
.hasMessageStartingWith("HTTP status code: 500; Message: error in building plan while starting program:")
.hasMessageEndingWith("try bounding 'from' with a call to 'range'");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ void disableRetry() {
.assertValueCount(0)
.assertError(throwable -> {
Assertions.assertThat(throwable).isInstanceOf(InfluxException.class);
Assertions.assertThat(throwable).hasMessage("token is temporarily over quota");
Assertions.assertThat(throwable).hasMessage("HTTP status code: 429; Message: token is temporarily over quota");
return true;
})
.assertNotComplete();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class WriteScalaApiTest extends AnyFunSuite with Matchers with BeforeAndAfter wi
val materialized = source.toMat(sink)(Keep.right)

whenReady(materialized.run().failed) { exc => {
exc.getMessage should be("line protocol poorly formed and no points were written")
exc.getMessage should be("HTTP status code: 500; Message: line protocol poorly formed and no points were written")
exc.getClass should be(classOf[InternalServerErrorException])
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
import com.influxdb.exceptions.UnprocessableEntityException;
import com.influxdb.utils.Arguments;

import org.jetbrains.annotations.NotNull;
import retrofit2.Call;

/**
Expand Down Expand Up @@ -242,7 +241,7 @@ public DeleteApi getDeleteApi() {
return new DeleteApiImpl(retrofit.create(DeleteService.class));
}

@NotNull
@Nonnull
@Override
public InvokableScriptsApi getInvokableScriptsApi() {
return new InvokableScriptsApiImpl(retrofit.create(InvokableScriptsService.class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ void findAuthorizationsByIDNull() {

Assertions.assertThatThrownBy(() -> authorizationsApi.findAuthorizationByID("020f755c3c082000"))
.isInstanceOf(NotFoundException.class)
.hasMessage("authorization not found");
.hasMessage("HTTP status code: 404; Message: authorization not found");
}

@Test
Expand Down Expand Up @@ -321,7 +321,7 @@ void deleteAuthorization() {

Assertions.assertThatThrownBy(() -> authorizationsApi.findAuthorizationByID(createdAuthorization.getId()))
.isInstanceOf(NotFoundException.class)
.hasMessage("authorization not found");
.hasMessage("HTTP status code: 404; Message: authorization not found");
}

@Test
Expand Down Expand Up @@ -350,7 +350,7 @@ void cloneAuthorizationNotFound() {

Assertions.assertThatThrownBy(() -> authorizationsApi.cloneAuthorization("020f755c3c082000"))
.isInstanceOf(NotFoundException.class)
.hasMessage("authorization not found");
.hasMessage("HTTP status code: 404; Message: authorization not found");
}

@Nonnull
Expand Down
6 changes: 3 additions & 3 deletions client/src/test/java/com/influxdb/client/ITBucketsApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ void findBucketByIDNull() {

Assertions.assertThatThrownBy(() -> bucketsApi.findBucketByID("020f755c3c082000"))
.isInstanceOf(NotFoundException.class)
.hasMessage("bucket not found");
.hasMessage("HTTP status code: 404; Message: bucket not found");
}

@Test
Expand Down Expand Up @@ -237,7 +237,7 @@ void deleteBucket() {

Assertions.assertThatThrownBy(() -> bucketsApi.findBucketByID(createBucket.getId()))
.isInstanceOf(NotFoundException.class)
.hasMessage("bucket not found");
.hasMessage("HTTP status code: 404; Message: bucket not found");
}

@Test
Expand Down Expand Up @@ -408,6 +408,6 @@ void cloneBucket() {
void cloneBucketNotFound() {
Assertions.assertThatThrownBy(() -> bucketsApi.cloneBucket(generateName("cloned"), "020f755c3c082000"))
.isInstanceOf(NotFoundException.class)
.hasMessage("bucket not found");
.hasMessage("HTTP status code: 404; Message: bucket not found");
}
}
8 changes: 4 additions & 4 deletions client/src/test/java/com/influxdb/client/ITChecksApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public void updateCheckNotExists() {

Assertions.assertThatThrownBy(() -> checksApi.updateCheck("020f755c3c082000", update))
.isInstanceOf(NotFoundException.class)
.hasMessage("check not found for key \"020f755c3c082000\"");
.hasMessage("HTTP status code: 404; Message: check not found for key \"020f755c3c082000\"");
}

@Test
Expand All @@ -247,15 +247,15 @@ public void deleteCheck() {

Assertions.assertThatThrownBy(() -> checksApi.findCheckByID(found.getId()))
.isInstanceOf(NotFoundException.class)
.hasMessage("check not found for key \"" + found.getId() + "\"");
.hasMessage("HTTP status code: 404; Message: check not found for key \"" + found.getId() + "\"");
}

@Test
public void deleteCheckNotFound() {

Assertions.assertThatThrownBy(() -> checksApi.deleteCheck("020f755c3c082000"))
.isInstanceOf(NotFoundException.class)
.hasMessage("check not found for key \"020f755c3c082000\"");
.hasMessage("HTTP status code: 404; Message: check not found for key \"020f755c3c082000\"");
}

@Test
Expand All @@ -280,7 +280,7 @@ public void findCheckByID() {
public void findCheckByIDNotFound() {
Assertions.assertThatThrownBy(() -> checksApi.findCheckByID("020f755c3c082000"))
.isInstanceOf(NotFoundException.class)
.hasMessage("check not found for key \"020f755c3c082000\"");
.hasMessage("HTTP status code: 404; Message: check not found for key \"020f755c3c082000\"");
}

@Test
Expand Down
Loading

0 comments on commit 6bdad46

Please sign in to comment.