1 // Copyright (C) 2023 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 use std::collections::HashSet;
15
16 use crate::config::{Action, Mode, Version};
17 use crate::info::State;
18 use crate::manage::network::{NetworkInfo, NetworkState, NetworkType};
19 use crate::task::reason::Reason;
20
21 const INITIALIZED: u8 = State::Initialized.repr;
22 const RUNNING: u8 = State::Running.repr;
23 const RETRYING: u8 = State::Retrying.repr;
24 const WAITING: u8 = State::Waiting.repr;
25 const PAUSED: u8 = State::Paused.repr;
26 const STOPPED: u8 = State::Stopped.repr;
27 const FAILED: u8 = State::Failed.repr;
28
29 const APP_BACKGROUND_OR_TERMINATE: u8 = Reason::AppBackgroundOrTerminate.repr;
30 const RUNNING_TASK_MEET_LIMITS: u8 = Reason::RunningTaskMeetLimits.repr;
31 const ACCOUNT_STOPPED: u8 = Reason::AccountStopped.repr;
32 const NETWORK_OFFLINE: u8 = Reason::NetworkOffline.repr;
33 const UNSUPPORTED_NETWORK_TYPE: u8 = Reason::UnsupportedNetworkType.repr;
34 const NETWORK_APP: u8 = Reason::NetworkApp.repr;
35 const NETWORK_ACCOUNT: u8 = Reason::NetworkAccount.repr;
36 const APP_ACCOUNT: u8 = Reason::AppAccount.repr;
37 const NETWORK_APP_ACCOUNT: u8 = Reason::NetworkAppAccount.repr;
38
39 const DOWNLOAD: u8 = Action::Download.repr;
40 const UPLOAD: u8 = Action::Upload.repr;
41
42 const BACKGROUND: u8 = Mode::BackGround.repr;
43 const FRONTEND: u8 = Mode::FrontEnd.repr;
44
45 const API9: u8 = Version::API9 as u8;
46 const API10: u8 = Version::API10 as u8;
47
48 pub(crate) struct SqlList {
49 sqls: Vec<String>,
50 }
51
52 impl SqlList {
new() -> Self53 pub(crate) fn new() -> Self {
54 SqlList { sqls: Vec::new() }
55 }
56
add_network_change(&mut self, info: &NetworkState)57 pub(crate) fn add_network_change(&mut self, info: &NetworkState) {
58 match info {
59 NetworkState::Online(info) => {
60 self.sqls.push(network_available(info));
61 if let Some(sql) = network_unavailable(info) {
62 self.sqls.push(sql);
63 }
64 }
65 NetworkState::Offline => {
66 self.sqls.push(network_offline());
67 }
68 }
69 }
70
add_account_change(&mut self, active_accounts: &HashSet<u64>)71 pub(crate) fn add_account_change(&mut self, active_accounts: &HashSet<u64>) {
72 self.sqls.push(account_available(active_accounts));
73 self.sqls.push(account_unavailable(active_accounts));
74 }
75
add_app_state_available(&mut self, top_uid: u64)76 pub(crate) fn add_app_state_available(&mut self, top_uid: u64) {
77 self.sqls.push(app_state_available(top_uid));
78 }
79
add_app_state_unavailable(&mut self, uid: u64)80 pub(crate) fn add_app_state_unavailable(&mut self, uid: u64) {
81 self.sqls.push(app_state_unavailable(uid));
82 }
83
add_app_uninstall(&mut self, uid: u64)84 pub(crate) fn add_app_uninstall(&mut self, uid: u64) {
85 self.sqls.push(app_uninstall(uid));
86 }
add_special_process_terminate(&mut self, uid: u64)87 pub(crate) fn add_special_process_terminate(&mut self, uid: u64) {
88 self.sqls.push(special_process_terminate(uid));
89 }
90 }
91
92 impl Iterator for SqlList {
93 type Item = String;
94
next(&mut self) -> Option<Self::Item>95 fn next(&mut self) -> Option<Self::Item> {
96 self.sqls.pop()
97 }
98 }
99
app_uninstall(uid: u64) -> String100 pub(crate) fn app_uninstall(uid: u64) -> String {
101 format!("DELETE FROM request_task WHERE uid = {}", uid)
102 }
103
app_state_unavailable(uid: u64) -> String104 pub(crate) fn app_state_unavailable(uid: u64) -> String {
105 format!(
106 "UPDATE request_task SET
107 state = CASE
108 WHEN (state = {RUNNING} OR state = {RETRYING}) AND action = {DOWNLOAD} THEN {WAITING}
109 WHEN (state = {RUNNING} OR state = {RETRYING}) AND action = {UPLOAD} THEN {FAILED}
110 ELSE state
111 END,
112 reason = CASE
113 WHEN (state = {RUNNING} OR state = {RETRYING}) THEN {APP_BACKGROUND_OR_TERMINATE}
114 WHEN state = {WAITING} THEN
115 CASE reason
116 WHEN {RUNNING_TASK_MEET_LIMITS} THEN {APP_BACKGROUND_OR_TERMINATE}
117 WHEN {NETWORK_OFFLINE} THEN {NETWORK_APP}
118 WHEN {UNSUPPORTED_NETWORK_TYPE} THEN {NETWORK_APP}
119 WHEN {ACCOUNT_STOPPED} THEN {APP_ACCOUNT}
120 WHEN {NETWORK_ACCOUNT} THEN {NETWORK_APP_ACCOUNT}
121 ELSE reason
122 END
123 ELSE reason
124 END
125 WHERE
126 uid = {uid} AND mode = {FRONTEND}",
127 )
128 }
129
app_state_available(uid: u64) -> String130 pub(crate) fn app_state_available(uid: u64) -> String {
131 format!(
132 "UPDATE request_task SET
133 reason = CASE
134 WHEN reason = {APP_BACKGROUND_OR_TERMINATE} THEN {RUNNING_TASK_MEET_LIMITS}
135 WHEN reason = {NETWORK_APP} THEN {NETWORK_OFFLINE}
136 WHEN reason = {APP_ACCOUNT} THEN {ACCOUNT_STOPPED}
137 WHEN reason = {NETWORK_APP_ACCOUNT} THEN {NETWORK_ACCOUNT}
138 ELSE reason
139 END
140 WHERE
141 state = {WAITING} AND uid = {uid}",
142 )
143 }
144
account_unavailable(active_accounts: &HashSet<u64>) -> String145 pub(super) fn account_unavailable(active_accounts: &HashSet<u64>) -> String {
146 let mut sql = format!(
147 "UPDATE request_task SET
148 state = CASE
149 WHEN state = {RUNNING} OR state = {RETRYING} THEN {WAITING}
150 ELSE state
151 END,
152 reason = CASE
153 WHEN (state = {RUNNING} OR state = {RETRYING}) THEN {ACCOUNT_STOPPED}
154 WHEN state = {WAITING} THEN
155 CASE reason
156 WHEN {RUNNING_TASK_MEET_LIMITS} THEN {ACCOUNT_STOPPED}
157 WHEN {NETWORK_OFFLINE} THEN {NETWORK_ACCOUNT}
158 WHEN {UNSUPPORTED_NETWORK_TYPE} THEN {NETWORK_ACCOUNT}
159 WHEN {APP_BACKGROUND_OR_TERMINATE} THEN {APP_ACCOUNT}
160 WHEN {NETWORK_APP} THEN {NETWORK_APP_ACCOUNT}
161 ELSE reason
162 END
163 ELSE reason
164 END
165 WHERE
166 uid/200000 NOT IN (",
167 );
168
169 for active_account in active_accounts {
170 sql.push_str(&format!("{},", active_account));
171 }
172 if !active_accounts.is_empty() {
173 sql.pop();
174 }
175
176 sql.push(')');
177 sql
178 }
179
account_available(active_accounts: &HashSet<u64>) -> String180 pub(super) fn account_available(active_accounts: &HashSet<u64>) -> String {
181 let mut sql = format!(
182 "UPDATE request_task SET
183 reason = CASE
184 WHEN reason= {ACCOUNT_STOPPED} THEN {RUNNING_TASK_MEET_LIMITS}
185 WHEN reason = {NETWORK_ACCOUNT} THEN {NETWORK_OFFLINE}
186 WHEN reason = {APP_ACCOUNT} THEN {APP_BACKGROUND_OR_TERMINATE}
187 WHEN reason = {NETWORK_APP_ACCOUNT} THEN {NETWORK_APP}
188 ELSE reason
189 END
190 WHERE
191 state = {WAITING} AND uid/200000 IN (",
192 );
193
194 for active_account in active_accounts {
195 sql.push_str(&format!("{},", active_account));
196 }
197 if !active_accounts.is_empty() {
198 sql.pop();
199 }
200 sql.push(')');
201 sql
202 }
203
network_offline() -> String204 pub(super) fn network_offline() -> String {
205 format!(
206 "UPDATE request_task SET
207 state = CASE
208 WHEN (state = {RUNNING} OR state = {RETRYING}) AND ((version = {API9} AND action = {DOWNLOAD}) OR (version = {API10} AND mode = {BACKGROUND} AND retry = 1)) THEN {WAITING}
209 WHEN (state = {RUNNING} OR state = {RETRYING}) AND ((version = {API9} AND action = {UPLOAD}) OR (version = {API10} AND (mode = {FRONTEND} OR retry = 0))) THEN {FAILED}
210 ELSE state
211 END,
212 reason = CASE
213 WHEN state = {RUNNING} OR state = {RETRYING} THEN {NETWORK_OFFLINE}
214 WHEN state = {WAITING} THEN
215 CASE reason
216 WHEN {RUNNING_TASK_MEET_LIMITS} THEN {NETWORK_OFFLINE}
217 WHEN {ACCOUNT_STOPPED} THEN {NETWORK_ACCOUNT}
218 WHEN {APP_BACKGROUND_OR_TERMINATE} THEN {NETWORK_APP}
219 WHEN {APP_ACCOUNT} THEN {NETWORK_APP_ACCOUNT}
220 ELSE reason
221 END
222 ELSE reason
223 END"
224 )
225 }
226
network_unavailable(info: &NetworkInfo) -> Option<String>227 pub(super) fn network_unavailable(info: &NetworkInfo) -> Option<String> {
228 if info.network_type == NetworkType::Other {
229 return None;
230 }
231 let mut unsupported_condition = format!("network != {}", info.network_type.repr);
232 if info.is_metered {
233 unsupported_condition.push_str(" OR metered = 0");
234 }
235 if info.is_roaming {
236 unsupported_condition.push_str(" OR roaming = 0");
237 }
238 Some(format!(
239 "UPDATE request_task SET
240 state = CASE
241 WHEN (state = {RUNNING} OR state = {RETRYING}) AND ((version = {API9} AND action = {DOWNLOAD}) OR (version = {API10} AND mode = {BACKGROUND} AND retry = 1)) THEN {WAITING}
242 WHEN (state = {RUNNING} OR state = {RETRYING}) AND ((version = {API9} AND action = {UPLOAD}) OR (version = {API10} AND (mode = {FRONTEND} OR retry = 0))) THEN {FAILED}
243 ELSE state
244 END,
245 reason = CASE
246 WHEN state = {RUNNING} OR state = {RETRYING} THEN {UNSUPPORTED_NETWORK_TYPE}
247 WHEN state = {WAITING} THEN
248 CASE reason
249 WHEN {RUNNING_TASK_MEET_LIMITS} THEN {UNSUPPORTED_NETWORK_TYPE}
250 WHEN {ACCOUNT_STOPPED} THEN {NETWORK_ACCOUNT}
251 WHEN {APP_BACKGROUND_OR_TERMINATE} THEN {NETWORK_APP}
252 WHEN {APP_ACCOUNT} THEN {NETWORK_APP_ACCOUNT}
253 ELSE reason
254 END
255 ELSE reason
256 END
257 WHERE
258 {unsupported_condition}"
259 ))
260 }
261
network_available(info: &NetworkInfo) -> String262 pub(super) fn network_available(info: &NetworkInfo) -> String {
263 let mut sql = format!(
264 "UPDATE request_task SET
265 reason = CASE
266 WHEN reason = {NETWORK_OFFLINE} THEN {RUNNING_TASK_MEET_LIMITS}
267 WHEN reason = {UNSUPPORTED_NETWORK_TYPE} THEN {RUNNING_TASK_MEET_LIMITS}
268 WHEN reason = {NETWORK_ACCOUNT} THEN {ACCOUNT_STOPPED}
269 WHEN reason = {NETWORK_APP} THEN {APP_BACKGROUND_OR_TERMINATE}
270 WHEN reason = {NETWORK_APP_ACCOUNT} THEN {APP_ACCOUNT}
271 ELSE reason
272 END
273 WHERE
274 state = {WAITING}",
275 );
276
277 if info.network_type == NetworkType::Other {
278 return sql;
279 }
280
281 sql.push_str(&format!(
282 " AND (network = 0 OR network = {}",
283 info.network_type.repr
284 ));
285 if info.is_metered {
286 sql.push_str(" AND metered = 1");
287 }
288 if info.is_roaming {
289 sql.push_str(" AND roaming = 1");
290 }
291 sql.push(')');
292 sql
293 }
294
special_process_terminate(uid: u64) -> String295 pub(crate) fn special_process_terminate(uid: u64) -> String {
296 format!(
297 "UPDATE request_task
298 SET
299 state = {FAILED},
300 reason = {APP_BACKGROUND_OR_TERMINATE}
301 WHERE
302 uid = {uid}
303 AND (
304 state = {INITIALIZED}
305 OR state = {RUNNING}
306 OR state = {RETRYING}
307 OR state = {WAITING}
308 OR state = {PAUSED}
309 OR state = {STOPPED}
310 );",
311 )
312 }
313
314 #[cfg(feature = "oh")]
315 #[cfg(test)]
316 mod test {
317
318 use super::*;
319 use crate::config::NetworkConfig;
320 use crate::manage::database::RequestDb;
321 use crate::tests::{lock_database, test_init};
322 use crate::utils::get_current_timestamp;
323 use crate::utils::task_id_generator::TaskIdGenerator;
324
325 const COMPLETED: u8 = State::Completed.repr;
326 const PAUSED: u8 = State::Paused.repr;
327 const INIT: u8 = State::Initialized.repr;
328 const WIFI: u8 = NetworkConfig::Wifi as u8;
329 const CELLULAR: u8 = NetworkConfig::Cellular as u8;
330
query_state_and_reason(task_id: u32) -> (u8, u8)331 fn query_state_and_reason(task_id: u32) -> (u8, u8) {
332 let db = RequestDb::get_instance();
333 (
334 db.query_integer(&format!(
335 "SELECT state FROM request_task where task_id = {task_id}"
336 ))[0],
337 db.query_integer(&format!(
338 "SELECT reason FROM request_task where task_id = {task_id}"
339 ))[0],
340 )
341 }
342
network(sql: &str, change_reason: u8)343 fn network(sql: &str, change_reason: u8) {
344 let db = RequestDb::get_instance();
345 let task_id = TaskIdGenerator::generate();
346 let fail_reason = get_current_timestamp() as u8;
347
348 // running
349 db.execute(&format!(
350 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network, version, mode, retry) VALUES ({task_id}, {RUNNING}, {fail_reason}, {WIFI}, {API10}, {BACKGROUND}, 1)",
351 ))
352 .unwrap();
353 db.execute(sql).unwrap();
354 let (state, reason) = query_state_and_reason(task_id);
355 assert_eq!(state, WAITING);
356 assert_eq!(reason, change_reason);
357
358 db.execute(&format!(
359 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network, version, action) VALUES ({task_id}, {RUNNING}, {fail_reason}, {WIFI}, {API9}, {DOWNLOAD})",
360 ))
361 .unwrap();
362 db.execute(sql).unwrap();
363 let (state, reason) = query_state_and_reason(task_id);
364 assert_eq!(state, WAITING);
365 assert_eq!(reason, change_reason);
366
367 db.execute(&format!(
368 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network, version, action) VALUES ({task_id}, {RUNNING}, {fail_reason}, {WIFI}, {API9}, {UPLOAD})",
369 ))
370 .unwrap();
371 db.execute(sql).unwrap();
372 let (state, reason) = query_state_and_reason(task_id);
373 assert_eq!(state, FAILED);
374 assert_eq!(reason, change_reason);
375
376 db.execute(&format!(
377 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network, version, mode, retry) VALUES ({task_id}, {RUNNING}, {fail_reason}, {WIFI}, {API10}, {FRONTEND}, 1)",
378 ))
379 .unwrap();
380 db.execute(sql).unwrap();
381 let (state, reason) = query_state_and_reason(task_id);
382 assert_eq!(state, FAILED);
383 assert_eq!(reason, change_reason);
384
385 db.execute(&format!(
386 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network, version, mode, retry) VALUES ({task_id}, {RUNNING}, {fail_reason}, {WIFI}, {API10}, {BACKGROUND}, 0)",
387 ))
388 .unwrap();
389 db.execute(sql).unwrap();
390 let (state, reason) = query_state_and_reason(task_id);
391 assert_eq!(state, FAILED);
392 assert_eq!(reason, change_reason);
393
394 // other state
395 db.execute(&format!(
396 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network) VALUES ({task_id}, {FAILED}, {fail_reason}, {WIFI})",
397 ))
398 .unwrap();
399 db.execute(sql).unwrap();
400
401 let (state, reason) = query_state_and_reason(task_id);
402 assert_eq!(state, FAILED);
403 assert_eq!(reason, fail_reason);
404
405 // waiting
406 db.execute(&format!(
407 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network) VALUES ({task_id}, {WAITING}, {RUNNING_TASK_MEET_LIMITS}, {WIFI})",
408 ))
409 .unwrap();
410 db.execute(sql).unwrap();
411
412 let (state, reason) = query_state_and_reason(task_id);
413 assert_eq!(state, WAITING);
414 assert_eq!(reason, change_reason);
415
416 // api9 + download
417 db.execute(&format!(
418 "INSERT OR REPLACE INTO request_task (task_id, state, version, action, network, metered, roaming) VALUES ({task_id}, {RUNNING}, {API9}, {DOWNLOAD}, {CELLULAR}, 1, 0)",
419 ))
420 .unwrap();
421 db.execute(sql).unwrap();
422
423 let (state, reason) = query_state_and_reason(task_id);
424 assert_eq!(state, WAITING);
425 assert_eq!(reason, change_reason);
426
427 // api9 + upload
428 db.execute(&format!(
429 "INSERT OR REPLACE INTO request_task (task_id, state, version, action, network, metered, roaming) VALUES ({task_id}, {RUNNING}, {API9}, {UPLOAD}, {CELLULAR}, 0, 1)",
430 ))
431 .unwrap();
432 db.execute(sql).unwrap();
433
434 let (state, reason) = query_state_and_reason(task_id);
435 assert_eq!(state, FAILED);
436 assert_eq!(reason, change_reason);
437
438 // api10 + background + retry
439 db.execute(&format!(
440 "INSERT OR REPLACE INTO request_task (task_id, state, version, mode, retry, network, metered, roaming) VALUES ({task_id}, {RUNNING}, {API10}, {BACKGROUND}, 1, {CELLULAR}, 0, 0)",
441 ))
442 .unwrap();
443 db.execute(sql).unwrap();
444
445 let (state, reason) = query_state_and_reason(task_id);
446 assert_eq!(state, WAITING);
447 assert_eq!(reason, change_reason);
448
449 // api10 + frontEnd + retry
450 db.execute(&format!(
451 "INSERT OR REPLACE INTO request_task (task_id, state, version, mode, retry, network) VALUES ({task_id}, {RUNNING}, {API10}, {FRONTEND}, 1, {WIFI})",
452 ))
453 .unwrap();
454 db.execute(sql).unwrap();
455
456 let (state, reason) = query_state_and_reason(task_id);
457 assert_eq!(state, FAILED);
458 assert_eq!(reason, change_reason);
459
460 // api10 + Background
461 db.execute(&format!(
462 "INSERT OR REPLACE INTO request_task (task_id, state, version, mode, retry, network) VALUES ({task_id}, {RUNNING}, {API10}, {BACKGROUND}, 0, {WIFI})",
463 ))
464 .unwrap();
465 db.execute(sql).unwrap();
466
467 let (state, reason) = query_state_and_reason(task_id);
468 assert_eq!(state, FAILED);
469 assert_eq!(reason, change_reason);
470 }
471
472 #[test]
ut_network_offline()473 fn ut_network_offline() {
474 test_init();
475 let _lock = lock_database();
476 network(&network_offline(), NETWORK_OFFLINE);
477 }
478
479 #[test]
ut_network_unsupported()480 fn ut_network_unsupported() {
481 test_init();
482 let _lock = lock_database();
483 let info = NetworkInfo {
484 network_type: NetworkType::Cellular,
485 is_metered: true,
486 is_roaming: true,
487 };
488 network(
489 &network_unavailable(&info).unwrap(),
490 UNSUPPORTED_NETWORK_TYPE,
491 );
492
493 // network type matches
494 let db = RequestDb::get_instance();
495 let task_id = TaskIdGenerator::generate();
496 db.execute(&format!(
497 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network, metered, roaming) VALUES ({task_id}, {WAITING}, {RUNNING_TASK_MEET_LIMITS}, {CELLULAR}, 1, 1)",
498 ))
499 .unwrap();
500 db.execute(&network_unavailable(&info).unwrap()).unwrap();
501
502 let (state, reason) = query_state_and_reason(task_id);
503 assert_eq!(state, WAITING);
504 assert_eq!(reason, RUNNING_TASK_MEET_LIMITS);
505 }
506
507 #[test]
ut_network_online()508 fn ut_network_online() {
509 test_init();
510 let _lock = lock_database();
511 let db = RequestDb::get_instance();
512 let task_id = TaskIdGenerator::generate();
513
514 let info = NetworkInfo {
515 network_type: NetworkType::Cellular,
516 is_metered: true,
517 is_roaming: true,
518 };
519
520 // unsupported
521 let unsupported_states = [
522 (WIFI, 1, 1),
523 (CELLULAR, 0, 0),
524 (CELLULAR, 1, 0),
525 (CELLULAR, 0, 1),
526 ];
527 for state in unsupported_states {
528 db.execute(&format!(
529 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network, metered, roaming) VALUES ({task_id}, {WAITING}, {NETWORK_OFFLINE}, {}, {}, {})",state.0,state.1,state.2
530 )).unwrap();
531
532 db.execute(&network_available(&info)).unwrap();
533
534 let state: u8 = db.query_integer(&format!(
535 "SELECT state FROM request_task where task_id = {task_id}"
536 ))[0];
537 let reason: u8 = db.query_integer(&format!(
538 "SELECT reason FROM request_task where task_id = {task_id}"
539 ))[0];
540 assert_eq!(state, WAITING);
541 assert_eq!(reason, NETWORK_OFFLINE);
542 }
543
544 // support
545 db.execute(&format!(
546 "INSERT OR REPLACE INTO request_task (task_id, state, reason, network, metered, roaming) VALUES ({task_id}, {WAITING}, {NETWORK_OFFLINE}, {CELLULAR}, 1, 1)"
547 )).unwrap();
548 db.execute(&network_available(&info)).unwrap();
549
550 let (state, reason) = query_state_and_reason(task_id);
551 assert_eq!(state, WAITING);
552 assert_eq!(reason, RUNNING_TASK_MEET_LIMITS);
553 }
554
555 #[test]
ut_app_state_unavailable()556 fn ut_app_state_unavailable() {
557 test_init();
558 let _lock = lock_database();
559 let db = RequestDb::get_instance();
560 let task_id = TaskIdGenerator::generate();
561 let uid = get_current_timestamp();
562 let fail_reason = get_current_timestamp() as u8;
563
564 // running
565 db.execute(&format!(
566 "INSERT OR REPLACE INTO request_task (task_id, uid, mode, state, reason, action) VALUES ({task_id}, {uid}, {FRONTEND}, {RUNNING}, {fail_reason}, {DOWNLOAD})"
567 )).unwrap();
568 db.execute(&app_state_unavailable(uid)).unwrap();
569
570 let (state, reason) = query_state_and_reason(task_id);
571 assert_eq!(state, WAITING);
572 assert_eq!(reason, APP_BACKGROUND_OR_TERMINATE);
573
574 // upload
575 db.execute(&format!(
576 "INSERT OR REPLACE INTO request_task (task_id, uid, mode, state, reason, action) VALUES ({task_id}, {uid}, {FRONTEND}, {RUNNING}, {fail_reason}, {UPLOAD})"
577 )).unwrap();
578 db.execute(&app_state_unavailable(uid)).unwrap();
579
580 let (state, reason) = query_state_and_reason(task_id);
581 assert_eq!(state, FAILED);
582 assert_eq!(reason, APP_BACKGROUND_OR_TERMINATE);
583
584 // retrying
585 db.execute(&format!(
586 "INSERT OR REPLACE INTO request_task (task_id, uid, mode, state, reason, action) VALUES ({task_id}, {uid}, {FRONTEND}, {RETRYING}, {fail_reason}, {DOWNLOAD})"
587 )).unwrap();
588 db.execute(&app_state_unavailable(uid)).unwrap();
589
590 let (state, reason) = query_state_and_reason(task_id);
591 assert_eq!(state, WAITING);
592 assert_eq!(reason, APP_BACKGROUND_OR_TERMINATE);
593
594 // other state
595 db.execute(&format!(
596 "INSERT OR REPLACE INTO request_task (task_id, uid, mode, state, reason) VALUES ({task_id}, {uid}, {FRONTEND}, {FAILED}, {fail_reason})"
597 )).unwrap();
598 db.execute(&app_state_unavailable(uid)).unwrap();
599
600 let (state, reason) = query_state_and_reason(task_id);
601 assert_eq!(state, FAILED);
602 assert_eq!(reason, fail_reason);
603
604 // waiting
605 db.execute(&format!(
606 "INSERT OR REPLACE INTO request_task (task_id, uid, mode, state, reason) VALUES ({task_id}, {uid}, {FRONTEND}, {WAITING}, {RUNNING_TASK_MEET_LIMITS})"
607 )).unwrap();
608 db.execute(&app_state_unavailable(uid)).unwrap();
609
610 let (state, reason) = query_state_and_reason(task_id);
611 assert_eq!(state, WAITING);
612 assert_eq!(reason, APP_BACKGROUND_OR_TERMINATE);
613
614 // running + donwload
615 db.execute(&format!(
616 "INSERT OR REPLACE INTO request_task (task_id, uid, mode, state, action) VALUES ({task_id}, {uid}, {FRONTEND}, {RUNNING}, {DOWNLOAD})"
617 )).unwrap();
618 db.execute(&app_state_unavailable(uid)).unwrap();
619
620 let (state, reason) = query_state_and_reason(task_id);
621 assert_eq!(state, WAITING);
622 assert_eq!(reason, APP_BACKGROUND_OR_TERMINATE);
623
624 // running + upload
625 db.execute(&format!(
626 "INSERT OR REPLACE INTO request_task (task_id, uid, mode, state, action) VALUES ({task_id}, {uid}, {FRONTEND}, {RUNNING}, {UPLOAD})"
627 )).unwrap();
628 db.execute(&app_state_unavailable(uid)).unwrap();
629
630 let (state, reason) = query_state_and_reason(task_id);
631 assert_eq!(state, FAILED);
632 assert_eq!(reason, APP_BACKGROUND_OR_TERMINATE);
633
634 // background
635 db.execute(&format!(
636 "INSERT OR REPLACE INTO request_task (task_id, uid, mode, state, action) VALUES ({task_id}, {uid}, {BACKGROUND}, {RUNNING}, {UPLOAD})"
637 )).unwrap();
638 db.execute(&app_state_unavailable(uid)).unwrap();
639
640 let state: u8 = db.query_integer(&format!(
641 "SELECT state FROM request_task where task_id = {task_id}"
642 ))[0];
643 assert_eq!(state, RUNNING);
644 }
645
646 #[test]
ut_app_state_available()647 fn ut_app_state_available() {
648 test_init();
649 let _lock = lock_database();
650 let db = RequestDb::get_instance();
651 let task_id = TaskIdGenerator::generate();
652 let uid = get_current_timestamp();
653
654 db.execute(&format!(
655 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason) VALUES ({task_id}, {uid}, {WAITING}, {APP_BACKGROUND_OR_TERMINATE})"
656 )).unwrap();
657 db.execute(&app_state_available(uid)).unwrap();
658
659 let (state, reason) = query_state_and_reason(task_id);
660 assert_eq!(state, WAITING);
661 assert_eq!(reason, RUNNING_TASK_MEET_LIMITS);
662 }
663
664 #[test]
ut_account_unavailable()665 fn ut_account_unavailable() {
666 test_init();
667 let _lock = lock_database();
668 let db = RequestDb::get_instance();
669 let task_id = TaskIdGenerator::generate();
670 let uid = get_current_timestamp();
671 let user = uid / 200000;
672
673 let mut hash_set = HashSet::new();
674 let states = [RUNNING, RETRYING, WAITING];
675 for (i, state) in states.into_iter().enumerate() {
676 db.execute(&format!(
677 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason) VALUES ({task_id}, {uid}, {state}, {RUNNING_TASK_MEET_LIMITS})"
678 )).unwrap();
679 db.execute(&account_unavailable(&hash_set)).unwrap();
680 let state: u8 = db.query_integer(&format!(
681 "SELECT state FROM request_task where task_id = {task_id}"
682 ))[0];
683 let reason: u8 = db.query_integer(&format!(
684 "SELECT reason FROM request_task where task_id = {task_id}"
685 ))[0];
686 assert_eq!(state, WAITING);
687 assert_eq!(reason, ACCOUNT_STOPPED);
688 hash_set.insert(user + i as u64 + 1);
689 }
690 let states = [COMPLETED, FAILED, PAUSED, INIT];
691 for state in states.into_iter() {
692 db.execute(&format!(
693 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason) VALUES ({task_id}, {uid}, {state}, {RUNNING_TASK_MEET_LIMITS})"
694 )).unwrap();
695 db.execute(&account_unavailable(&hash_set)).unwrap();
696 let change_state: u8 = db.query_integer(&format!(
697 "SELECT state FROM request_task where task_id = {task_id}"
698 ))[0];
699
700 assert_eq!(change_state, state);
701 let reason: u8 = db.query_integer(&format!(
702 "SELECT reason FROM request_task where task_id = {task_id}"
703 ))[0];
704 assert_eq!(reason, RUNNING_TASK_MEET_LIMITS);
705 }
706 }
707
708 #[test]
ut_account_available()709 fn ut_account_available() {
710 test_init();
711 let _lock = lock_database();
712 let db = RequestDb::get_instance();
713 let task_id = TaskIdGenerator::generate();
714 let uid = get_current_timestamp();
715 let user = uid / 200000;
716
717 let mut hash_set = HashSet::new();
718
719 db.execute(&format!(
720 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason) VALUES ({task_id}, {uid}, {WAITING}, {ACCOUNT_STOPPED})"
721 )).unwrap();
722 db.execute(&account_available(&hash_set)).unwrap();
723 let (state, reason) = query_state_and_reason(task_id);
724 assert_eq!(state, WAITING);
725 assert_eq!(reason, ACCOUNT_STOPPED);
726 hash_set.insert(user);
727 db.execute(&account_available(&hash_set)).unwrap();
728 let (state, reason) = query_state_and_reason(task_id);
729 assert_eq!(state, WAITING);
730 assert_eq!(reason, RUNNING_TASK_MEET_LIMITS);
731 }
732
733 #[test]
ut_multi_reason_available()734 fn ut_multi_reason_available() {
735 test_init();
736 let _lock = lock_database();
737 let db = RequestDb::get_instance();
738 let task_id = TaskIdGenerator::generate();
739 let uid = get_current_timestamp();
740 let user = uid / 200000;
741
742 let hash_set = HashSet::from([user]);
743 let info = NetworkInfo {
744 network_type: NetworkType::Cellular,
745 is_metered: true,
746 is_roaming: true,
747 };
748
749 // account + network
750 db.execute(&format!(
751 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_APP_ACCOUNT}, {CELLULAR}, 1, 1)"
752 )).unwrap();
753
754 db.execute(&account_available(&hash_set)).unwrap();
755 let (state, reason) = query_state_and_reason(task_id);
756 assert_eq!(state, WAITING);
757 assert_eq!(reason, NETWORK_APP);
758
759 db.execute(&network_available(&info)).unwrap();
760 let (state, reason) = query_state_and_reason(task_id);
761 assert_eq!(state, WAITING);
762 assert_eq!(reason, APP_BACKGROUND_OR_TERMINATE);
763
764 // account + app
765 db.execute(&format!(
766 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_APP_ACCOUNT}, {CELLULAR}, 1, 1)"
767 )).unwrap();
768
769 db.execute(&account_available(&hash_set)).unwrap();
770 db.execute(&app_state_available(uid)).unwrap();
771 let (state, reason) = query_state_and_reason(task_id);
772 assert_eq!(state, WAITING);
773 assert_eq!(reason, NETWORK_OFFLINE);
774
775 // network + app
776 db.execute(&format!(
777 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_APP_ACCOUNT}, {CELLULAR}, 1, 1)"
778 )).unwrap();
779 db.execute(&network_available(&info)).unwrap();
780 let (state, reason) = query_state_and_reason(task_id);
781 assert_eq!(state, WAITING);
782 assert_eq!(reason, APP_ACCOUNT);
783
784 db.execute(&app_state_available(uid)).unwrap();
785 let (state, reason) = query_state_and_reason(task_id);
786 assert_eq!(state, WAITING);
787 assert_eq!(reason, ACCOUNT_STOPPED);
788
789 // network + account
790 db.execute(&format!(
791 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_APP_ACCOUNT}, {CELLULAR}, 1, 1)"
792 )).unwrap();
793 db.execute(&network_available(&info)).unwrap();
794 db.execute(&account_available(&hash_set)).unwrap();
795 let (state, reason) = query_state_and_reason(task_id);
796 assert_eq!(state, WAITING);
797 assert_eq!(reason, APP_BACKGROUND_OR_TERMINATE);
798
799 // app + network
800 db.execute(&format!(
801 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_APP_ACCOUNT}, {CELLULAR}, 1, 1)"
802 )).unwrap();
803 db.execute(&app_state_available(uid)).unwrap();
804 let (state, reason) = query_state_and_reason(task_id);
805 assert_eq!(state, WAITING);
806 assert_eq!(reason, NETWORK_ACCOUNT);
807
808 db.execute(&network_available(&info)).unwrap();
809 let (state, reason) = query_state_and_reason(task_id);
810 assert_eq!(state, WAITING);
811 assert_eq!(reason, ACCOUNT_STOPPED);
812
813 // app + account
814 db.execute(&format!(
815 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_APP_ACCOUNT}, {CELLULAR}, 1, 1)"
816 )).unwrap();
817 db.execute(&app_state_available(uid)).unwrap();
818 db.execute(&account_available(&hash_set)).unwrap();
819 let (state, reason) = query_state_and_reason(task_id);
820 assert_eq!(state, WAITING);
821 assert_eq!(reason, NETWORK_OFFLINE);
822 }
823
824 #[test]
ut_multi_reason_unailable()825 fn ut_multi_reason_unailable() {
826 test_init();
827 let _lock = lock_database();
828 let db = RequestDb::get_instance();
829 let task_id = TaskIdGenerator::generate();
830 let uid = get_current_timestamp();
831 let hash_set = HashSet::new();
832 let info = NetworkInfo {
833 network_type: NetworkType::Wifi,
834 is_metered: true,
835 is_roaming: true,
836 };
837
838 // account + offline
839 db.execute(&format!(
840 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {ACCOUNT_STOPPED}, {CELLULAR}, 1, 1, {FRONTEND})"
841 )).unwrap();
842 db.execute(&network_offline()).unwrap();
843 let (state, reason) = query_state_and_reason(task_id);
844 assert_eq!(state, WAITING);
845 assert_eq!(reason, NETWORK_ACCOUNT);
846
847 // account + unsupported_network
848 db.execute(&format!(
849 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {ACCOUNT_STOPPED}, {CELLULAR}, 1, 1, {FRONTEND})"
850 )).unwrap();
851
852 db.execute(&network_unavailable(&info).unwrap()).unwrap();
853 let (state, reason) = query_state_and_reason(task_id);
854 assert_eq!(state, WAITING);
855 assert_eq!(reason, NETWORK_ACCOUNT);
856
857 // account + offline + app
858 db.execute(&format!(
859 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_ACCOUNT}, {CELLULAR}, 1, 1, {FRONTEND})"
860 )).unwrap();
861 db.execute(&app_state_unavailable(uid)).unwrap();
862 let (state, reason) = query_state_and_reason(task_id);
863 assert_eq!(state, WAITING);
864 assert_eq!(reason, NETWORK_APP_ACCOUNT);
865
866 // account + app
867 db.execute(&format!(
868 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {ACCOUNT_STOPPED}, {CELLULAR}, 1, 1, {FRONTEND})"
869 )).unwrap();
870 db.execute(&app_state_unavailable(uid)).unwrap();
871 let (state, reason) = query_state_and_reason(task_id);
872 assert_eq!(state, WAITING);
873 assert_eq!(reason, APP_ACCOUNT);
874
875 // account + app + offline
876 db.execute(&format!(
877 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {APP_ACCOUNT}, {CELLULAR}, 1, 1, {FRONTEND})"
878 )).unwrap();
879 db.execute(&network_offline()).unwrap();
880 let (state, reason) = query_state_and_reason(task_id);
881 assert_eq!(state, WAITING);
882 assert_eq!(reason, NETWORK_APP_ACCOUNT);
883
884 // account + app + unsupported_network
885 db.execute(&format!(
886 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {APP_ACCOUNT}, {CELLULAR}, 1, 1, {FRONTEND})"
887 )).unwrap();
888 db.execute(&network_unavailable(&info).unwrap()).unwrap();
889 let (state, reason) = query_state_and_reason(task_id);
890 assert_eq!(state, WAITING);
891 assert_eq!(reason, NETWORK_APP_ACCOUNT);
892
893 // network + account
894 db.execute(&format!(
895 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_OFFLINE}, {CELLULAR}, 1, 1, {FRONTEND})"
896 )).unwrap();
897 db.execute(&account_unavailable(&hash_set)).unwrap();
898 let (state, reason) = query_state_and_reason(task_id);
899 assert_eq!(state, WAITING);
900 assert_eq!(reason, NETWORK_ACCOUNT);
901
902 // unsupported_network + account
903 db.execute(&format!(
904 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {UNSUPPORTED_NETWORK_TYPE}, {CELLULAR}, 1, 1, {FRONTEND})"
905 )).unwrap();
906 db.execute(&account_unavailable(&hash_set)).unwrap();
907 let (state, reason) = query_state_and_reason(task_id);
908 assert_eq!(state, WAITING);
909 assert_eq!(reason, NETWORK_ACCOUNT);
910
911 // network + account + app
912 db.execute(&format!(
913 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_ACCOUNT}, {CELLULAR}, 1, 1, {FRONTEND})"
914 )).unwrap();
915 db.execute(&app_state_unavailable(uid)).unwrap();
916 let (state, reason) = query_state_and_reason(task_id);
917 assert_eq!(state, WAITING);
918 assert_eq!(reason, NETWORK_APP_ACCOUNT);
919
920 // network + app
921 db.execute(&format!(
922 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_OFFLINE}, {CELLULAR}, 1, 1, {FRONTEND})"
923 )).unwrap();
924 db.execute(&app_state_unavailable(uid)).unwrap();
925 let (state, reason) = query_state_and_reason(task_id);
926 assert_eq!(state, WAITING);
927 assert_eq!(reason, NETWORK_APP);
928
929 // unsupported_network + app
930 db.execute(&format!(
931 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {UNSUPPORTED_NETWORK_TYPE}, {CELLULAR}, 1, 1, {FRONTEND})"
932 )).unwrap();
933 db.execute(&app_state_unavailable(uid)).unwrap();
934 let (state, reason) = query_state_and_reason(task_id);
935 assert_eq!(state, WAITING);
936 assert_eq!(reason, NETWORK_APP);
937
938 // network + app + account
939 db.execute(&format!(
940 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_APP}, {CELLULAR}, 1, 1, {FRONTEND})"
941 )).unwrap();
942 db.execute(&account_unavailable(&hash_set)).unwrap();
943 let (state, reason) = query_state_and_reason(task_id);
944 assert_eq!(state, WAITING);
945 assert_eq!(reason, NETWORK_APP_ACCOUNT);
946
947 // app + offline
948 db.execute(&format!(
949 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {APP_BACKGROUND_OR_TERMINATE}, {CELLULAR}, 1, 1, {FRONTEND})"
950 )).unwrap();
951 db.execute(&network_offline()).unwrap();
952 let (state, reason) = query_state_and_reason(task_id);
953 assert_eq!(state, WAITING);
954 assert_eq!(reason, NETWORK_APP);
955
956 // app + unsupported_network
957 db.execute(&format!(
958 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {APP_BACKGROUND_OR_TERMINATE}, {CELLULAR}, 1, 1, {FRONTEND})"
959 )).unwrap();
960 db.execute(&network_unavailable(&info).unwrap()).unwrap();
961 let (state, reason) = query_state_and_reason(task_id);
962 assert_eq!(state, WAITING);
963 assert_eq!(reason, NETWORK_APP);
964
965 // app + network + account
966 db.execute(&format!(
967 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {NETWORK_APP}, {CELLULAR}, 1, 1, {FRONTEND})"
968 )).unwrap();
969 db.execute(&account_unavailable(&hash_set)).unwrap();
970 let (state, reason) = query_state_and_reason(task_id);
971 assert_eq!(state, WAITING);
972 assert_eq!(reason, NETWORK_APP_ACCOUNT);
973
974 // app + account
975 db.execute(&format!(
976 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {APP_BACKGROUND_OR_TERMINATE}, {CELLULAR}, 1, 1, {FRONTEND})"
977 )).unwrap();
978 db.execute(&account_unavailable(&hash_set)).unwrap();
979 let (state, reason) = query_state_and_reason(task_id);
980 assert_eq!(state, WAITING);
981 assert_eq!(reason, APP_ACCOUNT);
982
983 // app + account + offline
984 db.execute(&format!(
985 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {APP_ACCOUNT}, {CELLULAR}, 1, 1, {FRONTEND})"
986 )).unwrap();
987 db.execute(&network_offline()).unwrap();
988 let (state, reason) = query_state_and_reason(task_id);
989 assert_eq!(state, WAITING);
990 assert_eq!(reason, NETWORK_APP_ACCOUNT);
991
992 // app + account + unsupported_network
993 db.execute(&format!(
994 "INSERT OR REPLACE INTO request_task (task_id, uid, state, reason, network, metered, roaming, mode) VALUES ({task_id}, {uid}, {WAITING}, {APP_ACCOUNT}, {CELLULAR}, 1, 1, {FRONTEND})"
995 )).unwrap();
996 db.execute(&network_unavailable(&info).unwrap()).unwrap();
997 let (state, reason) = query_state_and_reason(task_id);
998 assert_eq!(state, WAITING);
999 assert_eq!(reason, NETWORK_APP_ACCOUNT);
1000 }
1001 }
1002