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

com.github.davidmoten.odata.client.TestingService Maven / Gradle / Ivy

package com.github.davidmoten.odata.client;

import static java.util.Arrays.asList;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.github.davidmoten.guavamini.Preconditions;

public final class TestingService {

    public static Builder expectResponse(String path, String responseResourceName) {
        return new Builder().expectResponse(path, responseResourceName);
    }

    public static Builder baseUrl(String url) {
        if (url.endsWith("/")) {
            url = url.substring(0, url.length() - 1);
        }
        return new Builder().baseUrl(url);
    }

    public static Builder pathStyle(PathStyle pathStyle) {
        return new Builder().pathStyle(pathStyle);
    }

    public static Builder builder() {
        return new Builder();
    }
    
    public static final class Response {
        public String resource;
        public final int statusCode;

        public Response(String resource, int statusCode) {
            this.resource = resource;
            this.statusCode = statusCode;
        }
        
        public Response(String text) {
            this(text, HttpURLConnection.HTTP_OK);
        }

        @Override
        public String toString() {
            return "Response [resource=" + resource + ", statusCode=" + statusCode + "]";
        }
    }

    public static abstract class BuilderBase, R> {
        Map responses = new HashMap<>();
        Map requests = new HashMap<>();

        String baseUrl = "https://testing.com";
        PathStyle pathStyle = PathStyle.IDENTIFIERS_AS_SEGMENTS;

        @SuppressWarnings("unchecked")
        public T baseUrl(String baseUrl) {
            this.baseUrl = baseUrl;
            return (T) this;
        }

        @SuppressWarnings("unchecked")
        public T pathStyle(PathStyle pathStyle) {
            this.pathStyle = pathStyle;
            return (T) this;
        }

        public T expectResponse(String path, String responseResourceName,
                RequestHeader... requestHeaders) {
            return expectResponse(path, responseResourceName, HttpMethod.GET, requestHeaders);
        }

        @SuppressWarnings("unchecked")
        public T expectResponse(String path, String responseResourceName, HttpMethod method, int statusCode,
                RequestHeader... requestHeaders) {
            responses.put(toKey(method, baseUrl + path, asList(requestHeaders)),
                    new Response(responseResourceName, statusCode));
            return (T) this;
        }
        
        public T expectResponse(String path, String responseResourceName, HttpMethod method,
                RequestHeader... requestHeaders) {
            return expectResponse(path, responseResourceName, method, HttpURLConnection.HTTP_OK, requestHeaders);
        }

        @SuppressWarnings("unchecked")
        public T expectRequest(String path, String requestResourceName, HttpMethod method,
                RequestHeader... requestHeaders) {
            Preconditions.checkArgument(method != HttpMethod.GET,
                    "GET not expected for a request with content");
            requests.put(toKey(method, baseUrl + path, asList(requestHeaders)),
                    requestResourceName);
            return (T) this;
        }

        @SuppressWarnings("unchecked")
        public T expectRequestAndResponse(String path, String requestResourceName,
                String responseResourceName, HttpMethod method, RequestHeader... requestHeaders) {
            requests.put(toKey(method, baseUrl + path, asList(requestHeaders)),
                    requestResourceName);
            responses.put(toKey(method, baseUrl + path, asList(requestHeaders)),
                    new Response(responseResourceName));
            return (T) this;
        }

        @SuppressWarnings("unchecked")
        public T expectDelete(String path, RequestHeader... requestHeaders) {
            requests.put(toKey(HttpMethod.DELETE, baseUrl + path, asList(requestHeaders)),
                    "DELETE");
            return (T) this;
        }

        private static String toKey(HttpMethod method, String url,
                Collection requestHeaders) {
            return method + "\n  " + url + "\n  " + requestHeaders.stream()
                    .map(x -> x.name() + "=" + x.value()).sorted().collect(Collectors.joining("|"));
        }

        private static final void log(Object o) {
            System.out.println(String.valueOf(o));
        }

        protected HttpService createService() {
            return new HttpService() {

                @Override
                public HttpResponse get(String url, List requestHeaders) {
                    log("Available responses:");
                    responses.entrySet().forEach(r -> log(r.getKey() + "\n=>" + r.getValue()));
                    String key = BuilderBase.toKey(HttpMethod.GET, url, requestHeaders);
                    log("Getting:\n" + key);
                    Response response = responses.get(key);
                    String resourceName = response == null? null: response.resource;
                    if (resourceName == null) {
                        throw new RuntimeException("GET response not found for url=" + url
                                + ", headers=" + requestHeaders);
                    }
                    try {
                        URL resource = TestingService.class.getResource(resourceName);
                        if (resource == null) {
                            throw new RuntimeException(
                                    "resource not found on classpath: " + resourceName);
                        }
                        String text = new String(Files.readAllBytes(Paths.get(resource.toURI())));
                        return new HttpResponse(response.statusCode, text);
                    } catch (IOException | URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public HttpResponse patch(String url, List requestHeaders,
                        InputStream content) {
                    log("PATCH called at " + url);
                    String text = Util.utf8(content);
                    log(text);
                    log("Available requests:");
                    requests.entrySet().forEach(r -> log(r.getKey() + "\n=>" + r.getValue()));
                    log("Calling:");
                    String key = BuilderBase.toKey(HttpMethod.PATCH, url, requestHeaders);
                    log(key);
                    String resourceName = requests.get(key);
                    if (resourceName == null) {
                        throw new RuntimeException("PATCH response not found for url=" + url
                                + ", headers=" + requestHeaders);
                    }
                    try {
                        String expected = new String(Files.readAllBytes(
                                Paths.get(TestingService.class.getResource(resourceName).toURI())));

                        if (Serializer.INSTANCE.matches(expected, text)) {
                            return new HttpResponse(HttpURLConnection.HTTP_NO_CONTENT, null);
                        } else {
                            throw new RuntimeException(
                                    "request does not match expected.\n==== Recieved ====\n" + text
                                            + "\n==== Expected =====\n" + expected);
                        }
                    } catch (IOException | URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public HttpResponse put(String url, List h, InputStream content) {
                    return patch(url, h, content);
                }

                @Override
                public HttpResponse post(String url, List requestHeaders,
                        InputStream content) {
                    log("POST called at " + url);
                    String text = Util.utf8(content);
                    log(text);
                    requests.entrySet().forEach(r -> log(r.getKey() + "\n=>" + r.getValue()));
                    log("Calling:");
                    String key = BuilderBase.toKey(HttpMethod.POST, url, requestHeaders);
                    log(key);
                    String requestResourceName = requests.get(key);
                    if (requestResourceName == null) {
                        throw new RuntimeException("POST request not expected for url=" + url
                                + ", headers=" + requestHeaders);
                    }
                    try {
                        String requestExpected = readResource(url, requestResourceName);
                        if (Serializer.INSTANCE.matches(requestExpected, text)) {
                            String responseResourceName = responses
                                    .get(BuilderBase.toKey(HttpMethod.POST, url, requestHeaders)).resource;
                            String responseExpected = readResource(url, responseResourceName);
                            int responseCode = url.contains("delta") ? HttpURLConnection.HTTP_OK
                                    : HttpURLConnection.HTTP_CREATED;
                            return new HttpResponse(responseCode, responseExpected);
                        } else {
                            throw new RuntimeException(
                                    "request does not match expected.\n==== Received ====\n" + text
                                            + "\n==== Expected =====\n" + requestExpected);
                        }
                    } catch (IOException | URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public HttpResponse delete(String url, List requestHeaders) {
                    log("DELETE called at " + url);
                    requests.entrySet().forEach(r -> log(r.getKey() + "\n=>" + r.getValue()));
                    log("Calling:");
                    String key = BuilderBase.toKey(HttpMethod.DELETE, url, requestHeaders);
                    log(key);

                    String resourceName = requests.get(key);
                    if (resourceName == null) {
                        throw new RuntimeException("DELETE request not expected for url=" + url
                                + ", headers=" + requestHeaders);
                    }
                    return new HttpResponse(HttpURLConnection.HTTP_NO_CONTENT, null);
                }

                @Override
                public Path getBasePath() {
                    return new Path(baseUrl, pathStyle);
                }

                @Override
                public void close() throws Exception {
                    // do nothing
                }

                @Override
                public InputStream getStream(String url, List requestHeaders) {
                    HttpResponse h = get(url, requestHeaders);
                    return new ByteArrayInputStream(h.getText().getBytes(StandardCharsets.UTF_8));
                }

            };
        }

        public abstract R build();
    }

    public static abstract class ContainerBuilder extends BuilderBase, T> {

        public abstract T _create(Context context);

        private Map properties = new HashMap<>();

        @Override
        public T build() {
            return _create(new Context(Serializer.INSTANCE, createService(), properties));
        }

        public ContainerBuilder addProperty(String name, Object value) {
            properties.put(name, value);
            return this;
        }

    }

    public static final class Builder extends BuilderBase {

        @Override
        public HttpService build() {
            return createService();
        }
    }

    private static String readResource(String url, String resourceName)
            throws IOException, URISyntaxException {
        if (resourceName == null) {
            throw new RuntimeException("resource not found for url=" + url);
        }
        return new String(Files
                .readAllBytes(Paths.get(TestingService.class.getResource(resourceName).toURI())));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy