org.tomitribe.beryllium.mocks.CallsSteps.java Source code

Java tutorial

Introduction

Here is the source code for org.tomitribe.beryllium.mocks.CallsSteps.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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
 *
 * http://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 org.tomitribe.beryllium.mocks;

import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.xebialabs.restito.builder.stub.StubHttp;
import com.xebialabs.restito.semantics.Action;
import com.xebialabs.restito.semantics.Applicable;
import com.xebialabs.restito.semantics.Condition;
import com.xebialabs.restito.semantics.ConditionWithApplicables;
import com.xebialabs.restito.semantics.Function;
import com.xebialabs.restito.server.StubServer;
import cucumber.api.DataTable;
import cucumber.api.java.After;
import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import lombok.Value;
import org.glassfish.grizzly.http.server.Response;
import org.glassfish.grizzly.http.util.HttpStatus;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static com.xebialabs.restito.builder.stub.StubHttp.whenHttp;
import static com.xebialabs.restito.semantics.Action.composite;
import static com.xebialabs.restito.semantics.Action.custom;
import static com.xebialabs.restito.semantics.Action.resourceContent;
import static com.xebialabs.restito.semantics.Action.status;
import static com.xebialabs.restito.semantics.Condition.delete;
import static com.xebialabs.restito.semantics.Condition.get;
import static com.xebialabs.restito.semantics.Condition.parameter;
import static com.xebialabs.restito.semantics.Condition.post;
import static com.xebialabs.restito.semantics.Condition.put;

public class CallsSteps {
    private StubServer server;
    private StubHttp stubHttp;

    @Before
    public void setUp() {
        server = new StubServer(9090).run();
        stubHttp = whenHttp(server);
    }

    @After
    public void tearDown() {
        server.stop();
    }

    @Given("^The call to external service should be:$")
    public void theCallToExternalServiceShouldBe(final DataTable data) throws Throwable {
        final Multimap<Call, Call> calls = Multimaps.index(data.asList(Call.class),
                new com.google.common.base.Function<Call, Call>() {
                    @Override
                    public Call apply(Call call) {
                        return new Call(call.getMethod(), call.getUrl(), -1, null);
                    }
                });

        for (final Map.Entry<Call, Collection<Call>> groupedCalls : calls.asMap().entrySet()) {
            final List<Action> actions = new ArrayList<>(groupedCalls.getValue().size());
            for (Call call : groupedCalls.getValue()) {
                actions.add(composite(status(HttpStatus.getHttpStatus(call.getStatusCode())), resourceContent(Thread
                        .currentThread().getContextClassLoader().getResource("fixtures/" + call.getFilename()))));
            }
            final Call key = groupedCalls.getKey();
            stubHttp.match(key.getHttpMethod(), key.buildQueryParams()).then(sequential(actions));
        }
    }

    /**
     * Creates a composite action which contains all passed actions and
     * executes them one by one on different invocations.
     */
    private static <T extends Applicable> Action sequential(final Iterable<T> actions) {
        return custom(new Function<Response, Response>() {
            private final Iterator<T> iterator = actions.iterator();
            private T last;

            @Override
            public Response apply(final Response input) {
                if (iterator.hasNext())
                    last = iterator.next();
                return last.apply(input);
            }
        });
    }

    @Value
    private static class Call {
        private String method;
        private String url;
        private int statusCode;
        private String filename;

        ConditionWithApplicables getHttpMethod() {
            switch (getMethod().toUpperCase()) {
            case "POST":
                return post(buildUrl());
            case "PUT":
                return put(buildUrl());
            case "DELETE":
                return delete(buildUrl());
            case "GET":
                return get(buildUrl());
            default:
                return get(buildUrl());
            }
        }

        String buildUrl() {
            return (getUrl().contains("?")) ? getUrl().split("\\?")[0] : getUrl();
        }

        Condition buildQueryParams() {
            final String queryParamsStr = (getUrl().contains("?")) ? getUrl().split("\\?")[1] : null;

            final String[] kvs = queryParamsStr != null ? queryParamsStr.split("\\&") : new String[0];
            final List<Condition> conditions = new ArrayList<>();
            for (final String kv : kvs) {
                final String[] sp = kv.split("\\=");
                conditions.add(parameter(sp[0], sp[1]));
            }
            return Condition.composite(conditions.toArray(new Condition[conditions.size()]));
        }
    }
}