All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.specto.hoverfly.junit.api.OkHttpHoverflyClient Maven / Gradle / Ivy

package io.specto.hoverfly.junit.api;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.specto.hoverfly.junit.api.command.DestinationCommand;
import io.specto.hoverfly.junit.api.command.JournalSearchCommand;
import io.specto.hoverfly.junit.api.command.ModeCommand;
import io.specto.hoverfly.junit.api.command.SortParams;
import io.specto.hoverfly.junit.api.model.ModeArguments;
import io.specto.hoverfly.junit.api.view.DiffView;
import io.specto.hoverfly.junit.api.view.HoverflyInfoView;
import io.specto.hoverfly.junit.api.view.StateView;
import io.specto.hoverfly.junit.core.HoverflyMode;
import io.specto.hoverfly.junit.core.model.Journal;
import io.specto.hoverfly.junit.core.model.Simulation;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class OkHttpHoverflyClient implements HoverflyClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(HoverflyClient.class);

    private static final String HEALTH_CHECK_PATH = "api/health";
    private static final String SIMULATION_PATH = "api/v2/simulation";
    private static final String INFO_PATH = "api/v2/hoverfly";
    private static final String DESTINATION_PATH = "api/v2/hoverfly/destination";
    private static final String MODE_PATH = "api/v2/hoverfly/mode";
    private static final String JOURNAL_PATH = "api/v2/journal";
    private static final String STATE_PATH = "api/v2/state";
    private static final String DIFF_PATH = "api/v2/diff";

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final MediaType JSON = MediaType.parse("application/json");

    private OkHttpClient client;

    private HttpUrl baseUrl;

    OkHttpHoverflyClient(String scheme, String host, int port, String authToken) {
        OBJECT_MAPPER.registerModule(new JavaTimeModule());
        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        if (authToken != null ) {
            clientBuilder.addInterceptor(new AuthHeaderInterceptor(authToken));
        }
        this.client = clientBuilder.build();
        this.baseUrl = new HttpUrl.Builder()
                .scheme(scheme)
                .host(host)
                .port(port)
                .build();
    }

    @Override
    public void setSimulation(Simulation simulation) {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(SIMULATION_PATH);
            final RequestBody body = createRequestBody(simulation);
            final Request request = builder.put(body).build();
            exchange(request);
        } catch (Exception e) {
            LOGGER.warn("Failed to set simulation: {}", e.getMessage());
            throw new HoverflyClientException("Failed to set simulation: " + e.getMessage());
        }
    }

    @Override
    public void setSimulation(String simulation) {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(SIMULATION_PATH);
            final RequestBody body = RequestBody.create(JSON, simulation);
            final Request request = builder.put(body).build();
            exchange(request);
        } catch (Exception e) {
            LOGGER.warn("Failed to set simulation: {}", e.getMessage());
            throw new HoverflyClientException("Failed to set simulation: " + e.getMessage());
        }
    }

    @Override
    public Simulation getSimulation() {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(SIMULATION_PATH);
            final Request request = builder.get().build();
            return exchange(request, Simulation.class);
        } catch (Exception e) {
            LOGGER.warn("Failed to get simulation: {}", e.getMessage());
            throw new HoverflyClientException("Failed to get simulation: " + e.getMessage());
        }
    }

    @Override
    public JsonNode getSimulationJson() {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(SIMULATION_PATH);
            final Request request = builder.get().build();
            try (Response response = client.newCall(request).execute()) {
                onFailure(response);
                return OBJECT_MAPPER.readTree(response.body().string());
            }
        } catch (Exception e) {
            LOGGER.warn("Failed to get simulation: {}", e.getMessage());
            throw new HoverflyClientException("Failed to get simulation: " + e.getMessage());
        }
    }

    @Override
    public void deleteSimulation() {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(SIMULATION_PATH);
            final Request request = builder.delete().build();
            exchange(request);
        } catch (Exception e) {
            LOGGER.warn("Failed to delete simulation: {}", e.getMessage());
            throw new HoverflyClientException("Failed to delete simulation: " + e.getMessage());
        }
    }

    @Override
    public Journal getJournal(int offset, int limit) {
        return getJournalInternal(offset, limit, null);
    }

    @Override
    public Journal getJournal(int offset, int limit, SortParams sortParams) {
        return getJournalInternal(offset, limit, sortParams);
    }

    @Override
    public Journal searchJournal(io.specto.hoverfly.junit.core.model.Request requestMatcher) {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(JOURNAL_PATH);
            final RequestBody body = createRequestBody(new JournalSearchCommand(requestMatcher));
            final Request request = builder.post(body).build();
            return exchange(request, Journal.class);
        } catch (Exception e) {
            LOGGER.warn("Failed to search journal: {}", e.getMessage());
            throw new HoverflyClientException("Failed to search journal: " + e.getMessage());
        }
    }


    @Override
    public void deleteJournal() {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(JOURNAL_PATH);
            final Request request = builder.delete().build();
            exchange(request);
        } catch (Exception e) {
            LOGGER.warn("Failed to delete journal: {}", e.getMessage());
            throw new HoverflyClientException("Failed to delete journal: " + e.getMessage());
        }
    }

    @Override
    public void deleteState() {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(STATE_PATH);
            final Request request = builder.delete().build();
            exchange(request);
        } catch (Exception e) {
            LOGGER.warn("Failed to delete states: {}", e.getMessage());
            throw new HoverflyClientException("Failed to delete states: " + e.getMessage());
        }
    }

    @Override
    public StateView getState() {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(STATE_PATH);
            final Request request = builder.get().build();
            return exchange(request, StateView.class);
        } catch (Exception e) {
            LOGGER.warn("Failed to get state: {}", e.getMessage());
            throw new HoverflyClientException("Failed to get state: " + e.getMessage());
        }
    }
  
    @Override
    public DiffView getDiffs() {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(DIFF_PATH);
            final Request request = builder.get().build();
            return exchange(request, DiffView.class);
        } catch (Exception e) {
            LOGGER.warn("Failed to get diffs: {}", e.getMessage());
            throw new HoverflyClientException("Failed to get diffs: " + e.getMessage());
        }
    }

    @Override
    public void setState(final StateView stateView) {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(STATE_PATH);
            final RequestBody body = createRequestBody(stateView);
            final Request request = builder.put(body).build();
            exchange(request);
        } catch (Exception e) {
            LOGGER.warn("Failed to set states: {}", e.getMessage());
            throw new HoverflyClientException("Failed to set states: " + e.getMessage());
        }
    }

    @Override
    public void updateState(final StateView stateView) {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(STATE_PATH);
            final RequestBody body = createRequestBody(stateView);
            final Request request = builder.patch(body).build();
            exchange(request);
        } catch (Exception e) {
            LOGGER.warn("Failed to update states: {}", e.getMessage());
            throw new HoverflyClientException("Failed to update states: " + e.getMessage());
        }
    }

    @Override
    public void cleanDiffs() {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(DIFF_PATH);
            final Request request = builder.delete().build();
            exchange(request);
        } catch (Exception e) {
            LOGGER.warn("Failed to delete diffs: {}", e.getMessage());
            throw new HoverflyClientException("Failed to delete diffs: " + e.getMessage());
        }
    }

    @Override
    public HoverflyInfoView getConfigInfo() {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(INFO_PATH);
            final Request request = builder.get().build();
            return exchange(request, HoverflyInfoView.class);
        } catch (Exception e) {
            LOGGER.warn("Failed to get config information: {}", e.getMessage());
            throw new HoverflyClientException("Failed to get config information: " + e.getMessage());
        }
    }

    @Override
    public void setDestination(String destination) {
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(DESTINATION_PATH);
            final RequestBody body = createRequestBody(new DestinationCommand(destination));
            final Request request = builder.put(body).build();

            exchange(request);
        } catch (Exception e) {
            LOGGER.warn("Failed to set destination: {}", e.getMessage());
            throw new HoverflyClientException("Failed to set destination: " + e.getMessage());
        }
    }

    @Override
    public void setMode(HoverflyMode mode) {
        putModeRequest(new ModeCommand(mode));
    }

    @Override
    public void setMode(HoverflyMode mode, ModeArguments modeArguments) {
        putModeRequest(new ModeCommand(mode, modeArguments));
    }

    @Override
    public boolean getHealth() {
        boolean isHealthy = false;
        try {
            final Request.Builder builder = createRequestBuilderWithUrl(HEALTH_CHECK_PATH);
            final Request request = builder.get().build();
            exchange(request);
            isHealthy = true;
        } catch (Exception e) {
            LOGGER.debug("Hoverfly healthcheck failed: " + e.getMessage());
        }
        return isHealthy;
    }

    private Journal getJournalInternal(int offset, int limit, SortParams sortParams) {
        try {
            HttpUrl.Builder urlBuilder = baseUrl.newBuilder()
                    .addPathSegments(JOURNAL_PATH)
                    .addQueryParameter("offset", String.valueOf(offset))
                    .addQueryParameter("limit", String.valueOf(limit));

            if (sortParams != null) {
                urlBuilder.addQueryParameter("sort", sortParams.toString());
            }
            final Request.Builder builder = new Request.Builder()
                    .url(urlBuilder.build());
            final Request request = builder.get().build();
            return exchange(request, Journal.class);
        } catch (Exception e) {
            LOGGER.warn("Failed to get journal: {}", e.getMessage());
            throw new HoverflyClientException("Failed to get journal: " + e.getMessage());
        }
    }

    private void putModeRequest(ModeCommand modeCommand) {
        try {
            final RequestBody body = createRequestBody(modeCommand);
            final Request.Builder builder = createRequestBuilderWithUrl(MODE_PATH);
            final Request request = builder.put(body).build();

            exchange(request);
        } catch (IOException e) {
            LOGGER.warn("Failed to set mode: {}", e.getMessage());
            throw new HoverflyClientException("Failed to set mode: " + e.getMessage());
        }
    }

    // Create request builder from Admin API path
    private Request.Builder createRequestBuilderWithUrl(String path) {
        return new Request.Builder()
                .url(baseUrl.newBuilder().addPathSegments(path).build());
    }


    // Convert object to JSON request body
    private RequestBody createRequestBody(Object data) throws JsonProcessingException {
        String content = OBJECT_MAPPER.writeValueAsString(data);
        return RequestBody.create(JSON, content);
    }


    // Deserialize response body on success
    private  T exchange(Request request, Class clazz) throws IOException {
        try (Response response = client.newCall(request).execute()) {
            onFailure(response);
            return OBJECT_MAPPER.readValue(response.body().string(), clazz);
        }
    }

    // Does nothing on success
    private void exchange(Request request) throws IOException {
        try (Response response = client.newCall(request).execute()) {
            onFailure(response);
        }
    }

    // Handle non-successful response
    private void onFailure(Response response) throws IOException {
        if (!response.isSuccessful()) {
            String errorResponse = String.format("Unexpected response (code=%d, message=%s)", response.code(), response.body().string());
            throw new IOException(errorResponse);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy