1/*
2 * Copyright (C) 2010 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.i18n.addressinput;
18
19import com.android.i18n.addressinput.JsonpRequestBuilder.AsyncCallback;
20import com.android.i18n.addressinput.testing.AsyncTestCase;
21
22import java.io.IOException;
23import java.io.InputStream;
24import java.io.OutputStream;
25import java.net.ServerSocket;
26import java.net.Socket;
27import java.net.SocketTimeoutException;
28
29public class JsonpRequestBuilderTest extends AsyncTestCase {
30    private JsonpRequestBuilder builder;
31
32    @Override
33    public void setUp() {
34        builder = new JsonpRequestBuilder();
35    }
36
37    public void testRequestObject() throws Exception {
38        delayTestFinish(4000);
39        builder.setTimeout(2000);
40
41        String url = HttpServer.execute(1000, "{\"id\": \"data\"}");
42
43        builder.requestObject(url, new AsyncCallback<JsoMap>() {
44            @Override
45            public void onFailure(Throwable caught) {
46                fail(caught.toString());
47            }
48
49            @Override
50            public void onSuccess(JsoMap result) {
51                assertNotNull(result);
52                assertEquals("data", result.get("id"));
53                finishTest();
54            }
55        });
56    }
57
58    public void testSetTimeout() throws Exception {
59        delayTestFinish(4000);
60        builder.setTimeout(1000);
61
62        String url = HttpServer.execute(2000, "Fubar");
63
64        builder.requestObject(url, new AsyncCallback<JsoMap>() {
65            @Override
66            public void onFailure(Throwable caught) {
67                assertNotNull(caught);
68                assertTrue(caught instanceof SocketTimeoutException);
69                finishTest();
70            }
71
72            @Override
73            public void onSuccess(JsoMap result) {
74                fail("The request should have timed out.");
75            }
76        });
77    }
78
79    public void testUrlEncoding() throws Exception {
80        delayTestFinish(4000);
81        builder.setTimeout(2000);
82
83        String urlBase = HttpServer.execute(1000, "{\"id\": \"data\"}");
84        String url = urlBase + "address/data/VN/B\u1EAFc K\u1EA1n";
85
86        builder.requestObject(url, new AsyncCallback<JsoMap>() {
87            @Override
88            public void onFailure(Throwable caught) {
89                fail(caught.toString());
90            }
91
92            @Override
93            public void onSuccess(JsoMap result) {
94                assertNotNull(result);
95                assertEquals("data", result.get("id"));
96                finishTest();
97            }
98        });
99    }
100
101    /**
102     * Simple implementation of an HTTP server.
103     */
104    private static class HttpServer extends Thread {
105        /**
106         * Start an HTTP server that will serve one request and then terminate.
107         *
108         * @param timeoutMillis
109         *            Wait this long before answering a request.
110         * @param response
111         *            Reply to any request with this response.
112         * @return The URL to the server.
113         * @throws IOException
114         */
115        public static String execute(long timeoutMillis, String response) throws IOException {
116            HttpServer server = new HttpServer(timeoutMillis, response);
117            server.start();
118            return "http://localhost:" + server.serverSocket.getLocalPort() + "/";
119        }
120
121        @Override
122        public void run() {
123            try {
124                Socket clientSocket = serverSocket.accept();
125                try {
126                    synchronized (this) {
127                        wait(waitMillis);
128                    }
129                } catch (InterruptedException e) {
130                    throw new RuntimeException(e);
131                }
132                InputStream inputStream = clientSocket.getInputStream();
133                inputStream.read(new byte[1024]);  // Discard input.
134                OutputStream outputStream = clientSocket.getOutputStream();
135                outputStream.write(response);
136                outputStream.close();
137                inputStream.close();
138                clientSocket.close();
139                serverSocket.close();
140            } catch (IOException e) {
141                throw new RuntimeException(e);
142            }
143        }
144
145        private HttpServer(long waitMillis, String response) throws IOException {
146            this.waitMillis = waitMillis;
147            this.response = (header + response).getBytes();
148            serverSocket = new ServerSocket(0);
149        }
150
151        private long waitMillis;
152        private byte[] response;
153        private ServerSocket serverSocket;
154
155        private static final String header = "HTTP/1.0 200 OK\nContent-Type: text/plain\n\n";
156    }
157}
158