1 // Copyright (C) 2024 Huawei Device Co., Ltd. 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 #[cfg(test)] 15 mod tests { 16 use super::*; 17 use crate::{error::HttpErrorCode, info::DownloadInfoMgr}; 18 use std::sync::{Arc, AtomicBool, Mutex}; 19 use std::cell::RefCell; 20 use mockall::mock; 21 22 mock! { 23 pub RequestCallback {} 24 impl RequestCallback for RequestCallback { 25 fn on_success(&mut self, response: Response); 26 fn on_fail(&mut self, error: HttpClientError); 27 fn on_cancel(&mut self); 28 fn on_data_receive(&mut self, data: &[u8], task: RequestTask); 29 fn on_progress(&mut self, dl_total: u64, dl_now: u64, ul_total: u64, ul_now: u64); 30 fn on_restart(&mut self); 31 } 32 } 33 34 // @tc.name: ut_callback_wrapper_creation 35 // @tc.desc: Test CallbackWrapper creation with valid parameters 36 // @tc.precon: NA 37 // @tc.step: 1. Create mock RequestCallback 38 // 2. Create required Arc and Weak pointers 39 // 3. Initialize CallbackWrapper with from_callback method 40 // @tc.expect: CallbackWrapper is successfully created with correct initial state 41 // @tc.type: FUNC 42 // @tc.require: issueNumber 43 // @tc.level: Level 0 44 #[test] ut_callback_wrapper_creation()45 fn ut_callback_wrapper_creation() { 46 let mock_callback = Box::new(MockRequestCallback::new()); 47 let reset = Arc::new(AtomicBool::new(false)); 48 let task = Arc::new(Mutex::new(SharedPtr::null())); 49 let task_weak = Arc::downgrade(&task); 50 let task_id = TaskId::new(); 51 let info_mgr = Arc::new(DownloadInfoMgr::new()); 52 53 let wrapper = CallbackWrapper::from_callback( 54 mock_callback, 55 reset.clone(), 56 task_weak, 57 task_id.clone(), 58 info_mgr.clone(), 59 0 60 ); 61 62 assert!(!wrapper.reset.load(Ordering::SeqCst)); 63 assert_eq!(wrapper.task_id, task_id); 64 assert_eq!(wrapper.current, 0); 65 assert_eq!(wrapper.tries, 0); 66 assert!(wrapper.inner.is_some()); 67 } 68 69 // @tc.name: ut_callback_wrapper_on_success_200 70 // @tc.desc: Test on_success callback with 200 status code 71 // @tc.precon: CallbackWrapper initialized with mock callback 72 // @tc.step: 1. Create test response with OK status 73 // 2. Call on_success method 74 // 3. Verify callback was triggered with success 75 // @tc.expect: on_success is called with properly converted Response 76 // @tc.type: FUNC 77 // @tc.require: issueNumber 78 // @tc.level: Level 1 79 #[test] ut_callback_wrapper_on_success_200()80 fn ut_callback_wrapper_on_success_200() { 81 let mut mock = MockRequestCallback::new(); 82 mock.expect_on_success().once().return_const(()); 83 84 let wrapper = create_test_wrapper(Box::new(mock)); 85 let mut wrapper = RefCell::new(wrapper); 86 87 let request = ffi::NewHttpClientRequest(); 88 let response = create_mock_response(ffi::ResponseCode::OK); 89 90 wrapper.borrow_mut().on_success(&request, &response); 91 92 assert!(wrapper.borrow().inner.is_none()); 93 } 94 95 // @tc.name: ut_callback_wrapper_on_success_error_status 96 // @tc.desc: Test on_success callback with error status code 97 // @tc.precon: CallbackWrapper initialized with mock callback 98 // @tc.step: 1. Create test response with 404 status 99 // 2. Call on_success method 100 // 3. Verify callback was triggered with failure 101 // @tc.expect: on_fail is called with appropriate error 102 // @tc.type: FUNC 103 // @tc.require: issueNumber 104 // @tc.level: Level 2 105 #[test] ut_callback_wrapper_on_success_error_status()106 fn ut_callback_wrapper_on_success_error_status() { 107 let mut mock = MockRequestCallback::new(); 108 mock.expect_on_fail().once().return_const(()); 109 110 let wrapper = create_test_wrapper(Box::new(mock)); 111 let mut wrapper = RefCell::new(wrapper); 112 113 let request = ffi::NewHttpClientRequest(); 114 let response = create_mock_response(ffi::ResponseCode::NOT_FOUND); 115 116 wrapper.borrow_mut().on_success(&request, &response); 117 118 assert!(wrapper.borrow().inner.is_none()); 119 } 120 121 // @tc.name: ut_task_status_try_from 122 // @tc.desc: Test TryFrom conversion for TaskStatus enum 123 // @tc.precon: NA 124 // @tc.step: 1. Attempt conversion from valid ffi::TaskStatus 125 // 2. Attempt conversion from invalid ffi::TaskStatus 126 // @tc.expect: Valid conversions succeed, invalid returns Err 127 // @tc.type: FUNC 128 // @tc.require: issueNumber 129 // @tc.level: Level 1 130 #[test] ut_task_status_try_from()131 fn ut_task_status_try_from() { 132 assert!(matches!(TaskStatus::try_from(ffi::TaskStatus::IDLE), Ok(TaskStatus::Idle))); 133 assert!(matches!(TaskStatus::try_from(ffi::TaskStatus::RUNNING), Ok(TaskStatus::Running))); 134 135 // Test invalid variant (using out-of-range value) 136 let invalid_status = unsafe { std::mem::transmute(999) }; 137 assert!(matches!(TaskStatus::try_from(invalid_status), Err(_))); 138 } 139 140 // @tc.name: ut_response_code_try_from 141 // @tc.desc: Test TryFrom conversion for ResponseCode enum 142 // @tc.precon: NA 143 // @tc.step: 1. Test conversion for multiple valid ResponseCode variants 144 // 2. Test conversion for invalid ResponseCode 145 // @tc.expect: Valid conversions return correct ResponseCode, invalid returns Err 146 // @tc.type: FUNC 147 // @tc.require: issueNumber 148 // @tc.level: Level 1 149 #[test] ut_response_code_try_from()150 fn ut_response_code_try_from() { 151 assert!(matches!(ResponseCode::try_from(ffi::ResponseCode::OK), Ok(ResponseCode::Ok))); 152 assert!(matches!(ResponseCode::try_from(ffi::ResponseCode::NOT_FOUND), Ok(ResponseCode::NotFound))); 153 assert!(matches!(ResponseCode::try_from(ffi::ResponseCode::INTERNAL_ERROR), Ok(ResponseCode::InternalError))); 154 155 // Test invalid variant 156 let invalid_code = unsafe { std::mem::transmute(999) }; 157 assert!(matches!(ResponseCode::try_from(invalid_code), Err(_))); 158 } 159 160 // @tc.name: ut_http_error_code_try_from 161 // @tc.desc: Test TryFrom conversion for HttpErrorCode enum 162 // @tc.precon: NA 163 // @tc.step: 1. Test conversion for multiple HttpErrorCode variants 164 // 2. Test edge case with unknown error code 165 // @tc.expect: Valid conversions return correct HttpErrorCode, unknown returns Err 166 // @tc.type: FUNC 167 // @tc.require: issueNumber 168 // @tc.level: Level 2 169 #[test] ut_http_error_code_try_from()170 fn ut_http_error_code_try_from() { 171 assert!(matches!(HttpErrorCode::try_from(ffi::HttpErrorCode::HTTP_NONE_ERR), Ok(HttpErrorCode::HttpNoneErr))); 172 assert!(matches!(HttpErrorCode::try_from(ffi::HttpErrorCode::HTTP_WRITE_ERROR), Ok(HttpErrorCode::HttpWriteError))); 173 assert!(matches!(HttpErrorCode::try_from(ffi::HttpErrorCode::HTTP_TASK_CANCELED), Ok(HttpErrorCode::HttpTaskCanceled))); 174 175 // Test edge case with unknown error code 176 let unknown_code = unsafe { std::mem::transmute(ffi::HttpErrorCode::HTTP_UNKNOWN_OTHER_ERROR) }; 177 assert!(matches!(HttpErrorCode::try_from(unknown_code), Ok(HttpErrorCode::HttpUnknownOtherError))); 178 } 179 180 // @tc.name: ut_callback_wrapper_on_progress 181 // @tc.desc: Test progress callback functionality 182 // @tc.precon: CallbackWrapper initialized with mock callback 183 // @tc.step: 1. Set up mock to expect progress call 184 // 2. Call on_progress with test values 185 // 3. Verify mock was called with correct parameters 186 // @tc.expect: on_progress is called with matching parameters 187 // @tc.type: FUNC 188 // @tc.require: issueNumber 189 // @tc.level: Level 1 190 #[test] ut_callback_wrapper_on_progress()191 fn ut_callback_wrapper_on_progress() { 192 let mut mock = MockRequestCallback::new(); 193 mock.expect_on_progress() 194 .withf(|dl_total, dl_now, ul_total, ul_now| 195 *dl_total == 1000 && *dl_now == 500 && *ul_total == 200 && *ul_now == 100) 196 .once() 197 .return_const(()); 198 199 let wrapper = create_test_wrapper(Box::new(mock)); 200 let mut wrapper = RefCell::new(wrapper); 201 202 wrapper.borrow_mut().on_progress(1000, 500, 200, 100); 203 } 204 205 // @tc.name: ut_callback_wrapper_on_cancel_reset 206 // @tc.desc: Test cancel behavior when reset flag is set 207 // @tc.precon: CallbackWrapper with reset flag set to true 208 // @tc.step: 1. Configure wrapper with reset=true 209 // 2. Call on_cancel method 210 // 3. Verify new task creation and callback restart 211 // @tc.expect: New task is created and reset flag is cleared 212 // @tc.type: FUNC 213 // @tc.require: issueNumber 214 // @tc.level: Level 3 215 #[test] ut_callback_wrapper_on_cancel_reset()216 fn ut_callback_wrapper_on_cancel_reset() { 217 let mut mock = MockRequestCallback::new(); 218 mock.expect_on_restart().once().return_const(()); 219 220 let reset = Arc::new(AtomicBool::new(true)); 221 let wrapper = create_test_wrapper_with_reset(Box::new(mock), reset.clone()); 222 let mut wrapper = RefCell::new(wrapper); 223 224 let request = ffi::NewHttpClientRequest(); 225 let response = create_mock_response(ffi::ResponseCode::OK); 226 227 wrapper.borrow_mut().on_cancel(&request, &response); 228 229 assert!(!reset.load(Ordering::SeqCst)); 230 } 231 232 // Helper functions for test setup create_test_wrapper(callback: Box<dyn RequestCallback>) -> CallbackWrapper233 fn create_test_wrapper(callback: Box<dyn RequestCallback>) -> CallbackWrapper { 234 let reset = Arc::new(AtomicBool::new(false)); 235 let task = Arc::new(Mutex::new(SharedPtr::null())); 236 let task_weak = Arc::downgrade(&task); 237 let task_id = TaskId::new(); 238 let info_mgr = Arc::new(DownloadInfoMgr::new()); 239 240 CallbackWrapper::from_callback(callback, reset, task_weak, task_id, info_mgr, 0) 241 } 242 create_test_wrapper_with_reset(callback: Box<dyn RequestCallback>, reset: Arc<AtomicBool>) -> CallbackWrapper243 fn create_test_wrapper_with_reset(callback: Box<dyn RequestCallback>, reset: Arc<AtomicBool>) -> CallbackWrapper { 244 let task = Arc::new(Mutex::new(SharedPtr::null())); 245 let task_weak = Arc::downgrade(&task); 246 let task_id = TaskId::new(); 247 let info_mgr = Arc::new(DownloadInfoMgr::new()); 248 249 CallbackWrapper::from_callback(callback, reset, task_weak, task_id, info_mgr, 0) 250 } 251 create_mock_response(code: ffi::ResponseCode) -> ffi::HttpClientResponse252 fn create_mock_response(code: ffi::ResponseCode) -> ffi::HttpClientResponse { 253 // In a real test environment, this would be replaced with actual mock implementation 254 unsafe { std::mem::zeroed() } 255 } 256 }