de.codecentric.spring.boot.chaos.monkey.watcher.outgoing.ChaosMonkeyRestTemplateWatcher Maven / Gradle / Ivy
/*
* Copyright 2021-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.codecentric.spring.boot.chaos.monkey.watcher.outgoing;
import de.codecentric.spring.boot.chaos.monkey.component.ChaosMonkeyRequestScope;
import de.codecentric.spring.boot.chaos.monkey.component.ChaosTarget;
import de.codecentric.spring.boot.chaos.monkey.configuration.AssaultProperties;
import de.codecentric.spring.boot.chaos.monkey.configuration.WatcherProperties;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.AbstractClientHttpResponse;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;
/** @author Marcel Becker */
public class ChaosMonkeyRestTemplateWatcher implements ClientHttpRequestInterceptor {
private final WatcherProperties watcherProperties;
private final ChaosMonkeyRequestScope chaosMonkeyRequestScope;
private final AssaultProperties assaultProperties;
public ChaosMonkeyRestTemplateWatcher(final ChaosMonkeyRequestScope chaosMonkeyRequestScope, final WatcherProperties watcherProperties,
AssaultProperties assaultProperties) {
this.chaosMonkeyRequestScope = chaosMonkeyRequestScope;
this.watcherProperties = watcherProperties;
this.assaultProperties = assaultProperties;
}
@Override
public ClientHttpResponse intercept(final HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution)
throws IOException {
ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes);
if (watcherProperties.isRestTemplate()) {
try {
chaosMonkeyRequestScope.callChaosMonkey(ChaosTarget.REST_TEMPLATE, httpRequest.getURI().toString());
} catch (final Exception exception) {
try {
if (exception.getClass().equals(assaultProperties.getException().getExceptionClass())) {
response = new ErrorResponse();
} else {
throw exception;
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
return response;
}
static class ErrorResponse extends AbstractClientHttpResponse {
static final String ERROR_TEXT = "This error is generated by Chaos Monkey for Spring Boot";
static final String ERROR_BODY = "{\"error\": \"This is a Chaos Monkey for Spring Boot generated failure\"}";
private static final Logger Logger = LoggerFactory.getLogger(ErrorResponse.class);
@Nullable
private InputStream responseStream;
@Override
public int getRawStatusCode() {
return HttpStatus.INTERNAL_SERVER_ERROR.value();
}
@Override
public String getStatusText() {
return ERROR_TEXT;
}
@Override
public void close() {
try {
if (this.responseStream == null) {
getBody();
}
StreamUtils.drain(this.responseStream);
this.responseStream.close();
} catch (Exception ex) {
Logger.debug("Exception while closing the error response", ex);
// ignore {@see
// #org.springframework.http.client.SimpleClientHttpResponse.close()}
}
}
@Override
public InputStream getBody() {
responseStream = new ByteArrayInputStream(ERROR_BODY.getBytes(StandardCharsets.UTF_8));
return responseStream;
}
@Override
public HttpHeaders getHeaders() {
return new HttpHeaders();
}
}
}