/*
* Copyright 2011 Daniel Josefsson
*
* 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 se.dannej.fakehttpserver;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.hamcrest.Description;
import org.hamcrest.StringDescription;
import se.dannej.fakehttpserver.expect.Expectation;
import se.dannej.fakehttpserver.expect.UnexpectedRequestExpectation;
/**
* {@link FakeServer} that uses Jetty.
*/
public class JettyFakeServer implements FakeHttpServer {
private final Server server = new Server();
private final SelectChannelConnector connector = new SelectChannelConnector();
private String serverName;
private final List<Expectation> expectations = new ArrayList<Expectation>();
private Expectation defaultExpectation = new UnexpectedRequestExpectation();
private final Handler handler = new AbstractHandler() {
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
FakeHttpServletRequest fakeHttpServletRequest = new FakeHttpServletRequest(request);
FakeHttpServletResponse fakeHttpServletResponse = new FakeHttpServletResponse(response);
for (Expectation expectation : expectations) {
boolean handled = expectation.handle(fakeHttpServletRequest, fakeHttpServletResponse);
if (handled) {
return;
}
}
defaultExpectation.handle(fakeHttpServletRequest, fakeHttpServletResponse);
}
};
/**
* Create a fake server
* @param port port to listen to
*/
public JettyFakeServer(int port) {
this(port, "jetty-server");
}
/**
* Create a fake server listening to a random available port
*/
public JettyFakeServer() {
this("jetty-server");
}
/**
* Create a fake server
* @param port port to listen to
* @param serverName name to give server in diagnostics
*/
public JettyFakeServer(int port, String serverName) {
this(serverName);
connector.setPort(port);
}
/**
* Create a fake server
* @param serverName name to give server in diagnostics
*/
public JettyFakeServer(String serverName) {
this.serverName = serverName;
server.setConnectors(new Connector[] {connector});
server.setHandler(handler);
}
public int getPort() {
return connector.getLocalPort();
}
/**
* Set the default handler, invoked a request does not match any expectations.
* @param defaultExpectation expectation to invoke for unexpected request
*/
public void setDefaultExpectation(Expectation defaultExpectation) {
this.defaultExpectation = defaultExpectation;
}
/**
* Add an expectation (a request handler) to the server.
*
* @param expectation
*/
@Override
public void addExpectation(final Expectation expectation) {
expectations.add(expectation);
}
@Override
public void start() {
try {
server.start();
} catch (Exception e) {
throw new FakeServerException("Failed starting jetty", e);
}
}
@Override
public void stop() {
if (server.isRunning()) {
try {
server.stop();
} catch (Exception e) {
throw new FakeServerException("Failed stopping jetty", e);
}
}
}
@Override
public boolean isSatisfied(Description mismatchDescription) {
StringBuilder sb = new StringBuilder();
StringDescription description = new StringDescription(sb);
description.appendText(serverName + ":<" + getPort() + ">:\n");
boolean allSatisfied = true;
for (Expectation expectation : expectations) {
allSatisfied &= isExpectationSatisfied(expectation, description);
}
allSatisfied &= isExpectationSatisfied(defaultExpectation, description);
if (!allSatisfied) {
mismatchDescription.appendText(sb.toString());
}
return allSatisfied;
}
private boolean isExpectationSatisfied(Expectation expectation, Description description) {
Description subDescription = new StringDescription();
boolean isSatisfied = expectation.isSatisfied(subDescription);
if (!isSatisfied) {
description.appendValue(subDescription).appendText("\n");
}
return isSatisfied;
}
}