// Copyright (C) 2024 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::Arc;
use std::time::Duration;
use ylong_http_client::Headers;
use ylong_runtime::net::UnixDatagram;
use ylong_runtime::sync::oneshot;
use crate::service::client::manager::ClientManager;
use crate::service::client::{Client, ClientEvent, ClientManagerEntry};
use crate::task::notify::{NotifyData, SubscribeType, WaitingCause};
use crate::task::reason::Reason;
use crate::config::Version;
#[cfg(test)]
mod tests {
use super::*;
// @tc.name: ut_client_manager_entry_new
// @tc.desc: Test creating a new ClientManagerEntry instance
// @tc.precon: NA
// @tc.step: 1. Create an unbounded channel
// 2. Create ClientManagerEntry with the sender
// @tc.expect: ClientManagerEntry is created successfully with correct sender
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 0
#[test]
fn ut_client_manager_entry_new_001() {
let (tx, _rx) = ylong_runtime::sync::mpsc::unbounded_channel();
let entry = ClientManagerEntry::new(tx.clone());
assert!(entry.send_event(ClientEvent::TaskFinished(1)));
}
// @tc.name: ut_client_manager_entry_send_event_success
// @tc.desc: Test successful event sending through ClientManagerEntry
// @tc.precon: Valid unbounded channel exists
// @tc.step: 1. Create ClientManagerEntry
// 2. Send a valid ClientEvent
// @tc.expect: send_event returns true
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 1
#[test]
fn ut_client_manager_entry_send_event_success_001() {
let (tx, rx) = ylong_runtime::sync::mpsc::unbounded_channel();
let entry = ClientManagerEntry::new(tx);
let result = entry.send_event(ClientEvent::TaskFinished(42));
assert_eq!(result, true);
// Verify event was received
let received = rx.try_recv();
assert!(received.is_ok());
match received.unwrap() {
ClientEvent::TaskFinished(tid) => assert_eq!(tid, 42),
_ => panic!("Unexpected event type"),
}
}
// @tc.name: ut_client_manager_entry_send_event_failure
// @tc.desc: Test event sending failure when channel is closed
// @tc.precon: Channel receiver is dropped
// @tc.step: 1. Create ClientManagerEntry
// 2. Drop the receiver
// 3. Attempt to send an event
// @tc.expect: send_event returns false
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 2
#[test]
fn ut_client_manager_entry_send_event_failure_001() {
let (tx, rx) = ylong_runtime::sync::mpsc::unbounded_channel();
let entry = ClientManagerEntry::new(tx);
// Drop the receiver to simulate channel closure
drop(rx);
let result = entry.send_event(ClientEvent::TaskFinished(42));
assert_eq!(result, false);
}
// @tc.name: ut_client_manager_init
// @tc.desc: Test ClientManager initialization
// @tc.precon: Runtime is available
// @tc.step: 1. Call ClientManager::init()
// 2. Verify ClientManagerEntry is returned
// @tc.expect: ClientManagerEntry is created successfully
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 0
#[test]
fn ut_client_manager_init_001() {
let entry = ClientManager::init();
assert!(entry.send_event(ClientEvent::TaskFinished(1)));
}
// @tc.name: ut_client_constructor_success
// @tc.desc: Test successful Client construction
// @tc.precon: Unix datagram socket creation is available
// @tc.step: 1. Call Client::constructor with valid pid
// 2. Verify the return value
// @tc.expect: Returns Some with sender and socket
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 1
#[test]
fn ut_client_constructor_success_001() {
let result = Client::constructor(12345);
assert!(result.is_some());
let (sender, socket) = result.unwrap();
assert!(sender.send(ClientEvent::TaskFinished(1)).is_ok());
assert!(Arc::strong_count(&socket) >= 1);
}
// @tc.name: ut_client_constructor_zero_pid
// @tc.desc: Test Client construction with zero pid
// @tc.precon: Unix datagram socket creation is available
// @tc.step: 1. Call Client::constructor with pid=0
// 2. Verify the return value
// @tc.expect: Returns Some with sender and socket
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 2
#[test]
fn ut_client_constructor_zero_pid_001() {
let result = Client::constructor(0);
assert!(result.is_some());
let (sender, socket) = result.unwrap();
assert!(sender.send(ClientEvent::TaskFinished(1)).is_ok());
assert!(Arc::strong_count(&socket) >= 1);
}
// @tc.name: ut_client_constructor_max_pid
// @tc.desc: Test Client construction with maximum u64 pid
// @tc.precon: Unix datagram socket creation is available
// @tc.step: 1. Call Client::constructor with pid=u64::MAX
// 2. Verify the return value
// @tc.expect: Returns Some with sender and socket
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 2
#[test]
fn ut_client_constructor_max_pid_001() {
let result = Client::constructor(u64::MAX);
assert!(result.is_some());
let (sender, socket) = result.unwrap();
assert!(sender.send(ClientEvent::TaskFinished(1)).is_ok());
assert!(Arc::strong_count(&socket) >= 1);
}
// Integration tests for ClientManagerEntry methods
mod integration_tests {
use super::*;
use ylong_runtime::sync::oneshot;
// @tc.name: ut_client_manager_entry_open_channel_integration
// @tc.desc: Test open_channel method integration
// @tc.precon: ClientManager is initialized
// @tc.step: 1. Initialize ClientManager
// 2. Call open_channel with valid pid
// 3. Verify the result
// @tc.expect: Returns Ok with UnixDatagram
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 1
#[ylong_runtime::test]
async fn ut_client_manager_entry_open_channel_integration_001() {
let entry = ClientManager::init();
let result = entry.open_channel(12345);
assert!(result.is_ok());
let socket = result.unwrap();
assert!(Arc::strong_count(&socket) >= 1);
}
// @tc.name: ut_client_manager_entry_subscribe_integration
// @tc.desc: Test subscribe method integration
// @tc.precon: ClientManager is initialized and channel is open
// @tc.step: 1. Initialize ClientManager
// 2. Open channel for pid
// 3. Subscribe to task
// @tc.expect: Returns ErrorCode::ErrOk
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 1
#[ylong_runtime::test]
async fn ut_client_manager_entry_subscribe_integration_001() {
let entry = ClientManager::init();
let pid = 12345;
let tid = 1;
let uid = 1000;
let token_id = 2000;
// First open channel
let _ = entry.open_channel(pid).unwrap();
// Then subscribe
let result = entry.subscribe(tid, pid, uid, token_id);
assert_eq!(result, ErrorCode::ErrOk);
}
// @tc.name: ut_client_manager_entry_subscribe_no_channel
// @tc.desc: Test subscribe without opening channel first
// @tc.precon: ClientManager is initialized
// @tc.step: 1. Initialize ClientManager
// 2. Attempt to subscribe without opening channel
// @tc.expect: Returns ErrorCode::ChannelNotOpen
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 2
#[ylong_runtime::test]
async fn ut_client_manager_entry_subscribe_no_channel_001() {
let entry = ClientManager::init();
let pid = 12345;
let tid = 1;
let uid = 1000;
let token_id = 2000;
// Attempt to subscribe without opening channel
let result = entry.subscribe(tid, pid, uid, token_id);
assert_eq!(result, ErrorCode::ChannelNotOpen);
}
// @tc.name: ut_client_manager_entry_unsubscribe_integration
// @tc.desc: Test unsubscribe method integration
// @tc.precon: ClientManager is initialized and subscription exists
// @tc.step: 1. Initialize ClientManager
// 2. Open channel and subscribe
// 3. Unsubscribe from task
// @tc.expect: Returns ErrorCode::ErrOk
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 1
#[ylong_runtime::test]
async fn ut_client_manager_entry_unsubscribe_integration_001() {
let entry = ClientManager::init();
let pid = 12345;
let tid = 1;
let uid = 1000;
let token_id = 2000;
// Open channel and subscribe
let _ = entry.open_channel(pid).unwrap();
let _ = entry.subscribe(tid, pid, uid, token_id);
// Then unsubscribe
let result = entry.unsubscribe(tid);
assert_eq!(result, ErrorCode::ErrOk);
}
// @tc.name: ut_client_manager_entry_unsubscribe_nonexistent
// @tc.desc: Test unsubscribe for non-existent task
// @tc.precon: ClientManager is initialized
// @tc.step: 1. Initialize ClientManager
// 2. Attempt to unsubscribe from non-existent task
// @tc.expect: Returns ErrorCode::Other
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 2
#[ylong_runtime::test]
async fn ut_client_manager_entry_unsubscribe_nonexistent_001() {
let entry = ClientManager::init();
let tid = 99999;
// Attempt to unsubscribe from non-existent task
let result = entry.unsubscribe(tid);
assert_eq!(result, ErrorCode::Other);
}
// @tc.name: ut_client_manager_entry_notify_task_finished
// @tc.desc: Test notify_task_finished method
// @tc.precon: ClientManager is initialized
// @tc.step: 1. Initialize ClientManager
// 2. Call notify_task_finished with valid tid
// @tc.expect: Method completes without error
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 1
#[ylong_runtime::test]
async fn ut_client_manager_entry_notify_task_finished_001() {
let entry = ClientManager::init();
let tid = 42;
// This should complete without error
entry.notify_task_finished(tid);
}
// @tc.name: ut_client_manager_entry_notify_process_terminate
// @tc.desc: Test notify_process_terminate method
// @tc.precon: ClientManager is initialized and process exists
// @tc.step: 1. Initialize ClientManager
// 2. Open channel for process
// 3. Terminate the process
// @tc.expect: Returns ErrorCode::ErrOk
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 1
#[ylong_runtime::test]
async fn ut_client_manager_entry_notify_process_terminate_001() {
let entry = ClientManager::init();
let pid = 12345;
// Open channel first
let _ = entry.open_channel(pid).unwrap();
// Then terminate
let result = entry.notify_process_terminate(pid);
assert_eq!(result, ErrorCode::ErrOk);
}
// @tc.name: ut_client_manager_entry_notify_process_terminate_nonexistent
// @tc.desc: Test notify_process_terminate for non-existent process
// @tc.precon: ClientManager is initialized
// @tc.step: 1. Initialize ClientManager
// 2. Attempt to terminate non-existent process
// @tc.expect: Returns ErrorCode::ErrOk
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 2
#[ylong_runtime::test]
async fn ut_client_manager_entry_notify_process_terminate_nonexistent_001() {
let entry = ClientManager::init();
let pid = 99999;
// Attempt to terminate non-existent process
let result = entry.notify_process_terminate(pid);
assert_eq!(result, ErrorCode::ErrOk);
}
}
// Security tests
mod security_tests {
use super::*;
// @tc.name: ut_client_manager_memory_safety
// @tc.desc: Test memory safety during concurrent operations
// @tc.precon: Multiple threads accessing ClientManager
// @tc.step: 1. Initialize ClientManager
// 2. Spawn multiple threads to perform operations
// 3. Verify no memory issues
// @tc.expect: No crashes or memory corruption
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 3
#[ylong_runtime::test]
async fn ut_client_manager_memory_safety_001() {
let entry = ClientManager::init();
let mut handles = vec![];
for i in 0..100 {
let entry_clone = entry.clone();
let handle = ylong_runtime::spawn(async move {
let pid = 1000 + i;
let _ = entry_clone.open_channel(pid);
let _ = entry_clone.subscribe(i as u32, pid, 1000, 2000);
let _ = entry_clone.unsubscribe(i as u32);
let _ = entry_clone.notify_process_terminate(pid);
});
handles.push(handle);
}
for handle in handles {
let _ = handle.await;
}
// Test passes if no panics occurred
}
// @tc.name: ut_client_manager_zero_sized_payloads
// @tc.desc: Test handling of zero-sized payloads
// @tc.precon: ClientManager is initialized
// @tc.step: 1. Initialize ClientManager
// 2. Send events with zero-sized data
// @tc.expect: System handles gracefully
// @tc.type: FUNC
// @tc.require: issue#ICODTG
// @tc.level: Level 3
#[ylong_runtime::test]
async fn ut_client_manager_zero_sized_payloads_001() {
let entry = ClientManager::init();
let pid = 12345;
// Test with empty headers
let _ = entry.open_channel(pid);
let _ = entry.subscribe(1, pid, 1000, 2000);
let empty_headers = Headers::new();
entry.send_response(1, "HTTP/1.1".to_string(), 200, "OK".to_string(), empty_headers);
// Should not crash
}
}
}