tests: Adjust byte sizes to better test seeking
[profile/ivi/rygel.git] / tests / rygel-http-response-test.vala
1 /*
2  * Copyright (C) 2010 Nokia Corporation.
3  *
4  * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
5  *                               <zeeshan.ali@nokia.com>
6  *
7  * This file is part of Rygel.
8  *
9  * Rygel is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Rygel is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23
24 // This module contains the common code between the test cases for
25 // HTTPResponse subclasses.
26 using Soup;
27
28 public errordomain Rygel.TestError {
29     SKIP = 77,
30     TIMEOUT
31 }
32
33 public abstract class Rygel.HTTPResponseTest : GLib.Object {
34     public const long MAX_BYTES = 102400;
35
36     protected HTTPServer server;
37     protected HTTPClient client;
38
39     private bool server_done;
40     private bool client_done;
41
42     private MainLoop main_loop;
43
44     protected Cancellable cancellable;
45     private Error error;
46
47     public HTTPResponseTest (Cancellable? cancellable = null) throws Error {
48         this.cancellable = cancellable;
49
50         this.server = new HTTPServer ();
51         this.client = new HTTPClient (this.server.context,
52                                       this.server.uri,
53                                       MAX_BYTES,
54                                       cancellable != null);
55         this.main_loop = new MainLoop (null, false);
56     }
57
58     public HTTPResponseTest.complete () throws Error {
59         this ();
60     }
61
62     public HTTPResponseTest.abort () throws Error {
63         this (new Cancellable ());
64     }
65
66     public virtual void run () throws Error {
67         Timeout.add_seconds (3, this.on_timeout);
68         this.server.message_received.connect (this.on_message_received);
69         this.server.message_aborted.connect (this.on_message_aborted);
70         if (this.cancellable == null) {
71             this.client.completed.connect (this.on_client_completed);
72         } else {
73             this.client_done = true;
74         }
75
76         this.client.run.begin ();
77
78         this.main_loop.run ();
79
80         if (this.error != null) {
81             throw this.error;
82         }
83     }
84
85     internal abstract HTTPResponse create_response (Soup.Message msg)
86                                                     throws Error;
87
88     private void on_client_completed (StateMachine client) {
89         if (this.server_done) {
90             this.main_loop.quit ();
91         }
92
93         this.client_done = true;
94     }
95
96     private void on_response_completed (StateMachine response) {
97         if (this.client_done) {
98             this.main_loop.quit ();
99         }
100
101         this.server_done = true;
102     }
103
104     private void on_message_received (HTTPServer   server,
105                                       Soup.Message msg) {
106         try {
107             var response = this.create_response (msg);
108
109             response.run.begin ();
110
111             response.completed.connect (this.on_response_completed);
112         } catch (Error error) {
113             this.error = error;
114             this.main_loop.quit ();
115
116             return;
117         }
118     }
119
120     private void on_message_aborted (HTTPServer   server,
121                                      Soup.Message msg) {
122         this.cancellable.cancel ();
123     }
124
125     private bool on_timeout () {
126         this.error = new TestError.TIMEOUT ("Timeout");
127         this.main_loop.quit ();
128
129         return false;
130     }
131 }
132
133 public class Rygel.HTTPServer : GLib.Object {
134     private const string SERVER_PATH = "/RygelHTTPServer/Rygel/Test";
135
136     public GUPnP.Context context;
137
138     public string uri {
139         owned get { return "http://" +
140                            this.context.host_ip + ":" +
141                            this.context.port.to_string () +
142                            SERVER_PATH;
143         }
144     }
145
146     public signal void message_received (Soup.Message message);
147     public signal void message_aborted (Soup.Message message);
148
149     public HTTPServer () throws TestError {
150         try {
151             this.context = new GUPnP.Context (null, "lo", 0);
152         } catch (Error error) {
153             throw new TestError.SKIP ("Network context not available");
154         }
155
156         assert (this.context != null);
157         assert (this.context.host_ip != null);
158         assert (this.context.port > 0);
159
160         this.context.server.add_handler (SERVER_PATH, this.server_cb);
161         this.context.server.request_aborted.connect (this.on_request_aborted);
162     }
163
164     private void server_cb (Server        server,
165                             Soup.Message  msg,
166                             string        path,
167                             HashTable?    query,
168                             ClientContext client) {
169         this.context.server.pause_message (msg);
170         this.message_received (msg);
171     }
172
173     private void on_request_aborted (Soup.Server        server,
174                                      Soup.Message       message,
175                                      Soup.ClientContext client) {
176         this.message_aborted (message);
177     }
178 }
179
180 public class Rygel.HTTPClient : GLib.Object, StateMachine {
181     public GUPnP.Context context;
182     public Soup.Message msg;
183     public size_t total_bytes;
184
185     public Cancellable cancellable { get; set; }
186
187     public HTTPClient (GUPnP.Context context,
188                        string        uri,
189                        size_t        total_bytes,
190                        bool          active) {
191         this.context = context;
192         this.total_bytes = total_bytes;
193
194         this.msg = new Soup.Message ("HTTP",  uri);
195         assert (this.msg != null);
196         this.msg.response_body.set_accumulate (false);
197
198         if (active) {
199             this.cancellable = new Cancellable ();
200             this.cancellable.cancelled += this.on_cancelled;
201         }
202     }
203
204     public async void run () {
205         SourceFunc run_continue = run.callback;
206         size_t bytes_received = 0;
207
208         this.msg.got_chunk.connect ((msg, chunk) => {
209             bytes_received += chunk.length;
210
211             if (bytes_received >= this.total_bytes &&
212                 this.cancellable != null) {
213
214                 this.cancellable.cancel ();
215             }
216         });
217
218         this.context.session.queue_message (this.msg, (session, msg) => {
219             assert (cancellable != null || bytes_received == this.total_bytes);
220
221             run_continue ();
222         });
223
224         yield;
225
226         this.completed ();
227     }
228
229     private void on_cancelled (Cancellable cancellable) {
230         this.context.session.cancel_message (this.msg,
231                                              KnownStatusCode.CANCELLED);
232         this.completed ();
233     }
234 }
235
236 public class Rygel.HTTPSeek : GLib.Object {
237     public int64 start { get; private set; }
238     public int64 stop { get; private set; }
239     public int64 length { get; private set; }
240     public int64 total_length { get; private set; }
241
242     public HTTPSeek (int64 start, int64 stop, int64 total_length) {
243         this.start = start;
244         this.stop = stop;
245         this.total_length = total_length;
246
247         this.length = stop - start + 1;
248     }
249 }