// Path: marketdata-common/src/main/java/com/handson/dto/Quote.java
// public class Quote {
// 
//     public final String code;
//     public final double quote;
// 
//     public Quote(String code, double quote) {
//         this.code = code;
//         this.quote = quote;
//     }
// 
//     public static Quote fromJson(String input) {
//         return new Gson().fromJson(input, Quote.class);
//     }
// 
//     public String toJson() {
//         return new Gson().toJson(this);
//     }
// 
//     @Override
//     public String toString() {
//         return toJson();
//     }
// }
// 
// Path: marketdata-common/src/main/java/com/handson/infra/EventStreamClient.java
// public interface EventStreamClient {
// 
//     Observable<String> readServerSideEvents();
// }
// 
// Path: marketdata-common/src/main/java/com/handson/infra/HttpRequest.java
// public class HttpRequest {
// 
//     private final Map<String, List<String>> parameters;
// 
//     public HttpRequest(Map<String, List<String>> parameters) {
//         this.parameters = parameters;
//     }
// 
//     public String getParameter(String name) {
//         if (parameters.get(name) == null) {
//             return null;
//         }
//         return parameters.get(name).get(0);
//     }
// }


import com.handson.dto.Quote;
import com.handson.infra.EventStreamClient;
import com.handson.infra.HttpRequest;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import rx.Observable;
import rx.marble.HotObservable;
import rx.marble.junit.MarbleRule;
import java.util.Arrays;
import java.util.Collections;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static rx.marble.MapHelper.of;
import static rx.marble.junit.MarbleRule.*;
        stockQuoteServer.getEvents(request).takeUntil(stopSource).subscribe();
        // then
        expectSubscriptions(forexSource.getSubscriptions())
                .toBe("^-----!-");
    }

    /**
     * Test 16
     */
    @Test
    @Ignore
    public void should_send_an_error_when_no_forex_data_after_five_seconds() {
        // given
        Observable<String> quoteSource
                = hot("-g-----", of("g", new Quote("GOOGL", 1300).toJson()));
        Observable<String> forexSource
                = hot("-------");
        // when
        StockQuoteServer stockQuoteServer = createServer(quoteSource, forexSource);
        HttpRequest request = createRequest("code", "GOOGL");
        // then
        expectObservable(stockQuoteServer.getEvents(request))
                .toBe("------#");
    }

    public HttpRequest createRequest(String name, String value) {
        return new HttpRequest(Collections.singletonMap(name, Arrays.asList(value)));
    }

    public StockQuoteServer createServer(Observable<String> quoteSource, Observable<String> forexSource) {
// Path: marketdata-common/src/main/java/com/handson/dto/Quote.java
// public class Quote {
// 
//     public final String code;
//     public final double quote;
// 
//     public Quote(String code, double quote) {
//         this.code = code;
//         this.quote = quote;
//     }
// 
//     public static Quote fromJson(String input) {
//         return new Gson().fromJson(input, Quote.class);
//     }
// 
//     public String toJson() {
//         return new Gson().toJson(this);
//     }
// 
//     @Override
//     public String toString() {
//         return toJson();
//     }
// }
// 
// Path: marketdata-common/src/main/java/com/handson/infra/EventStreamClient.java
// public interface EventStreamClient {
// 
//     Observable<String> readServerSideEvents();
// }
// 
// Path: marketdata-common/src/main/java/com/handson/infra/HttpRequest.java
// public class HttpRequest {
// 
//     private final Map<String, List<String>> parameters;
// 
//     public HttpRequest(Map<String, List<String>> parameters) {
//         this.parameters = parameters;
//     }
// 
//     public String getParameter(String name) {
//         if (parameters.get(name) == null) {
//             return null;
//         }
//         return parameters.get(name).get(0);
//     }
// }


// Path: marketdata-web/src/test/java/com/handson/rx/StockQuoteServerTest.java
import com.handson.dto.Quote;
import com.handson.infra.EventStreamClient;
import com.handson.infra.HttpRequest;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import rx.Observable;
import rx.marble.HotObservable;
import rx.marble.junit.MarbleRule;
import java.util.Arrays;
import java.util.Collections;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static rx.marble.MapHelper.of;
import static rx.marble.junit.MarbleRule.*;

        stockQuoteServer.getEvents(request).takeUntil(stopSource).subscribe();
        // then
        expectSubscriptions(forexSource.getSubscriptions())
                .toBe("^-----!-");
    }

    /**
     * Test 16
     */
    @Test
    @Ignore
    public void should_send_an_error_when_no_forex_data_after_five_seconds() {
        // given
        Observable<String> quoteSource
                = hot("-g-----", of("g", new Quote("GOOGL", 1300).toJson()));
        Observable<String> forexSource
                = hot("-------");
        // when
        StockQuoteServer stockQuoteServer = createServer(quoteSource, forexSource);
        HttpRequest request = createRequest("code", "GOOGL");
        // then
        expectObservable(stockQuoteServer.getEvents(request))
                .toBe("------#");
    }

    public HttpRequest createRequest(String name, String value) {
        return new HttpRequest(Collections.singletonMap(name, Arrays.asList(value)));
    }

    public StockQuoteServer createServer(Observable<String> quoteSource, Observable<String> forexSource) {
        EventStreamClient stockQuoteEventStreamClient = mock(EventStreamClient.class);