use std::collections::HashSet;
use std::io::{BufReader, Lines};
use std::net::TcpStream;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, LazyLock, Mutex};
use std::time::Duration;
use std::{fs, thread};
use request_utils;
use request_utils::test::log::init;
use request_utils::test::server::test_server;
use super::*;
use crate::download::CANCEL;
const ERROR_IP: &str = "127.12.31.12";
const NO_DATA: usize = 1359;
const TEST_URL: &str = "http://www.baidu.com";
const TEST_VIDEO_URL: &str = "https://www.w3cschool.cn/statics/demosource/movie.mp4";
static TEST_TEXT_URL: Mutex<&'static str> = Mutex::new(
"https://www.gitee.com/tiga-ultraman/downloadTests/releases/download/v1.01/test.txt",
);
const FINISH_SUFFIX: &str = "_F";
#[cfg(feature = "ohos")]
const DOWNLOADER: Downloader = Downloader::Netstack;
#[cfg(not(feature = "ohos"))]
const DOWNLOADER: Downloader = Downloader::Ylong;
struct TestCallbackN;
impl PreloadCallback for TestCallbackN {}
struct TestCallbackS {
flag: Arc<AtomicUsize>,
}
impl PreloadCallback for TestCallbackS {
fn on_success(&mut self, data: Arc<RamCache>, _task_id: &str) {
if data.size() != 0 {
self.flag.fetch_add(1, Ordering::SeqCst);
} else {
self.flag.store(NO_DATA, Ordering::SeqCst);
}
}
}
struct TestCallbackF {
flag: Arc<Mutex<String>>,
}
impl PreloadCallback for TestCallbackF {
fn on_fail(&mut self, error: CacheDownloadError, _info: RustDownloadInfo, _task_id: &str) {
*self.flag.lock().unwrap() = error.message().to_string();
}
}
struct TestCallbackC {
flag: Arc<AtomicUsize>,
}
impl PreloadCallback for TestCallbackC {
fn on_cancel(&mut self) {
self.flag.fetch_add(1, Ordering::SeqCst);
}
}
#[test]
fn ut_preload_success() {
init();
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let success_flag = Arc::new(AtomicUsize::new(0));
let callback = Box::new(TestCallbackS {
flag: success_flag.clone(),
});
let handle = SERVICE.preload(DownloadRequest::new(TEST_URL), callback, true, DOWNLOADER);
assert!(handle.is_some());
let handle = handle.unwrap();
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
assert_eq!(success_flag.load(Ordering::SeqCst), 1);
}
#[test]
fn ut_preload_success_add_callback() {
init();
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let success_flag_0 = Arc::new(AtomicUsize::new(0));
let callback_0 = Box::new(TestCallbackS {
flag: success_flag_0.clone(),
});
let success_flag_1 = Arc::new(AtomicUsize::new(0));
let callback_1 = Box::new(TestCallbackS {
flag: success_flag_1.clone(),
});
let handle = SERVICE.preload(DownloadRequest::new(TEST_URL), callback_0, true, DOWNLOADER);
SERVICE.preload(DownloadRequest::new(TEST_URL), callback_1, true, DOWNLOADER);
assert!(handle.is_some());
let handle = handle.unwrap();
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
assert_eq!(success_flag_0.load(Ordering::SeqCst), 1);
assert_eq!(success_flag_1.load(Ordering::SeqCst), 1);
}
#[test]
fn ut_preload_fail() {
init();
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let error = Arc::new(Mutex::new(String::new()));
let callback = Box::new(TestCallbackF {
flag: error.clone(),
});
let handle = SERVICE.preload(DownloadRequest::new(ERROR_IP), callback, true, DOWNLOADER);
assert!(handle.is_some());
let handle = handle.unwrap();
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
assert!(!error.lock().unwrap().as_str().is_empty());
}
#[test]
fn ut_preload_fail_add_callback() {
init();
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let error_0 = Arc::new(Mutex::new(String::new()));
let callback_0 = Box::new(TestCallbackF {
flag: error_0.clone(),
});
let error_1 = Arc::new(Mutex::new(String::new()));
let callback_1 = Box::new(TestCallbackF {
flag: error_1.clone(),
});
let handle = SERVICE.preload(DownloadRequest::new(ERROR_IP), callback_0, true, DOWNLOADER);
assert!(handle.is_some());
let handle = handle.unwrap();
SERVICE.preload(DownloadRequest::new(ERROR_IP), callback_1, true, DOWNLOADER);
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
assert!(!error_0.lock().unwrap().as_str().is_empty());
assert!(!error_1.lock().unwrap().as_str().is_empty());
}
#[test]
fn ut_preload_cancel_0() {
init();
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let cancel_flag = Arc::new(AtomicUsize::new(0));
let callback = Box::new(TestCallbackC {
flag: cancel_flag.clone(),
});
let handle = SERVICE.preload(DownloadRequest::new(TEST_URL), callback, true, DOWNLOADER);
assert!(handle.is_some());
let mut handle = handle.unwrap();
handle.cancel();
while handle.state() != CANCEL {
std::thread::sleep(Duration::from_millis(500));
}
assert_eq!(cancel_flag.load(Ordering::SeqCst), 1);
}
#[test]
fn ut_preload_cancel_1() {
init();
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let cancel_flag = Arc::new(AtomicUsize::new(0));
let callback = Box::new(TestCallbackC {
flag: cancel_flag.clone(),
});
let handle = SERVICE.preload(DownloadRequest::new(TEST_URL), callback, true, DOWNLOADER);
SERVICE.cancel(TEST_URL);
assert!(handle.is_some());
let handle = handle.unwrap();
while handle.state() != CANCEL {
std::thread::sleep(Duration::from_millis(500));
}
assert_eq!(cancel_flag.load(Ordering::SeqCst), 1);
}
#[test]
fn ut_preload_cancel_add_callback() {
init();
let test_url = "https://www.gitee.com";
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let cancel_flag_0 = Arc::new(AtomicUsize::new(0));
let callback_0 = Box::new(TestCallbackC {
flag: cancel_flag_0.clone(),
});
let cancel_flag_1 = Arc::new(AtomicUsize::new(0));
let callback_1 = Box::new(TestCallbackC {
flag: cancel_flag_1.clone(),
});
let handle_0 = SERVICE.preload(DownloadRequest::new(test_url), callback_0, true, DOWNLOADER);
let handle_1 = SERVICE.preload(DownloadRequest::new(test_url), callback_1, true, DOWNLOADER);
assert!(handle_0.is_some());
assert!(handle_1.is_some());
let mut handle_0 = handle_0.unwrap();
let mut handle_1 = handle_1.unwrap();
handle_0.cancel();
assert_eq!(cancel_flag_0.load(Ordering::SeqCst), 0);
assert_eq!(cancel_flag_1.load(Ordering::SeqCst), 0);
handle_1.cancel();
assert!(handle_0.is_finish());
assert!(handle_1.is_finish());
while handle_1.state() != CANCEL {
std::thread::sleep(Duration::from_millis(500));
}
assert_eq!(cancel_flag_0.load(Ordering::SeqCst), 1);
assert_eq!(cancel_flag_1.load(Ordering::SeqCst), 1);
}
#[test]
fn ut_preload_already_success() {
init();
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let handle = SERVICE.preload(
DownloadRequest::new(TEST_URL),
Box::new(TestCallbackN),
true,
DOWNLOADER,
);
assert!(handle.is_some());
let handle = handle.unwrap();
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
let success_flag = Arc::new(AtomicUsize::new(0));
let callback = Box::new(TestCallbackS {
flag: success_flag.clone(),
});
SERVICE.preload(DownloadRequest::new(TEST_URL), callback, false, DOWNLOADER);
std::thread::sleep(Duration::from_millis(50));
assert_eq!(success_flag.load(Ordering::SeqCst), 1);
}
#[test]
fn ut_preload_local_headers() {
init();
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let headers = vec![
("User-Agent", "Mozilla/5.0"),
("Accept", "text/html"),
("Accept-Language", "en-US"),
("Accept-Encoding", "gzip, deflate"),
("Connection", "keep-alive"),
];
let mut headers_clone: HashSet<String> = headers
.iter()
.map(|(k, v)| format!("{}:{}", k.to_ascii_lowercase(), v.to_ascii_lowercase()))
.collect();
let flag = Arc::new(AtomicBool::new(true));
let flag_clone = flag.clone();
let test_f = move |mut lines: Lines<BufReader<&mut TcpStream>>| {
for line in lines.by_ref() {
let line = line.unwrap();
let line = line.to_ascii_lowercase();
if line.is_empty() {
break;
}
headers_clone.remove(&line);
}
if headers_clone.is_empty() {
flag_clone.store(true, Ordering::SeqCst);
}
};
let server = test_server(test_f);
let mut request = DownloadRequest::new(&server);
request.headers(headers);
let success_flag = Arc::new(AtomicUsize::new(0));
let callback = Box::new(TestCallbackS {
flag: success_flag.clone(),
});
let handle = SERVICE.preload(request, callback, true, DOWNLOADER);
assert!(handle.is_some());
let handle = handle.unwrap();
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
assert!(flag.load(Ordering::SeqCst));
assert_eq!(success_flag.load(Ordering::SeqCst), NO_DATA);
}
#[test]
fn ut_preload_fetch() {
init();
static SERVICE: LazyLock<CacheDownloadService> = LazyLock::new(CacheDownloadService::new);
let success_flag = Arc::new(AtomicUsize::new(0));
let callback = Box::new(TestCallbackS {
flag: success_flag.clone(),
});
let handle = SERVICE.preload(DownloadRequest::new(TEST_URL), callback, true, DOWNLOADER);
assert!(handle.is_some());
let handle = handle.unwrap();
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
let cache = SERVICE.fetch(TEST_URL);
assert!(cache.is_some());
assert_eq!(success_flag.load(Ordering::SeqCst), 1);
}
#[test]
fn ut_download_request_ssl_type() {
let mut request = DownloadRequest::new(TEST_URL);
request.ssl_type("TLS");
assert_eq!(request.ssl_type, Some("TLS"));
}
#[test]
fn ut_download_request_max_retry() {
let mut request = DownloadRequest::new(TEST_URL);
request.max_retry(5);
assert_eq!(request.max_retry, Some(5));
}
#[test]
fn ut_download_request_network_check_timeout() {
let mut request = DownloadRequest::new(TEST_URL);
request.network_check_timeout(10);
assert_eq!(request.network_check_timeout, Some(10));
}
#[test]
fn ut_download_request_http_total_timeout() {
let mut request = DownloadRequest::new(TEST_URL);
request.http_total_timeout(90);
assert_eq!(request.http_total_timeout, Some(90));
}
#[test]
fn ut_download_request_all_options() {
let mut request = DownloadRequest::new(TEST_URL);
request.max_retry(7);
request.network_check_timeout(15);
request.http_total_timeout(120);
assert_eq!(request.max_retry, Some(7));
assert_eq!(request.network_check_timeout, Some(15));
assert_eq!(request.http_total_timeout, Some(120));
}
#[test]
fn ut_set_global_retry_options() {
CacheDownloadService::get_instance().set_global_retry_options(5);
let max_retry = CacheDownloadService::get_instance().get_global_max_retry();
assert_eq!(max_retry, 5);
CacheDownloadService::get_instance().set_global_retry_options(1);
}
#[test]
fn ut_set_global_retry_options_boundary() {
CacheDownloadService::get_instance().set_global_retry_options(10);
let max_retry = CacheDownloadService::get_instance().get_global_max_retry();
assert_eq!(max_retry, 10);
CacheDownloadService::get_instance().set_global_retry_options(0);
let max_retry = CacheDownloadService::get_instance().get_global_max_retry();
assert_eq!(max_retry, 0);
CacheDownloadService::get_instance().set_global_retry_options(1);
}
#[test]
fn ut_set_global_timeout_options() {
CacheDownloadService::get_instance().set_global_timeout_options(10, 30);
let network_timeout = CacheDownloadService::get_instance().get_global_network_check_timeout();
let http_timeout = CacheDownloadService::get_instance().get_global_http_total_timeout();
assert_eq!(network_timeout, 10);
assert_eq!(http_timeout, 30);
CacheDownloadService::get_instance().set_global_timeout_options(20, 60);
}
#[test]
fn ut_set_global_timeout_options_boundary() {
CacheDownloadService::get_instance().set_global_timeout_options(20, 60);
let network_timeout = CacheDownloadService::get_instance().get_global_network_check_timeout();
assert_eq!(network_timeout, 20);
CacheDownloadService::get_instance().set_global_timeout_options(0, 60);
let network_timeout = CacheDownloadService::get_instance().get_global_network_check_timeout();
assert_eq!(network_timeout, 0);
CacheDownloadService::get_instance().set_global_timeout_options(20, 1);
let http_timeout = CacheDownloadService::get_instance().get_global_http_total_timeout();
assert_eq!(http_timeout, 1);
CacheDownloadService::get_instance().set_global_timeout_options(20, 60);
}
#[test]
fn ut_remove_file_cache() {
let test_url = TEST_TEXT_URL.lock().unwrap();
CacheDownloadService::get_instance().remove(test_url.as_ref());
let success_flag = Arc::new(AtomicUsize::new(0));
let callback = Box::new(TestCallbackS {
flag: success_flag.clone(),
});
let handle = CacheDownloadService::get_instance().preload(
DownloadRequest::new(test_url.as_ref()),
callback,
true,
DOWNLOADER,
);
assert!(handle.is_some());
let handle = handle.unwrap();
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
let cache = CacheDownloadService::get_instance().fetch(test_url.as_ref());
assert!(cache.is_some());
let path = get_curr_store_dir();
let task_id = handle.task_id();
let file_name = format!("{}{}", task_id, FINISH_SUFFIX);
let file_path = path.join(file_name);
assert!(file_path.exists());
CacheDownloadService::get_instance().clear_file_cache();
assert!(!file_path.exists());
let cache = CacheDownloadService::get_instance().fetch(test_url.as_ref());
assert!(cache.is_some());
}
#[test]
fn ut_remove_ram_cache() {
let test_url = TEST_TEXT_URL.lock().unwrap();
CacheDownloadService::get_instance().remove(test_url.as_ref());
let success_flag = Arc::new(AtomicUsize::new(0));
let callback = Box::new(TestCallbackS {
flag: success_flag.clone(),
});
let handle = CacheDownloadService::get_instance().preload(
DownloadRequest::new(test_url.as_ref()),
callback,
true,
DOWNLOADER,
);
assert!(handle.is_some());
let handle = handle.unwrap();
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
let cache = CacheDownloadService::get_instance().fetch(test_url.as_ref());
assert!(cache.is_some());
drop(cache);
CacheDownloadService::get_instance().clear_memory_cache();
let cache = CacheDownloadService::get_instance().fetch(test_url.as_ref());
assert!(cache.is_some());
drop(cache);
CacheDownloadService::get_instance().clear_memory_cache();
CacheDownloadService::get_instance().clear_file_cache();
let cache = CacheDownloadService::get_instance().fetch(test_url.as_ref());
assert!(cache.is_none());
}
#[test]
fn ut_remove_finished_caches() {
let test_url = TEST_TEXT_URL.lock().unwrap();
CacheDownloadService::get_instance().remove(test_url.as_ref());
CacheDownloadService::get_instance().remove(TEST_VIDEO_URL);
let success_flag = Arc::new(AtomicUsize::new(0));
let callback = Box::new(TestCallbackS {
flag: success_flag.clone(),
});
let handle = CacheDownloadService::get_instance().preload(
DownloadRequest::new(test_url.as_ref()),
callback,
true,
DOWNLOADER,
);
assert!(handle.is_some());
let handle = handle.unwrap();
while !handle.is_finish() {
thread::sleep(Duration::from_millis(500));
}
let success_flag2 = Arc::new(AtomicUsize::new(0));
let callback2 = Box::new(TestCallbackS {
flag: success_flag2.clone(),
});
let handle2 = CacheDownloadService::get_instance().preload(
DownloadRequest::new(TEST_VIDEO_URL),
callback2,
true,
DOWNLOADER,
);
CacheDownloadService::get_instance().clear_memory_cache();
CacheDownloadService::get_instance().clear_file_cache();
assert!(handle2.is_some());
let handle2 = handle2.unwrap();
while !handle2.is_finish() {
thread::sleep(Duration::from_millis(500));
}
let cache = CacheDownloadService::get_instance().fetch(test_url.as_ref());
assert!(cache.is_none());
let cache = CacheDownloadService::get_instance().fetch(TEST_VIDEO_URL);
assert!(cache.is_some());
}
#[test]
fn ut_download_fetch_after_init() {
const SELF_CREATE_URL: &str = "http://www.file.not.exists.com";
let path = get_curr_store_dir();
let res = fs::create_dir_all(&path);
assert!(res.is_ok());
let task_id = TaskId::from_url(SELF_CREATE_URL);
let file_name = format!("{}{}", task_id, FINISH_SUFFIX);
let file_path = path.join(file_name);
let res = fs::write(file_path, "hello");
assert!(res.is_ok());
let first_ram = CacheDownloadService::get_instance().fetch(SELF_CREATE_URL);
if let Some(ram) = first_ram {
let data = ram.cursor().into_inner();
assert_eq!(data, b"hello");
} else {
thread::sleep(Duration::from_millis(100));
let ram = CacheDownloadService::get_instance().fetch(SELF_CREATE_URL);
assert!(ram.is_some());
let ram = ram.unwrap();
let data = ram.cursor().into_inner();
assert_eq!(data, b"hello");
}
CacheDownloadService::get_instance().remove(SELF_CREATE_URL);
}
pub fn get_curr_store_dir() -> PathBuf {
let mut path = match request_application::application::wrapper::get_cache_dir() {
Some(dir) => PathBuf::from_str(&dir).unwrap(),
None => {
error!("get cache dir failed");
PathBuf::from_str("/data/storage/el2/base/cache").unwrap()
}
};
path.push("preload_caches");
path
}