1 /*
2  * librest - RESTful web services access
3  * Copyright (c) 2009 Intel Corporation.
4  *
5  * Authors: Rob Bradford <rob@linux.intel.com>
6  *          Ross Burton <ross@linux.intel.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU Lesser General Public License,
10  * version 2.1, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT ANY
13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22 
23 /*
24  * TODO:
25  * - port to gtest
26  * - decide if status 3xx is success or failure
27  * - test query params
28  * - test request headers
29  * - test response headers
30  */
31 
32 #include <config.h>
33 
34 #include <string.h>
35 #include <stdlib.h>
36 #include <libsoup/soup.h>
37 #include <rest/rest-proxy.h>
38 
39 #if SOUP_CHECK_VERSION (2, 28, 0)
40 /* Avoid deprecation warning with newer libsoup */
41 #define soup_message_headers_get soup_message_headers_get_one
42 #endif
43 
44 static int errors = 0;
45 
46 static void
server_callback(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * client,gpointer user_data)47 server_callback (SoupServer *server, SoupMessage *msg,
48                  const char *path, GHashTable *query,
49                  SoupClientContext *client, gpointer user_data)
50 {
51   if (g_str_equal (path, "/ping")) {
52     soup_message_set_status (msg, SOUP_STATUS_OK);
53   }
54   else if (g_str_equal (path, "/echo")) {
55     const char *value;
56 
57     value = g_hash_table_lookup (query, "value");
58     soup_message_set_response (msg, "text/plain", SOUP_MEMORY_COPY,
59                                value, strlen (value));
60     soup_message_set_status (msg, SOUP_STATUS_OK);
61   }
62   else if (g_str_equal (path, "/reverse")) {
63     char *value;
64 
65     value = g_strdup (g_hash_table_lookup (query, "value"));
66     g_strreverse (value);
67 
68     soup_message_set_response (msg, "text/plain", SOUP_MEMORY_TAKE,
69                                value, strlen (value));
70     soup_message_set_status (msg, SOUP_STATUS_OK);
71   }
72   else if (g_str_equal (path, "/status")) {
73     const char *value;
74     int status;
75 
76     value = g_hash_table_lookup (query, "status");
77     if (value) {
78       status = atoi (value);
79       soup_message_set_status (msg, status ?: SOUP_STATUS_INTERNAL_SERVER_ERROR);
80     } else {
81       soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
82     }
83   }
84   else if (g_str_equal (path, "/useragent/none")) {
85     if (soup_message_headers_get (msg->request_headers, "User-Agent") == NULL) {
86       soup_message_set_status (msg, SOUP_STATUS_OK);
87     } else {
88       soup_message_set_status (msg, SOUP_STATUS_EXPECTATION_FAILED);
89     }
90   }
91   else if (g_str_equal (path, "/useragent/testsuite")) {
92     const char *value;
93     value = soup_message_headers_get (msg->request_headers, "User-Agent");
94     if (g_strcmp0 (value, "TestSuite-1.0") == 0) {
95       soup_message_set_status (msg, SOUP_STATUS_OK);
96     } else {
97       soup_message_set_status (msg, SOUP_STATUS_EXPECTATION_FAILED);
98     }
99   }
100 }
101 
102 static void
ping_test(RestProxy * proxy)103 ping_test (RestProxy *proxy)
104 {
105   RestProxyCall *call;
106   GError *error = NULL;
107 
108   call = rest_proxy_new_call (proxy);
109   rest_proxy_call_set_function (call, "ping");
110 
111   if (!rest_proxy_call_run (call, NULL, &error)) {
112     g_printerr ("Call failed: %s\n", error->message);
113     g_error_free (error);
114     errors++;
115     g_object_unref (call);
116     return;
117   }
118   g_assert(error == NULL);
119 
120   if (rest_proxy_call_get_status_code (call) != SOUP_STATUS_OK) {
121     g_printerr ("wrong response code\n");
122     errors++;
123     return;
124   }
125 
126   if (rest_proxy_call_get_payload_length (call) != 0) {
127     g_printerr ("wrong length returned\n");
128     errors++;
129     return;
130   }
131 
132   g_object_unref (call);
133 }
134 
135 static void
echo_test(RestProxy * proxy)136 echo_test (RestProxy *proxy)
137 {
138   RestProxyCall *call;
139   GError *error = NULL;
140 
141   call = rest_proxy_new_call (proxy);
142   rest_proxy_call_set_function (call, "echo");
143   rest_proxy_call_add_param (call, "value", "echome");
144 
145   if (!rest_proxy_call_run (call, NULL, &error)) {
146     g_printerr ("Call failed: %s\n", error->message);
147     g_error_free (error);
148     errors++;
149     g_object_unref (call);
150     return;
151   }
152   g_assert(error == NULL);
153 
154   if (rest_proxy_call_get_status_code (call) != SOUP_STATUS_OK) {
155     g_printerr ("wrong response code\n");
156     errors++;
157     g_object_unref (call);
158     return;
159   }
160   if (rest_proxy_call_get_payload_length (call) != 6) {
161     g_printerr ("wrong length returned\n");
162     errors++;
163     g_object_unref (call);
164     return;
165   }
166   if (g_strcmp0 ("echome", rest_proxy_call_get_payload (call)) != 0) {
167     g_printerr ("wrong string returned\n");
168     errors++;
169     g_object_unref (call);
170     return;
171   }
172   g_object_unref (call);
173 }
174 
175 static void
reverse_test(RestProxy * proxy)176 reverse_test (RestProxy *proxy)
177 {
178   RestProxyCall *call;
179   GError *error = NULL;
180 
181   call = rest_proxy_new_call (proxy);
182   rest_proxy_call_set_function (call, "reverse");
183   rest_proxy_call_add_param (call, "value", "reverseme");
184 
185   if (!rest_proxy_call_run (call, NULL, &error)) {
186     g_printerr ("Call failed: %s\n", error->message);
187     g_error_free (error);
188     errors++;
189     g_object_unref (call);
190     return;
191   }
192   g_assert(error == NULL);
193 
194   if (rest_proxy_call_get_status_code (call) != SOUP_STATUS_OK) {
195     g_printerr ("wrong response code\n");
196     errors++;
197     g_object_unref (call);
198     return;
199   }
200   if (rest_proxy_call_get_payload_length (call) != 9) {
201     g_printerr ("wrong length returned\n");
202     errors++;
203     g_object_unref (call);
204     return;
205   }
206   if (g_strcmp0 ("emesrever", rest_proxy_call_get_payload (call)) != 0) {
207     g_printerr ("wrong string returned\n");
208     errors++;
209     g_object_unref (call);
210     return;
211   }
212   g_object_unref (call);
213 }
214 
215 static void
status_ok_test(RestProxy * proxy,int status)216 status_ok_test (RestProxy *proxy, int status)
217 {
218   RestProxyCall *call;
219   GError *error = NULL;
220   char *status_str;
221 
222   call = rest_proxy_new_call (proxy);
223   rest_proxy_call_set_function (call, "status");
224   status_str = g_strdup_printf ("%d", status);
225   rest_proxy_call_add_param (call, "status", status_str);
226   g_free (status_str);
227 
228   if (!rest_proxy_call_run (call, NULL, &error)) {
229     g_printerr ("Call failed: %s\n", error->message);
230     g_error_free (error);
231     errors++;
232     g_object_unref (call);
233     return;
234   }
235   g_assert(error == NULL);
236 
237   if (rest_proxy_call_get_status_code (call) != status) {
238     g_printerr ("wrong response code, got %d\n", rest_proxy_call_get_status_code (call));
239     errors++;
240     return;
241   }
242 
243   g_object_unref (call);
244 }
245 
246 static void
status_error_test(RestProxy * proxy,int status)247 status_error_test (RestProxy *proxy, int status)
248 {
249   RestProxyCall *call;
250   GError *error = NULL;
251   char *status_str;
252 
253   call = rest_proxy_new_call (proxy);
254   rest_proxy_call_set_function (call, "status");
255   status_str = g_strdup_printf ("%d", status);
256   rest_proxy_call_add_param (call, "status", status_str);
257   g_free (status_str);
258 
259   if (rest_proxy_call_run (call, NULL, &error)) {
260     g_printerr ("Call succeeded should have failed");
261     errors++;
262     g_object_unref (call);
263     return;
264   }
265   g_error_free (error);
266 
267   if (rest_proxy_call_get_status_code (call) != status) {
268     g_printerr ("wrong response code, got %d\n", rest_proxy_call_get_status_code (call));
269     errors++;
270     return;
271   }
272 
273   g_object_unref (call);
274 }
275 
276 static void
test_status_ok(RestProxy * proxy,const char * function)277 test_status_ok (RestProxy *proxy, const char *function)
278 {
279   RestProxyCall *call;
280   GError *error = NULL;
281 
282   call = rest_proxy_new_call (proxy);
283   rest_proxy_call_set_function (call, function);
284 
285   if (!rest_proxy_call_run (call, NULL, &error)) {
286     g_printerr ("%s call failed: %s\n", function, error->message);
287     g_error_free (error);
288     errors++;
289     g_object_unref (call);
290     return;
291   }
292   g_assert(error == NULL);
293 
294   if (rest_proxy_call_get_status_code (call) != SOUP_STATUS_OK) {
295     g_printerr ("wrong response code, got %d\n", rest_proxy_call_get_status_code (call));
296     errors++;
297     return;
298   }
299 
300   g_object_unref (call);
301 }
302 
303 int
main(int argc,char ** argv)304 main (int argc, char **argv)
305 {
306   SoupServer *server;
307   char *url;
308   RestProxy *proxy;
309 
310 #if !GLIB_CHECK_VERSION (2, 36, 0)
311   g_type_init ();
312 #endif
313 
314   server = soup_server_new (NULL);
315   soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
316   soup_server_run_async (server);
317 
318   url = g_strdup_printf ("http://127.0.0.1:%d/", soup_server_get_port (server));
319   proxy = rest_proxy_new (url, FALSE);
320   g_free (url);
321 
322   ping_test (proxy);
323   echo_test (proxy);
324   reverse_test (proxy);
325   status_ok_test (proxy, SOUP_STATUS_OK);
326   status_ok_test (proxy, SOUP_STATUS_NO_CONTENT);
327   /* status_ok_test (proxy, SOUP_STATUS_MULTIPLE_CHOICES); */
328   status_error_test (proxy, SOUP_STATUS_BAD_REQUEST);
329   status_error_test (proxy, SOUP_STATUS_NOT_IMPLEMENTED);
330 
331   test_status_ok (proxy, "useragent/none");
332   rest_proxy_set_user_agent (proxy, "TestSuite-1.0");
333   test_status_ok (proxy, "useragent/testsuite");
334 
335   return errors != 0;
336 }
337