aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/net/image_cache_task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/net/image_cache_task.rs')
-rw-r--r--src/components/net/image_cache_task.rs993
1 files changed, 0 insertions, 993 deletions
diff --git a/src/components/net/image_cache_task.rs b/src/components/net/image_cache_task.rs
deleted file mode 100644
index de0c978c3cf..00000000000
--- a/src/components/net/image_cache_task.rs
+++ /dev/null
@@ -1,993 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use image::base::{Image, load_from_memory};
-use resource_task;
-use resource_task::{LoadData, ResourceTask};
-
-use std::comm::{channel, Receiver, Sender};
-use std::collections::hashmap::HashMap;
-use std::mem::replace;
-use std::task::spawn;
-use std::result;
-use sync::{Arc, Mutex};
-use serialize::{Encoder, Encodable};
-use url::Url;
-
-pub enum Msg {
- /// Tell the cache that we may need a particular image soon. Must be posted
- /// before Decode
- Prefetch(Url),
-
- /// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage
- Decode(Url),
-
- /// Request an Image object for a URL. If the image is not is not immediately
- /// available then ImageNotReady is returned.
- GetImage(Url, Sender<ImageResponseMsg>),
-
- /// Wait for an image to become available (or fail to load).
- WaitForImage(Url, Sender<ImageResponseMsg>),
-
- /// Clients must wait for a response before shutting down the ResourceTask
- Exit(Sender<()>),
-
- /// Used by the prefetch tasks to post back image binaries
- StorePrefetchedImageData(Url, Result<Vec<u8>, ()>),
-
- /// Used by the decoder tasks to post decoded images back to the cache
- StoreImage(Url, Option<Arc<Box<Image>>>),
-
- /// For testing
- WaitForStore(Sender<()>),
-
- /// For testing
- WaitForStorePrefetched(Sender<()>),
-}
-
-#[deriving(Clone)]
-pub enum ImageResponseMsg {
- ImageReady(Arc<Box<Image>>),
- ImageNotReady,
- ImageFailed
-}
-
-impl PartialEq for ImageResponseMsg {
- fn eq(&self, other: &ImageResponseMsg) -> bool {
- match (self, other) {
- (&ImageReady(..), &ImageReady(..)) => fail!("unimplemented comparison"),
- (&ImageNotReady, &ImageNotReady) => true,
- (&ImageFailed, &ImageFailed) => true,
-
- (&ImageReady(..), _) | (&ImageNotReady, _) | (&ImageFailed, _) => false
- }
- }
-}
-
-#[deriving(Clone)]
-pub struct ImageCacheTask {
- chan: Sender<Msg>,
-}
-
-impl<E, S: Encoder<E>> Encodable<S, E> for ImageCacheTask {
- fn encode(&self, _: &mut S) -> Result<(), E> {
- Ok(())
- }
-}
-
-type DecoderFactory = fn() -> proc(&[u8]) -> Option<Image>;
-
-impl ImageCacheTask {
- pub fn new(resource_task: ResourceTask) -> ImageCacheTask {
- let (chan, port) = channel();
- let chan_clone = chan.clone();
-
- spawn(proc() {
- let mut cache = ImageCache {
- resource_task: resource_task,
- port: port,
- chan: chan_clone,
- state_map: HashMap::new(),
- wait_map: HashMap::new(),
- need_exit: None
- };
- cache.run();
- });
-
- ImageCacheTask {
- chan: chan,
- }
- }
-
- pub fn new_sync(resource_task: ResourceTask) -> ImageCacheTask {
- let (chan, port) = channel();
-
- spawn(proc() {
- let inner_cache = ImageCacheTask::new(resource_task);
-
- loop {
- let msg: Msg = port.recv();
-
- match msg {
- GetImage(url, response) => {
- inner_cache.send(WaitForImage(url, response));
- }
- Exit(response) => {
- inner_cache.send(Exit(response));
- break;
- }
- msg => inner_cache.send(msg)
- }
- }
- });
-
- ImageCacheTask {
- chan: chan,
- }
- }
-}
-
-struct ImageCache {
- /// A handle to the resource task for fetching the image binaries
- resource_task: ResourceTask,
- /// The port on which we'll receive client requests
- port: Receiver<Msg>,
- /// A copy of the shared chan to give to child tasks
- chan: Sender<Msg>,
- /// The state of processsing an image for a URL
- state_map: HashMap<Url, ImageState>,
- /// List of clients waiting on a WaitForImage response
- wait_map: HashMap<Url, Arc<Mutex<Vec<Sender<ImageResponseMsg>>>>>,
- need_exit: Option<Sender<()>>,
-}
-
-#[deriving(Clone)]
-enum ImageState {
- Init,
- Prefetching(AfterPrefetch),
- Prefetched(Vec<u8>),
- Decoding,
- Decoded(Arc<Box<Image>>),
- Failed
-}
-
-#[deriving(Clone)]
-enum AfterPrefetch {
- DoDecode,
- DoNotDecode
-}
-
-impl ImageCache {
- pub fn run(&mut self) {
- let mut store_chan: Option<Sender<()>> = None;
- let mut store_prefetched_chan: Option<Sender<()>> = None;
-
- loop {
- let msg = self.port.recv();
-
- debug!("image_cache_task: received: {:?}", msg);
-
- match msg {
- Prefetch(url) => self.prefetch(url),
- StorePrefetchedImageData(url, data) => {
- store_prefetched_chan.map(|chan| {
- chan.send(());
- });
- store_prefetched_chan = None;
-
- self.store_prefetched_image_data(url, data);
- }
- Decode(url) => self.decode(url),
- StoreImage(url, image) => {
- store_chan.map(|chan| {
- chan.send(());
- });
- store_chan = None;
-
- self.store_image(url, image)
- }
- GetImage(url, response) => self.get_image(url, response),
- WaitForImage(url, response) => {
- self.wait_for_image(url, response)
- }
- WaitForStore(chan) => store_chan = Some(chan),
- WaitForStorePrefetched(chan) => store_prefetched_chan = Some(chan),
- Exit(response) => {
- assert!(self.need_exit.is_none());
- self.need_exit = Some(response);
- }
- }
-
- let need_exit = replace(&mut self.need_exit, None);
-
- match need_exit {
- Some(response) => {
- // Wait until we have no outstanding requests and subtasks
- // before exiting
- let mut can_exit = true;
- for (_, state) in self.state_map.iter() {
- match *state {
- Prefetching(..) => can_exit = false,
- Decoding => can_exit = false,
-
- Init | Prefetched(..) | Decoded(..) | Failed => ()
- }
- }
-
- if can_exit {
- response.send(());
- break;
- } else {
- self.need_exit = Some(response);
- }
- }
- None => ()
- }
- }
- }
-
- fn get_state(&self, url: Url) -> ImageState {
- match self.state_map.find(&url) {
- Some(state) => state.clone(),
- None => Init
- }
- }
-
- fn set_state(&mut self, url: Url, state: ImageState) {
- self.state_map.insert(url, state);
- }
-
- fn prefetch(&mut self, url: Url) {
- match self.get_state(url.clone()) {
- Init => {
- let to_cache = self.chan.clone();
- let resource_task = self.resource_task.clone();
- let url_clone = url.clone();
-
- spawn(proc() {
- let url = url_clone;
- debug!("image_cache_task: started fetch for {:s}", url.serialize());
-
- let image = load_image_data(url.clone(), resource_task.clone());
-
- let result = if image.is_ok() {
- Ok(image.unwrap())
- } else {
- Err(())
- };
- to_cache.send(StorePrefetchedImageData(url.clone(), result));
- debug!("image_cache_task: ended fetch for {:s}", url.serialize());
- });
-
- self.set_state(url, Prefetching(DoNotDecode));
- }
-
- Prefetching(..) | Prefetched(..) | Decoding | Decoded(..) | Failed => {
- // We've already begun working on this image
- }
- }
- }
-
- fn store_prefetched_image_data(&mut self, url: Url, data: Result<Vec<u8>, ()>) {
- match self.get_state(url.clone()) {
- Prefetching(next_step) => {
- match data {
- Ok(data) => {
- self.set_state(url.clone(), Prefetched(data));
- match next_step {
- DoDecode => self.decode(url),
- _ => ()
- }
- }
- Err(..) => {
- self.set_state(url.clone(), Failed);
- self.purge_waiters(url, || ImageFailed);
- }
- }
- }
-
- Init
- | Prefetched(..)
- | Decoding
- | Decoded(..)
- | Failed => {
- fail!("wrong state for storing prefetched image")
- }
- }
- }
-
- fn decode(&mut self, url: Url) {
- match self.get_state(url.clone()) {
- Init => fail!("decoding image before prefetch"),
-
- Prefetching(DoNotDecode) => {
- // We don't have the data yet, queue up the decode
- self.set_state(url, Prefetching(DoDecode))
- }
-
- Prefetching(DoDecode) => {
- // We don't have the data yet, but the decode request is queued up
- }
-
- Prefetched(data) => {
- let to_cache = self.chan.clone();
- let url_clone = url.clone();
-
- spawn(proc() {
- let url = url_clone;
- debug!("image_cache_task: started image decode for {:s}", url.serialize());
- let image = load_from_memory(data.as_slice());
- let image = if image.is_some() {
- Some(Arc::new(box image.unwrap()))
- } else {
- None
- };
- to_cache.send(StoreImage(url.clone(), image));
- debug!("image_cache_task: ended image decode for {:s}", url.serialize());
- });
-
- self.set_state(url, Decoding);
- }
-
- Decoding | Decoded(..) | Failed => {
- // We've already begun decoding
- }
- }
- }
-
- fn store_image(&mut self, url: Url, image: Option<Arc<Box<Image>>>) {
-
- match self.get_state(url.clone()) {
- Decoding => {
- match image {
- Some(image) => {
- self.set_state(url.clone(), Decoded(image.clone()));
- self.purge_waiters(url, || ImageReady(image.clone()) );
- }
- None => {
- self.set_state(url.clone(), Failed);
- self.purge_waiters(url, || ImageFailed );
- }
- }
- }
-
- Init
- | Prefetching(..)
- | Prefetched(..)
- | Decoded(..)
- | Failed => {
- fail!("incorrect state in store_image")
- }
- }
-
- }
-
- fn purge_waiters(&mut self, url: Url, f: || -> ImageResponseMsg) {
- match self.wait_map.pop(&url) {
- Some(waiters) => {
- let mut items = waiters.lock();
- for response in items.iter() {
- response.send(f());
- }
- }
- None => ()
- }
- }
-
- fn get_image(&self, url: Url, response: Sender<ImageResponseMsg>) {
- match self.get_state(url.clone()) {
- Init => fail!("request for image before prefetch"),
- Prefetching(DoDecode) => response.send(ImageNotReady),
- Prefetching(DoNotDecode) | Prefetched(..) => fail!("request for image before decode"),
- Decoding => response.send(ImageNotReady),
- Decoded(image) => response.send(ImageReady(image.clone())),
- Failed => response.send(ImageFailed),
- }
- }
-
- fn wait_for_image(&mut self, url: Url, response: Sender<ImageResponseMsg>) {
- match self.get_state(url.clone()) {
- Init => fail!("request for image before prefetch"),
-
- Prefetching(DoNotDecode) | Prefetched(..) => fail!("request for image before decode"),
-
- Prefetching(DoDecode) | Decoding => {
- // We don't have this image yet
- if self.wait_map.contains_key(&url) {
- let waiters = self.wait_map.find_mut(&url).unwrap();
- let mut response = Some(response);
- let mut items = waiters.lock();
- items.push(response.take().unwrap());
- } else {
- let response = vec!(response);
- let wrapped = Arc::new(Mutex::new(response));
- self.wait_map.insert(url, wrapped);
- }
- }
-
- Decoded(image) => {
- response.send(ImageReady(image.clone()));
- }
-
- Failed => {
- response.send(ImageFailed);
- }
- }
- }
-
-}
-
-
-pub trait ImageCacheTaskClient {
- fn exit(&self);
-}
-
-impl ImageCacheTaskClient for ImageCacheTask {
- fn exit(&self) {
- let (response_chan, response_port) = channel();
- self.send(Exit(response_chan));
- response_port.recv();
- }
-}
-
-impl ImageCacheTask {
- pub fn send(&self, msg: Msg) {
- self.chan.send(msg);
- }
-
- #[cfg(test)]
- fn wait_for_store(&self) -> Receiver<()> {
- let (chan, port) = channel();
- self.send(WaitForStore(chan));
- port
- }
-
- #[cfg(test)]
- fn wait_for_store_prefetched(&self) -> Receiver<()> {
- let (chan, port) = channel();
- self.send(WaitForStorePrefetched(chan));
- port
- }
-}
-
-fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<Vec<u8>, ()> {
- let (response_chan, response_port) = channel();
- resource_task.send(resource_task::Load(LoadData::new(url), response_chan));
-
- let mut image_data = vec!();
-
- let progress_port = response_port.recv().progress_port;
- loop {
- match progress_port.recv() {
- resource_task::Payload(data) => {
- image_data.push_all(data.as_slice());
- }
- resource_task::Done(result::Ok(..)) => {
- return Ok(image_data.move_iter().collect());
- }
- resource_task::Done(result::Err(..)) => {
- return Err(());
- }
- }
- }
-}
-
-
-pub fn spawn_listener<A: Send>(f: proc(Receiver<A>):Send) -> Sender<A> {
- let (setup_chan, setup_port) = channel();
-
- spawn(proc() {
- let (chan, port) = channel();
- setup_chan.send(chan);
- f(port);
- });
- setup_port.recv()
-}
-
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use resource_task;
- use resource_task::{ResourceTask, Metadata, start_sending};
- use image::base::test_image_bin;
- use std::comm;
- use url::Url;
-
- trait Closure {
- fn invoke(&self, _response: Sender<resource_task::ProgressMsg>) { }
- }
- struct DoesNothing;
- impl Closure for DoesNothing { }
-
- struct JustSendOK {
- url_requested_chan: Sender<()>,
- }
- impl Closure for JustSendOK {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- self.url_requested_chan.send(());
- response.send(resource_task::Done(Ok(())));
- }
- }
-
- struct SendTestImage;
- impl Closure for SendTestImage {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- response.send(resource_task::Payload(test_image_bin()));
- response.send(resource_task::Done(Ok(())));
- }
- }
-
- struct SendBogusImage;
- impl Closure for SendBogusImage {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- response.send(resource_task::Payload(vec!()));
- response.send(resource_task::Done(Ok(())));
- }
- }
-
- struct SendTestImageErr;
- impl Closure for SendTestImageErr {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- response.send(resource_task::Payload(test_image_bin()));
- response.send(resource_task::Done(Err("".to_string())));
- }
- }
-
- struct WaitSendTestImage {
- wait_port: Receiver<()>,
- }
- impl Closure for WaitSendTestImage {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- // Don't send the data until after the client requests
- // the image
- self.wait_port.recv();
- response.send(resource_task::Payload(test_image_bin()));
- response.send(resource_task::Done(Ok(())));
- }
- }
-
- struct WaitSendTestImageErr {
- wait_port: Receiver<()>,
- }
- impl Closure for WaitSendTestImageErr {
- fn invoke(&self, response: Sender<resource_task::ProgressMsg>) {
- // Don't send the data until after the client requests
- // the image
- self.wait_port.recv();
- response.send(resource_task::Payload(test_image_bin()));
- response.send(resource_task::Done(Err("".to_string())));
- }
- }
-
- fn mock_resource_task<T: Closure+Send>(on_load: Box<T>) -> ResourceTask {
- spawn_listener(proc(port: Receiver<resource_task::ControlMsg>) {
- loop {
- match port.recv() {
- resource_task::Load(_, response) => {
- let chan = start_sending(response, Metadata::default(
- Url::parse("file:///fake").unwrap()));
- on_load.invoke(chan);
- }
- resource_task::Exit => break
- }
- }
- })
- }
-
- #[test]
- fn should_exit_on_request() {
- let mock_resource_task = mock_resource_task(box DoesNothing);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- #[should_fail]
- fn should_fail_if_unprefetched_image_is_requested() {
- let mock_resource_task = mock_resource_task(box DoesNothing);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let (chan, port) = channel();
- image_cache_task.send(GetImage(url, chan));
- port.recv();
- }
-
- #[test]
- fn should_request_url_from_resource_task_on_prefetch() {
- let (url_requested_chan, url_requested) = channel();
-
- let mock_resource_task = mock_resource_task(box JustSendOK { url_requested_chan: url_requested_chan});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url));
- url_requested.recv();
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
- let (url_requested_chan, url_requested) = comm::channel();
-
- let mock_resource_task = mock_resource_task(box JustSendOK { url_requested_chan: url_requested_chan});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Prefetch(url));
- url_requested.recv();
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- match url_requested.try_recv() {
- Err(_) => (),
- Ok(_) => fail!(),
- };
- }
-
- #[test]
- fn should_return_image_not_ready_if_data_has_not_arrived() {
- let (wait_chan, wait_port) = comm::channel();
-
- let mock_resource_task = mock_resource_task(box WaitSendTestImage{wait_port: wait_port});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- assert!(response_port.recv() == ImageNotReady);
- wait_chan.send(());
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_decoded_image_data_if_data_has_arrived() {
- let mock_resource_task = mock_resource_task(box SendTestImage);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- match response_port.recv() {
- ImageReady(_) => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_decoded_image_data_for_multiple_requests() {
- let mock_resource_task = mock_resource_task(box SendTestImage);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- for _ in range(0u32, 2u32) {
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url.clone(), response_chan));
- match response_port.recv() {
- ImageReady(_) => (),
- _ => fail!("bleh")
- }
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_not_request_image_from_resource_task_if_image_is_already_available() {
- let (image_bin_sent_chan, image_bin_sent) = comm::channel();
-
- let (resource_task_exited_chan, resource_task_exited) = comm::channel();
-
- let mock_resource_task = spawn_listener(proc(port: Receiver<resource_task::ControlMsg>) {
- loop {
- match port.recv() {
- resource_task::Load(_, response) => {
- let chan = start_sending(response, Metadata::default(
- Url::parse("file:///fake").unwrap()));
- chan.send(resource_task::Payload(test_image_bin()));
- chan.send(resource_task::Done(Ok(())));
- image_bin_sent_chan.send(());
- }
- resource_task::Exit => {
- resource_task_exited_chan.send(());
- break
- }
- }
- }
- });
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- image_bin_sent.recv();
-
- image_cache_task.send(Prefetch(url.clone()));
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
-
- resource_task_exited.recv();
-
- // Our resource task should not have received another request for the image
- // because it's already cached
- match image_bin_sent.try_recv() {
- Err(_) => (),
- Ok(_) => fail!(),
- }
- }
-
- #[test]
- fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
- let (image_bin_sent_chan, image_bin_sent) = comm::channel();
-
- let (resource_task_exited_chan, resource_task_exited) = comm::channel();
-
- let mock_resource_task = spawn_listener(proc(port: Receiver<resource_task::ControlMsg>) {
- loop {
- match port.recv() {
- resource_task::Load(_, response) => {
- let chan = start_sending(response, Metadata::default(
- Url::parse("file:///fake").unwrap()));
- chan.send(resource_task::Payload(test_image_bin()));
- chan.send(resource_task::Done(Err("".to_string())));
- image_bin_sent_chan.send(());
- }
- resource_task::Exit => {
- resource_task_exited_chan.send(());
- break
- }
- }
- }
- });
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- image_bin_sent.recv();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
-
- resource_task_exited.recv();
-
- // Our resource task should not have received another request for the image
- // because it's already cached
- match image_bin_sent.try_recv() {
- Err(_) => (),
- Ok(_) => fail!(),
- }
- }
-
- #[test]
- fn should_return_failed_if_image_bin_cannot_be_fetched() {
- let mock_resource_task = mock_resource_task(box SendTestImageErr);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store_prefetched();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() {
- let mock_resource_task = mock_resource_task(box SendTestImageErr);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store_prefetched();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url.clone(), response_chan));
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- // And ask again, we should get the same response
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_failed_if_image_decode_fails() {
- let mock_resource_task = mock_resource_task(box SendBogusImage);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- // Make the request
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
-
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_image_on_wait_if_image_is_already_loaded() {
- let mock_resource_task = mock_resource_task(box SendTestImage);
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- let join_port = image_cache_task.wait_for_store();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- // Wait until our mock resource task has sent the image to the image cache
- join_port.recv();
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(WaitForImage(url, response_chan));
- match response_port.recv() {
- ImageReady(..) => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
- let (wait_chan, wait_port) = comm::channel();
-
- let mock_resource_task = mock_resource_task(box WaitSendTestImage {wait_port: wait_port});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(WaitForImage(url, response_chan));
-
- wait_chan.send(());
-
- match response_port.recv() {
- ImageReady(..) => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn should_return_image_failed_on_wait_if_image_fails_to_load() {
- let (wait_chan, wait_port) = comm::channel();
-
- let mock_resource_task = mock_resource_task(box WaitSendTestImageErr{wait_port: wait_port});
-
- let image_cache_task = ImageCacheTask::new(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(WaitForImage(url, response_chan));
-
- wait_chan.send(());
-
- match response_port.recv() {
- ImageFailed => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-
- #[test]
- fn sync_cache_should_wait_for_images() {
- let mock_resource_task = mock_resource_task(box SendTestImage);
-
- let image_cache_task = ImageCacheTask::new_sync(mock_resource_task.clone());
- let url = Url::parse("file:///").unwrap();
-
- image_cache_task.send(Prefetch(url.clone()));
- image_cache_task.send(Decode(url.clone()));
-
- let (response_chan, response_port) = comm::channel();
- image_cache_task.send(GetImage(url, response_chan));
- match response_port.recv() {
- ImageReady(_) => (),
- _ => fail!("bleh")
- }
-
- image_cache_task.exit();
- mock_resource_task.send(resource_task::Exit);
- }
-}