tests: Mark non-abstract property as such
[profile/ivi/rygel.git] / tests / rygel-http-get-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 using Soup;
25 using Gee;
26
27 public errordomain Rygel.TestError {
28     SKIP = 77,
29     TIMEOUT
30 }
31
32 public class Rygel.HTTPGetTest : GLib.Object {
33     protected HTTPServer server;
34     protected HTTPClient client;
35
36     private bool server_done;
37     private bool client_done;
38
39     private MainLoop main_loop;
40
41     private Error error;
42
43     public static int main (string[] args) {
44         try {
45             var test = new HTTPGetTest ();
46
47             test.run ();
48         } catch (TestError.SKIP error) {
49             return error.code;
50         } catch (Error error) {
51             critical ("%s", error.message);
52
53             return -1;
54         }
55
56         return 0;
57     }
58
59     public HTTPGetTest () throws Error {
60         this.server = new HTTPServer ();
61         this.client = new HTTPClient (this.server.context,
62                                       this.server.uri);
63         this.main_loop = new MainLoop (null, false);
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.client.completed.connect (this.on_client_completed);
70
71         this.client.run.begin ();
72
73         this.main_loop.run ();
74
75         if (this.error != null) {
76             throw this.error;
77         }
78     }
79
80     private HTTPRequest create_request (Soup.Message msg) throws Error {
81         return new HTTPGet (this.server,
82                             this.server.context.server,
83                             msg);
84     }
85
86     private void on_client_completed (StateMachine client) {
87         if (this.server_done) {
88             this.main_loop.quit ();
89         }
90
91         this.client_done = true;
92     }
93
94     private void on_message_received (HTTPServer   server,
95                                       Soup.Message msg) {
96         this.handle_client_message.begin (msg);
97     }
98
99     private async void handle_client_message (Soup.Message msg) {
100         try {
101             var request = this.create_request (msg);
102
103             yield request.run ();
104
105             assert ((request as HTTPGet).item != null);
106
107             if (this.client_done) {
108                 this.main_loop.quit ();
109             }
110
111             this.server_done = true;
112         } catch (Error error) {
113             this.error = error;
114             this.main_loop.quit ();
115
116             return;
117         }
118     }
119
120     private bool on_timeout () {
121         this.error = new TestError.TIMEOUT ("Timeout");
122         this.main_loop.quit ();
123
124         return false;
125     }
126 }
127
128 public class Rygel.HTTPServer : GLib.Object {
129     private const string SERVER_PATH = "/RygelHTTPServer/Rygel/Test";
130     public string path_root {
131         get {
132             return SERVER_PATH;
133         }
134     }
135
136     public MediaContainer root_container;
137     public GUPnP.Context context;
138
139     public string uri {
140         owned get {
141             var item_uri = new HTTPItemURI (this.root_container.ITEM_ID,
142                                             this);
143
144             return item_uri.to_string ();
145         }
146     }
147
148     public signal void message_received (Soup.Message message);
149
150     public HTTPServer () throws TestError {
151         try {
152             this.context = new GUPnP.Context (null, "lo", 0);
153         } catch (Error error) {
154             throw new TestError.SKIP ("Network context not available");
155         }
156
157         assert (this.context != null);
158         assert (this.context.host_ip != null);
159         assert (this.context.port > 0);
160
161         this.context.server.add_handler (SERVER_PATH, this.server_cb);
162
163         this.root_container = new MediaContainer ();
164     }
165
166     private void server_cb (Server        server,
167                             Soup.Message  msg,
168                             string        path,
169                             HashTable?    query,
170                             ClientContext client) {
171         this.context.server.pause_message (msg);
172         this.message_received (msg);
173     }
174
175     public Transcoder get_transcoder (string target) throws Error {
176         return new Transcoder ();
177     }
178 }
179
180 public class Rygel.HTTPClient : GLib.Object, StateMachine {
181     public GUPnP.Context context;
182     public Soup.Message msg;
183
184     public Cancellable cancellable { get; set; }
185
186     public HTTPClient (GUPnP.Context context,
187                        string        uri) {
188         this.context = context;
189
190         this.msg = new Soup.Message ("GET",  uri);
191         assert (this.msg != null);
192     }
193
194     public async void run () {
195         SourceFunc run_continue = run.callback;
196
197         this.context.session.queue_message (this.msg, (session, msg) => {
198             run_continue ();
199         });
200
201         yield;
202
203         this.completed ();
204     }
205 }
206
207 public class Rygel.MediaContainer : Rygel.MediaObject {
208     public const string ITEM_ID = "TestItem";
209
210     public async MediaObject? find_object (string       item_id,
211                                            Cancellable? cancellable)
212                                            throws Error {
213         SourceFunc find_object_continue = find_object.callback;
214         Idle.add (() => {
215             find_object_continue ();
216
217             return false;
218         });
219
220         yield;
221
222         if (item_id == ITEM_ID) {
223             return new MediaItem ();
224         } else {
225             return null;
226         }
227     }
228 }
229
230 internal abstract class Rygel.HTTPGetHandler {
231     public HTTPResponse render_body (HTTPGet get_request) {
232         return new HTTPResponse (get_request);
233     }
234
235     public void add_response_headers (HTTPGet get_request) {}
236 }
237
238 internal class Rygel.HTTPTranscodeHandler : Rygel.HTTPGetHandler {
239     public HTTPTranscodeHandler (Transcoder  transcoder,
240                                  Cancellable cancellable) {}
241 }
242
243 internal class Rygel.HTTPIdentityHandler : Rygel.HTTPGetHandler {
244     public HTTPIdentityHandler (Cancellable cancellable) {}
245 }
246
247 public class Rygel.MediaItem : Rygel.MediaObject {
248     public long size = 1024;
249     public long duration = 1024;
250     public ArrayList<Subtitle> subtitles = new ArrayList<Subtitle> ();
251     public ArrayList<Thumbnail> thumbnails = new ArrayList<Thumbnail> ();
252
253     public bool should_stream () {
254         return true;
255     }
256 }
257
258 public class Rygel.Thumbnail {
259     public long size = 1024;
260 }
261
262 public class Rygel.Subtitle {
263     public long size = 1024;
264 }
265
266 internal class Rygel.HTTPResponse : Rygel.StateMachine, GLib.Object {
267     public Cancellable cancellable { get; set; }
268
269     private Soup.Message msg;
270     private Soup.Server server;
271
272     public HTTPResponse (HTTPGet get_request) {
273         this.msg = get_request.msg;
274         this.server = get_request.server;
275     }
276
277     public async void run () {
278         SourceFunc run_continue = run.callback;
279
280         Idle.add (() => {
281             run_continue ();
282
283             return false;
284         });
285
286         yield;
287
288         this.msg.set_status (Soup.KnownStatusCode.OK);
289         this.server.unpause_message (msg);
290
291         this.completed ();
292     }
293 }
294
295
296 public class Rygel.Transcoder {}
297 public class Rygel.MediaObject {}