Assamese translation updated
[profile/ivi/rygel.git] / tests / rygel-http-response-test.vala
index 0d09ba2..c56230b 100644 (file)
@@ -21,8 +21,6 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-// This module contains the common code between the test cases for
-// HTTPResponse subclasses.
 using Soup;
 
 public errordomain Rygel.TestError {
@@ -30,8 +28,12 @@ public errordomain Rygel.TestError {
     TIMEOUT
 }
 
-public abstract class Rygel.HTTPResponseTest : GLib.Object {
-    public const long MAX_BYTES = 1024;
+public errordomain Rygel.HTTPRequestError {
+    NOT_FOUND = Soup.Status.NOT_FOUND
+}
+
+public class Rygel.HTTPResponseTest : GLib.Object {
+    public const long MAX_BYTES = 102400;
 
     protected HTTPServer server;
     protected HTTPClient client;
@@ -39,11 +41,31 @@ public abstract class Rygel.HTTPResponseTest : GLib.Object {
     private bool server_done;
     private bool client_done;
 
+    private MediaItem item;
+
     private MainLoop main_loop;
 
     protected Cancellable cancellable;
     private Error error;
 
+    public static int main (string[] args) {
+        try {
+            var test = new HTTPResponseTest.complete ();
+            test.run ();
+
+            test = new HTTPResponseTest.abort ();
+            test.run ();
+        } catch (TestError.SKIP error) {
+            return error.code;
+        } catch (Error error) {
+            critical ("%s", error.message);
+
+            return -1;
+        }
+
+        return 0;
+    }
+
     public HTTPResponseTest (Cancellable? cancellable = null) throws Error {
         this.cancellable = cancellable;
 
@@ -57,10 +79,14 @@ public abstract class Rygel.HTTPResponseTest : GLib.Object {
 
     public HTTPResponseTest.complete () throws Error {
         this ();
+
+        this.item = new MediaItem.fixed_size ();
     }
 
     public HTTPResponseTest.abort () throws Error {
         this (new Cancellable ());
+
+        this.item = new MediaItem ();
     }
 
     public virtual void run () throws Error {
@@ -82,8 +108,24 @@ public abstract class Rygel.HTTPResponseTest : GLib.Object {
         }
     }
 
-    internal abstract HTTPResponse create_response (Soup.Message msg)
-                                                    throws Error;
+    private HTTPResponse create_response (Soup.Message msg) throws Error {
+        var seek = null as HTTPSeek;
+
+        if (!this.item.is_live_stream ()) {
+            seek = new HTTPByteSeek (0, MAX_BYTES - 1, this.item.size);
+            msg.response_headers.set_content_length (seek.length);
+        }
+
+        var request = new HTTPGet (this.server.context.server,
+                                   msg,
+                                   this.item,
+                                   seek,
+                                   this.cancellable);
+        var handler = new HTTPGetHandler (this.cancellable);
+        var src = this.item.create_stream_source ();
+
+        return new HTTPResponse (request, handler, src);
+    }
 
     private void on_client_completed (StateMachine client) {
         if (this.server_done) {
@@ -197,7 +239,7 @@ public class Rygel.HTTPClient : GLib.Object, StateMachine {
 
         if (active) {
             this.cancellable = new Cancellable ();
-            this.cancellable.cancelled += this.on_cancelled;
+            this.cancellable.cancelled.connect (this.on_cancelled);
         }
     }
 
@@ -210,14 +252,13 @@ public class Rygel.HTTPClient : GLib.Object, StateMachine {
 
             if (bytes_received >= this.total_bytes &&
                 this.cancellable != null) {
-                bytes_received = bytes_received.clamp (0, this.total_bytes);
 
                 this.cancellable.cancel ();
             }
         });
 
         this.context.session.queue_message (this.msg, (session, msg) => {
-            assert (cancellable == null || bytes_received == this.total_bytes);
+            assert (cancellable != null || bytes_received == this.total_bytes);
 
             run_continue ();
         });
@@ -229,7 +270,153 @@ public class Rygel.HTTPClient : GLib.Object, StateMachine {
 
     private void on_cancelled (Cancellable cancellable) {
         this.context.session.cancel_message (this.msg,
-                                             KnownStatusCode.CANCELLED);
+                                             Status.CANCELLED);
         this.completed ();
     }
 }
+
+public class Rygel.HTTPSeek : GLib.Object {
+    public int64 start { get; private set; }
+    public int64 stop { get; private set; }
+    public int64 length { get; private set; }
+    public int64 total_length { get; private set; }
+
+    public HTTPSeek (int64 start, int64 stop, int64 total_length) {
+        this.start = start;
+        this.stop = stop;
+        this.total_length = total_length;
+
+        this.length = stop - start + 1;
+    }
+}
+
+public class Rygel.HTTPByteSeek : Rygel.HTTPSeek {
+    public HTTPByteSeek (int64 start, int64 stop, int64 total_length) {
+        base (start, stop, total_length);
+    }
+}
+
+public class Rygel.HTTPTimeSeek : Rygel.HTTPSeek {
+    public HTTPTimeSeek (int64 start, int64 stop, int64 total_length) {
+        base (start, stop, total_length);
+    }
+}
+
+public class Rygel.HTTPGet : GLib.Object {
+    public Soup.Server server;
+    public Soup.Message msg;
+
+    public Cancellable cancellable;
+
+    public MediaItem item;
+
+    internal HTTPSeek seek;
+
+    public HTTPGet (Soup.Server  server,
+                    Soup.Message msg,
+                    MediaItem    item,
+                    HTTPSeek?    seek,
+                    Cancellable? cancellable) {
+        this.server = server;
+        this.msg = msg;
+        this.item = item;
+        this.seek = seek;
+        this.cancellable = cancellable;
+        this.msg.response_headers.set_encoding (Soup.Encoding.EOF);
+        this.msg.set_status (Soup.Status.OK);
+    }
+}
+
+public class Rygel.HTTPGetHandler : GLib.Object {
+    public Cancellable cancellable;
+
+    public HTTPGetHandler (Cancellable? cancellable) {
+        this.cancellable = cancellable;
+    }
+}
+
+internal class Rygel.TestDataSource : Rygel.DataSource, Object {
+    private long block_size;
+    private long buffers;
+    private uint64 data_sent;
+    private bool frozen;
+
+    public TestDataSource (long block_size, long buffers) {
+        this.block_size = block_size;
+        this.buffers = buffers;
+        this.data_sent = 0;
+    }
+
+    public void start (HTTPSeek? seek) throws Error {
+        Idle.add ( () => {
+            if (frozen) {
+                return false;
+            }
+
+            var data = new uint8[block_size];
+            this.data_sent += block_size;
+            if (this.data_sent > HTTPResponseTest.MAX_BYTES) {
+                this.done ();
+
+                return false;
+            }
+
+            this.data_available (data);
+
+            return true;
+        });
+    }
+
+    public void freeze () {
+        this.frozen = true;
+    }
+
+    public void thaw () {
+        if (!this.frozen) {
+            return;
+        }
+
+        this.frozen = false;
+
+        try {
+            this.start (null);
+        } catch (GLib.Error error) {
+            assert_not_reached ();
+        }
+    }
+
+    public void stop () {
+        this.freeze ();
+    }
+}
+
+public class Rygel.MediaItem {
+    private static const long BLOCK_SIZE = HTTPResponseTest.MAX_BYTES / 16;
+    private static const long MAX_BUFFERS = 25;
+
+    public int64 size {
+        get {
+            return MAX_BUFFERS * BLOCK_SIZE;
+        }
+    }
+
+    private DataSource src;
+    bool is_live = false;
+
+    public MediaItem () {
+        this.src = new TestDataSource (BLOCK_SIZE, MAX_BUFFERS);
+        this.is_live = true;
+    }
+
+    public MediaItem.fixed_size () {
+        this ();
+    }
+
+    public DataSource? create_stream_source () {
+        return this.src;
+    }
+
+    public bool is_live_stream () {
+        return this.is_live;
+    }
+}