Skip to content

Commit

Permalink
feat: add check graph cmd and integration tests
Browse files Browse the repository at this point in the history
feat: upload runtime only, ignore others (#93)

fix: no need to package src (#92)

feat: add a python script for auto update package versions according … (#85)

Co-authored-by: Hu Yueh-Wei <[email protected]>

docs: updating ten_agent_server from astra_agents_dev (#95)

* docs: updating ten_agent_server from astra_agents_dev

Updating ten_agent_server from astra_agents_dev

* docs: fixing typo

Fixing typo

fix: fix some integration test cases (#94)

feat: add cargo config auto-gen (#51)

Co-authored-by: Hu Yueh-Wei <[email protected]>

chore: update version and publish to cloud store automatically (#97)

Co-authored-by: Hu Yueh-Wei <[email protected]>

fix: forked repo can not get version since tag is not synced (#99)

doc: update summary part

feat: add linux/arm64 (#98)

Co-authored-by: Hu Yueh-Wei <[email protected]>

chore: update to latest ten_gn

chore: add more CI test cases (#136)

chore: enable more CI test cases (#137)

feat: add a python script to update "supports" in manifest (#138)

feat: add async extension in Python binding in order to use asyncio m… (#91)

Co-authored-by: Hu Yueh-Wei <[email protected]>

chore: disable auto-added supports field in GN build flow

fix: check the app in graph

fix: help message
  • Loading branch information
leoadonia authored and halajohn committed Oct 15, 2024
1 parent d674568 commit 33e1c38
Show file tree
Hide file tree
Showing 45 changed files with 1,150 additions and 134 deletions.
11 changes: 11 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,17 @@
"hello_world",
],
},
{
"name": "tman check_graph (lldb)",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/core/src/ten_manager/target/x86_64-unknown-linux-gnu/debug/tman",
"cwd": "${workspaceFolder}/core/src/ten_manager/",
"args": [
"check-graph",
"/home/workspace/pcm-pusher"
]
},
{
"name": "ten_rust (rust)",
"type": "lldb",
Expand Down
7 changes: 7 additions & 0 deletions core/src/ten_manager/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ declare_args() {
use_shared_lib = false
}

copy("ten_manager_test_data") {
sources = [ "//core/src/ten_manager/tests/test_data" ]
outputs = [ "${root_out_dir}/tests/standalone/ten_manager/tests/test_data" ]
}

if (ten_enable_package_manager) {
if (ten_package_manager_enable_tests) {
rust_test("tman_test") {
project_path = "//core/src/ten_manager"
integration_test_output_name = "integration_test"

clingo_lib_folder =
rebase_path("${root_out_dir}/gen/cmake/clingo/install/lib")
Expand All @@ -37,6 +43,7 @@ if (ten_enable_package_manager) {
test_output_dir = "${root_out_dir}/tests/standalone/ten_manager"

deps = [
":ten_manager_test_data",
"//core/src/ten_rust:ten_rust_static_lib",
"//third_party/clingo",
]
Expand Down
217 changes: 217 additions & 0 deletions core/src/ten_manager/src/cmd/cmd_check/cmd_check_graph.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
//
// Copyright © 2024 Agora
// This file is part of TEN Framework, an open source project.
// Licensed under the Apache License, Version 2.0, with certain conditions.
// Refer to the "LICENSE" file in the root directory for more information.
//

use std::{collections::HashMap, fs, path};

use anyhow::{Context, Result};
use clap::{Arg, ArgMatches, Command};
use console::Emoji;
use ten_rust::pkg_info::{
default_app_loc, get_all_existed_pkgs_info_of_app, graph::Graph,
property::parse_property_in_folder, PkgInfo,
};

use crate::config::TmanConfig;

#[derive(Debug)]
pub struct CheckGraphCommand {
pub app: Vec<String>,
pub predefined_graph_name: Option<String>,
pub graph: Option<String>,
}

pub fn create_sub_cmd(_args_cfg: &crate::cmd_line::ArgsCfg) -> Command {
Command::new("graph")
.about(
"Check the predefined graph or start_graph cmd for the primary \
app. For more detailed usage, run 'graph -h'",
)
.arg(
Arg::new("APP")
.long("app")
.help(
"The absolute path of the app declared in the graph. By \
default, the predefined graph will be read from the first \
one in the list. ",
)
.required(true),
)
.arg(
Arg::new("PREDEFINED_GRAPH_NAME")
.long("predefined-graph-name")
.help(
"Specify the predefined graph name only to be checked, \
otherwise, all graphs will be checked.",
)
.required(false)
.conflicts_with("GRAPH"),
)
.arg(
Arg::new("GRAPH")
.long("graph")
.help(
"Specify the json string of a 'start_graph' cmd to be \
checked. If not specified, the predefined graph in the \
primary app will be checked.",
)
.required(false)
.conflicts_with("PREDEFINED_GRAPH_NAME"),
)
}

pub fn parse_sub_cmd(
_sub_cmd_args: &ArgMatches,
) -> crate::cmd::cmd_check::cmd_check_graph::CheckGraphCommand {
let cmd = CheckGraphCommand {
app: _sub_cmd_args
.get_many::<String>("APP")
.unwrap_or_default()
.map(|s| s.to_string())
.collect(),
predefined_graph_name: _sub_cmd_args
.get_one::<String>("PREDEFINED_GRAPH_NAME")
.cloned(),
graph: _sub_cmd_args.get_one::<String>("GRAPH").cloned(),
};

cmd
}

fn validate_cmd_args(command: &CheckGraphCommand) -> Result<()> {
for app in &command.app {
let stat = fs::metadata(app).with_context(|| {
format!("Failed to get metadata of app path [{}].", app)
})?;
if !stat.is_dir() {
return Err(anyhow::anyhow!(
"App path [{}] is not a directory.",
app
));
}
}

Ok(())
}

fn get_all_pkg_infos(
command: &CheckGraphCommand,
) -> Result<HashMap<String, Vec<PkgInfo>>> {
let mut pkgs_info: HashMap<String, Vec<PkgInfo>> = HashMap::new();

let single_app = command.app.len() == 1;

for app in &command.app {
let app_path = path::Path::new(app);

// TODO(Liu): Add a limitation in the schema to ensure that the 'uri' in
// the property.json is not 'localhost'.
let app_property = parse_property_in_folder(app_path)?;
let app_pkgs = get_all_existed_pkgs_info_of_app(app_path)?;

let app_uri = app_property.get_app_uri();
if !single_app && app_uri.as_str() == default_app_loc() {
return Err(anyhow::anyhow!(
"The app uri should be some string other than 'localhost' when
using in multi-apps graph."
));
}

let present_pkg = pkgs_info.insert(app_uri.clone(), app_pkgs);
if present_pkg.is_some() {
return Err(anyhow::anyhow!(
"All apps should have a unique uri, but uri [{}] is duplicated.",
app_uri
));
}
}

Ok(pkgs_info)
}

fn get_graphs_to_be_checked(command: &CheckGraphCommand) -> Result<Vec<Graph>> {
let mut graphs_to_be_checked: Vec<Graph> = Vec::new();

if let Some(graph_str) = &command.graph {
let graph: Graph = serde_json::from_str(graph_str)
.with_context(|| "The graph json string is invalid")?;
graphs_to_be_checked.push(graph);
} else {
let app_path = path::Path::new(&command.app[0]);
let app_property = parse_property_in_folder(app_path)?;
let predefined_graphs = app_property
._ten
.and_then(|p| p.predefined_graphs)
.ok_or_else(|| {
anyhow::anyhow!(
"No predefined graph is found in the primary app."
)
})?;

if let Some(predefined_graph_name) = &command.predefined_graph_name {
let predefined_graph = predefined_graphs
.iter()
.find(|g| g.name == predefined_graph_name.as_str())
.ok_or_else(|| {
anyhow::anyhow!(
"Predefined graph [{}] is not found.",
predefined_graph_name
)
})?;
graphs_to_be_checked.push(predefined_graph.graph.clone());
} else {
for predefined_graph in predefined_graphs {
graphs_to_be_checked.push(predefined_graph.graph.clone());
}
}
}

Ok(graphs_to_be_checked)
}

fn display_error(e: &anyhow::Error) {
e.to_string().lines().for_each(|l| {
println!(" {}", l);
});
}

pub async fn execute_cmd(
_tman_config: &TmanConfig,
command_data: CheckGraphCommand,
) -> Result<()> {
validate_cmd_args(&command_data)?;

let all_pkgs = get_all_pkg_infos(&command_data)?;
let graphs = get_graphs_to_be_checked(&command_data)?;

let mut err_count = 0;

for (graph_idx, graph) in graphs.iter().enumerate() {
print!("Checking graph[{}]... ", graph_idx);

match graph.check(&all_pkgs) {
Ok(_) => println!("{}", Emoji("✅", "Passed")),
Err(e) => {
err_count += 1;
println!("{}. Details:", Emoji("❌", "Failed"));
display_error(&e);
println!();
}
}
}

println!("All is done.");

if err_count > 0 {
Err(anyhow::anyhow!(
"{}/{} graphs failed.",
err_count,
graphs.len()
))
} else {
Ok(())
}
}
54 changes: 54 additions & 0 deletions core/src/ten_manager/src/cmd/cmd_check/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// Copyright © 2024 Agora
// This file is part of TEN Framework, an open source project.
// Licensed under the Apache License, Version 2.0, with certain conditions.
// Refer to the "LICENSE" file in the root directory for more information.
//
pub mod cmd_check_graph;

use anyhow::Result;
use clap::{ArgMatches, Command};

use crate::config::TmanConfig;

#[derive(Debug)]
pub enum CheckCommandData {
CheckGraph(crate::cmd::cmd_check::cmd_check_graph::CheckGraphCommand),
}

pub fn create_sub_cmd(args_cfg: &crate::cmd_line::ArgsCfg) -> Command {
Command::new("check")
.about("Check cmd group. For more detailed usage, run 'check -h'")
.subcommand_required(true)
.arg_required_else_help(true)
.subcommand(crate::cmd::cmd_check::cmd_check_graph::create_sub_cmd(
args_cfg,
))
}

pub fn parse_sub_cmd(sub_cmd_args: &ArgMatches) -> CheckCommandData {
match sub_cmd_args.subcommand() {
Some(("graph", graph_cmd_args)) => CheckCommandData::CheckGraph(
crate::cmd::cmd_check::cmd_check_graph::parse_sub_cmd(
graph_cmd_args,
),
),

_ => unreachable!("Command not found"),
}
}

pub async fn execute_cmd(
tman_config: &TmanConfig,
command_data: CheckCommandData,
) -> Result<()> {
match command_data {
CheckCommandData::CheckGraph(cmd) => {
crate::cmd::cmd_check::cmd_check_graph::execute_cmd(
tman_config,
cmd,
)
.await
}
}
}
5 changes: 5 additions & 0 deletions core/src/ten_manager/src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// Licensed under the Apache License, Version 2.0, with certain conditions.
// Refer to the "LICENSE" file in the root directory for more information.
//
pub mod cmd_check;
pub mod cmd_delete;
pub mod cmd_dev_server;
pub mod cmd_install;
Expand All @@ -22,6 +23,7 @@ pub enum CommandData {
Publish(self::cmd_publish::PublishCommand),
Delete(self::cmd_delete::DeleteCommand),
DevServer(self::cmd_dev_server::DevServerCommand),
Check(self::cmd_check::CheckCommandData),
}

pub async fn execute_cmd(
Expand All @@ -47,5 +49,8 @@ pub async fn execute_cmd(
CommandData::DevServer(cmd) => {
crate::cmd::cmd_dev_server::execute_cmd(tman_config, cmd).await
}
CommandData::Check(cmd) => {
crate::cmd::cmd_check::execute_cmd(tman_config, cmd).await
}
}
}
4 changes: 4 additions & 0 deletions core/src/ten_manager/src/cmd_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ fn create_cmd() -> clap::ArgMatches {
.subcommand(crate::cmd::cmd_publish::create_sub_cmd(&args_cfg))
.subcommand(crate::cmd::cmd_delete::create_sub_cmd(&args_cfg))
.subcommand(crate::cmd::cmd_dev_server::create_sub_cmd(&args_cfg))
.subcommand(crate::cmd::cmd_check::create_sub_cmd(&args_cfg))
.get_matches()
}

Expand Down Expand Up @@ -139,6 +140,9 @@ pub fn parse_cmd(
crate::cmd::cmd_dev_server::parse_sub_cmd(sub_cmd_args),
)
}
Some(("check", sub_cmd_args)) => crate::cmd::CommandData::Check(
crate::cmd::cmd_check::parse_sub_cmd(sub_cmd_args),
),
_ => unreachable!("Command not found"),
}
}
4 changes: 2 additions & 2 deletions core/src/ten_manager/src/dev_server/graphs/connections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub struct DevServerConnection {
impl From<GraphConnection> for DevServerConnection {
fn from(conn: GraphConnection) -> Self {
DevServerConnection {
app: conn.app,
app: conn.get_app_uri().to_string(),
extension_group: conn.extension_group,
extension: conn.extension,

Expand Down Expand Up @@ -94,7 +94,7 @@ pub struct DevServerDestination {
impl From<GraphDestination> for DevServerDestination {
fn from(destination: GraphDestination) -> Self {
DevServerDestination {
app: destination.app,
app: destination.get_app_uri().to_string(),
extension_group: destination.extension_group,
extension: destination.extension,
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/ten_manager/src/dev_server/graphs/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ pub async fn get_graph_nodes(
addon: extension.addon.clone(),
name: extension.name.clone(),
extension_group: extension.extension_group.clone().unwrap(),
app: extension.app.clone(),
app: extension.app.as_ref().unwrap().clone(),
api: pkg_info.api.as_ref().map(|api| DevServerApi {
property: if api.property.is_empty() {
None
Expand Down
2 changes: 1 addition & 1 deletion core/src/ten_manager/src/dev_server/messages/compatible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub struct DevServerCompatibleMsg {
impl From<CompatibleExtensionAndMsg<'_>> for DevServerCompatibleMsg {
fn from(compatible: CompatibleExtensionAndMsg) -> Self {
DevServerCompatibleMsg {
app: compatible.extension.app.clone(),
app: compatible.extension.app.as_ref().unwrap().clone(),
extension_group: compatible
.extension
.extension_group
Expand Down
Loading

0 comments on commit 33e1c38

Please sign in to comment.