// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.handler.test; import com.google.common.annotations.Beta; import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; import com.yahoo.container.jdisc.LoggingRequestHandler; import com.yahoo.filedistribution.fileacquirer.FileAcquirer; import com.yahoo.jdisc.Metric; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; /** * This is a generic http handler that can be used to mock a service when testing your application on jDISC. * Configuration and necessary files are given to the handle in its configuration. * * Example config: *
* <handler id="MockService"> * <config name="container.handler.test.mockservice"> * <file>myresponses.txt</file> * </config> * <binding>http://*\/my/service/path1/*</binding> * </handler> ** * The file formats supported out of the box is text, see {@link com.yahoo.container.handler.test.MockService.TextFileHandler}. * for descriptions of the format. * * @author Ulf Lilleengen */ @Beta public class MockService extends LoggingRequestHandler { private final MockServiceHandler handler; /** * Create a mock service that mocks an external service using data provided via file distribution. * A custom handler can be created by subclassing and overriding the createHandler method. * * @param executor used to create threads * @param fileAcquirer used to fetch file from config * @param config the mock config for this service * @throws InterruptedException if unable to get data file within timeout * @throws IOException if unable to create handler due to some IO errors */ public MockService(Executor executor, FileAcquirer fileAcquirer, MockserviceConfig config, Metric metric) throws InterruptedException, IOException { super(executor, metric); File dataFile = fileAcquirer.waitFor(config.file(), config.fileAcquirerTimeout(), TimeUnit.SECONDS); this.handler = createHandler(dataFile); } /** * Create a handler for a file. Override this method to handle a custom file syntax of your own. * * @param dataFile the file to read * @return the handler used to handle requests * @throws IOException if errors occurred when loading the file */ protected MockServiceHandler createHandler(File dataFile) throws IOException { if (!dataFile.getName().endsWith(".txt")) { throw new IllegalArgumentException("Default handler only support .txt files"); } return new TextFileHandler(dataFile); } @Override public final HttpResponse handle(HttpRequest request) { try { MockServiceHandler.Key key = handler.createKey(request); MockServiceHandler.Value value = handler.get(key); if (value == null) { return new ErrorResponse(404, key + " was not found"); } return new RawResponse(value.returnCode, value.data, value.contentType); } catch (Exception e) { return new ExceptionResponse(500, e); } } /** * A .txt file handler deals with the following format when reading data: * method:url:responsecode:data * * For instance: * GET:/my/path1:200:{\"foo\":\"bar\"} * PUT:/my/path1:403:{\"error\":\"permission denied\"} * TODO: Support binary files */ private static class TextFileHandler implements MockServiceHandler { private final Map