From e1681379095403b932da2f6898fc17092272a0d8 Mon Sep 17 00:00:00 2001 From: Vasanth kumar Kalaiselvan Date: Mon, 1 Jan 2024 15:06:52 +0530 Subject: [PATCH 1/2] Removed the unused code for the service --- crates/services/api-old/Cargo.toml | 60 ----- crates/services/api-old/src/bootstrap.rs | 76 ------- crates/services/api-old/src/error.rs | 95 -------- crates/services/api-old/src/main.rs | 24 -- .../services/api-old/src/route/app/action.rs | 112 --------- crates/services/api-old/src/route/app/case.rs | 215 ------------------ .../api-old/src/route/app/datatable.rs | 172 -------------- .../services/api-old/src/route/app/group.rs | 114 ---------- crates/services/api-old/src/route/app/mod.rs | 76 ------- .../api-old/src/route/app/object_repo.rs | 0 .../services/api-old/src/route/app/profile.rs | 119 ---------- crates/services/api-old/src/route/app/suit.rs | 166 -------------- crates/services/api-old/src/route/file.rs | 71 ------ crates/services/api-old/src/route/mod.rs | 25 -- crates/services/api-old/src/route/ws.rs | 84 ------- .../api-old/src/server/context/mod.rs | 1 - .../api-old/src/server/context/request.rs | 71 ------ .../api-old/src/server/middleware/mod.rs | 1 - .../api-old/src/server/middleware/request.rs | 95 -------- crates/services/api-old/src/server/mod.rs | 2 - .../services/api-old/src/utils/client/mod.rs | 7 - crates/services/api-old/src/utils/config.rs | 56 ----- crates/services/api-old/src/utils/mod.rs | 20 -- crates/services/api-old/tests/mod.rs | 1 - crates/services/api-old/tests/seed_data.rs | 151 ------------ 25 files changed, 1814 deletions(-) delete mode 100644 crates/services/api-old/Cargo.toml delete mode 100644 crates/services/api-old/src/bootstrap.rs delete mode 100644 crates/services/api-old/src/error.rs delete mode 100644 crates/services/api-old/src/main.rs delete mode 100644 crates/services/api-old/src/route/app/action.rs delete mode 100644 crates/services/api-old/src/route/app/case.rs delete mode 100644 crates/services/api-old/src/route/app/datatable.rs delete mode 100644 crates/services/api-old/src/route/app/group.rs delete mode 100644 crates/services/api-old/src/route/app/mod.rs delete mode 100644 crates/services/api-old/src/route/app/object_repo.rs delete mode 100644 crates/services/api-old/src/route/app/profile.rs delete mode 100644 crates/services/api-old/src/route/app/suit.rs delete mode 100644 crates/services/api-old/src/route/file.rs delete mode 100644 crates/services/api-old/src/route/mod.rs delete mode 100644 crates/services/api-old/src/route/ws.rs delete mode 100644 crates/services/api-old/src/server/context/mod.rs delete mode 100644 crates/services/api-old/src/server/context/request.rs delete mode 100644 crates/services/api-old/src/server/middleware/mod.rs delete mode 100644 crates/services/api-old/src/server/middleware/request.rs delete mode 100644 crates/services/api-old/src/server/mod.rs delete mode 100644 crates/services/api-old/src/utils/client/mod.rs delete mode 100644 crates/services/api-old/src/utils/config.rs delete mode 100644 crates/services/api-old/src/utils/mod.rs delete mode 100644 crates/services/api-old/tests/mod.rs delete mode 100644 crates/services/api-old/tests/seed_data.rs diff --git a/crates/services/api-old/Cargo.toml b/crates/services/api-old/Cargo.toml deleted file mode 100644 index 2e1c180..0000000 --- a/crates/services/api-old/Cargo.toml +++ /dev/null @@ -1,60 +0,0 @@ -[package] -name = "api" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license.workspace = true -documentation.workspace = true -homepage.workspace = true -repository.workspace = true -rust-version.workspace = true - - -[[bin]] -name = "apiold" -path = "src/main.rs" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -http = "0.2.8" -jsonwebtoken = "8" -thiserror = "1.0.31" -log = "0.4.16" -env_logger = "0.10.0" -clap = "4.0.32" -actix = "0.13.0" -actix-http = "3.0.4" -actix-web = { version = "4.2.1", features = ["openssl"] } -actix-web-actors = "4.1.0" -lazy_static = "1.4.0" -dotenv = "0.15.0" -chrono = "0.4.23" -tokio = "1.23.0" -async_once = "0.2.6" -serde = { version = "1.0.147", features = ["derive"] } -serde_json = "1.0.87" -openssl = { version = "0.10", features = ["v110"] } -futures = { version = "^0.3" } -futures-util = { version = "^0.3" } - -sea-orm = { version = "0.10.7", default-features = true, features = [ - "macros", - "debug-print", - "runtime-async-std-native-tls", - "sqlx-postgres", -] } - - -cerium = { workspace=true } -migration = { workspace=true } -entity = { workspace=true } -engine = { workspace=true } - - -[dev-dependencies] -rust_decimal = "1.14.3" -tokio = { version = "1.0", features = ["full"] } -cross-test = "0.1.6" -futures = "0.3" -dotenv = "0.15.0" diff --git a/crates/services/api-old/src/bootstrap.rs b/crates/services/api-old/src/bootstrap.rs deleted file mode 100644 index 8ffc269..0000000 --- a/crates/services/api-old/src/bootstrap.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! migration module will controller the Migration of application -//! automatically on beginning of application startup -//! - -use std::io::Write; - -use actix_web::{App, HttpServer, web}; -use actix_web::middleware::{Compress, Logger}; -use chrono::Local; -use dotenv::dotenv; -use env_logger::Builder; -use env_logger::fmt::Color; -use log::LevelFilter; -use sea_orm::DbErr; - -use migration::MigratorTrait; - -use crate::route; -use crate::route::ws::ws_init; -use crate::server::middleware::request::RequestHandler; -use crate::utils::config::CONFIG; - -/// init_logger - function will initialize log Handler for the application -pub(crate) fn init_logger() { - dotenv().ok(); - Builder::new() - .format(|buf, record| { - let mut timestamp_style = buf.style(); - timestamp_style.set_color(Color::Magenta); - - let mut level_style = buf.style(); - level_style.set_color(Color::Red); - writeln!(buf, - "[{} {}] {} >>> {}", - timestamp_style.value(Local::now().format("%d-%m-%Y %H:%M:%S")), - level_style.value(record.level()), - record.module_path_static().unwrap_or(""), - record.args() - ) - }) - .filter_level(LevelFilter::Debug) - .init(); - // env_logger::init(); -} - -pub(crate) async fn run_migration() -> Result<(), DbErr> { - migration::Migrator::up(&CONFIG.get().await.db_client, None).await?; - Ok(()) -} - -/// run_app_server - will kick start the Application server -/// that will navigate all the rest request for Application -pub(crate) async fn run_app_server() -> std::io::Result<()> { - // let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - // builder - // .set_private_key_file("key.pem", SslFiletype::PEM) - // .unwrap(); - // builder.set_certificate_chain_file("cert.pem").unwrap(); - HttpServer::new(move || { - App::new() - .app_data(web::JsonConfig::default().limit(4096)) - .wrap(Logger::default()) - .wrap(Compress::default()) - .wrap(RequestHandler::default()) - .configure(route::general_config) - .service(web::resource("/ws").route(web::get().to(ws_init))) - .service( - web::scope("/api/v1") - .configure(route::app::app_config) - ) - }) - .workers(5) - .bind("127.0.0.1:10000")? - .run() - .await -} diff --git a/crates/services/api-old/src/error.rs b/crates/services/api-old/src/error.rs deleted file mode 100644 index 994eacf..0000000 --- a/crates/services/api-old/src/error.rs +++ /dev/null @@ -1,95 +0,0 @@ -use std::fmt; -use std::fmt::Formatter; - -use actix_web::{HttpResponse, ResponseError}; -use http::StatusCode; -use jsonwebtoken::errors::Error; -use serde::Serialize; -use thiserror::Error; - -pub type OrcaResult = Result; - -pub type InternalResult = Result; - -#[derive(Clone)] -pub struct ErrorResponse { - code: StatusCode, - error: String, - message: String, -} - -#[derive(Serialize)] -struct Response { - code: u16, - error: String, - message: String, -} - -impl ErrorResponse { - pub fn new(code: StatusCode, error: &str, message: String) -> Self { - Self { code, error: error.to_string(), message } - } -} - -/// OrcaError - will have all the error raised from Orca system -#[derive(Error, Debug)] -pub enum OrcaError { - /// Internal Error Core Error - #[error("json error: {0}")] - JsonError(#[from] serde_json::Error), - #[error("io error: {0}")] - IoError(#[from] std::io::Error), - #[error("DB error: {0}")] - DBError(#[from] sea_orm::DbErr), - #[error("JWT error: {0}")] - JWTError(#[from] Error), - #[error("You are forbidden to access requested file.")] - Forbidden, - #[error("Header ({0}) is not available.")] - HeaderNotFound(String), - - #[error("User Not found")] - UserNotFound(i32), - - // #[error("Unknown Internal Error - {0}")] - // Unknown(#[from] String) -} - -impl OrcaError { - pub fn decode(&self) -> ErrorResponse { - match self { - Self::HeaderNotFound(ref _a) => ErrorResponse::new(StatusCode::NOT_FOUND, "HeaderNotFound", self.to_string()), - - Self::JsonError(ref _a) => ErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, "NotFound", self.to_string()), - // Self::NotFound => ErrorResponse::new(StatusCode::OK, "NotFound", self.to_string()), - Self::Forbidden => ErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, "Unknown", self.to_string()), - Self::IoError(ref _a) => ErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, "Unknown", self.to_string()), - Self::DBError(ref _a) => ErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, "DBError", self.to_string()), - - Self::JWTError(ref _a) => ErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, "JWTError", self.to_string()), - - Self::UserNotFound(ref _a) => ErrorResponse::new(StatusCode::NOT_FOUND, "UserNotFound", self.to_string()), - _ => ErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, "Unknown", self.to_string()), - } - } - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_fmt(format_args!( - "An error occurred: \"{}\"", - self.to_string() - )) - } -} - -impl ResponseError for OrcaError { - - fn error_response(&self) -> HttpResponse { - let response = self.decode(); - let _status_code = response.clone().code; - let eresponse = Response{ - code: response.clone().code.as_u16(), - error: response.error, - message: response.message - }; - HttpResponse::build(_status_code).json(eresponse) - } -} diff --git a/crates/services/api-old/src/main.rs b/crates/services/api-old/src/main.rs deleted file mode 100644 index ffd7cb5..0000000 --- a/crates/services/api-old/src/main.rs +++ /dev/null @@ -1,24 +0,0 @@ -extern crate cerium; - -use log::info; - -use crate::bootstrap::{init_logger, run_app_server, run_migration}; - -pub(crate) mod bootstrap; -pub(crate) mod utils; -pub(crate) mod route; -pub(crate) mod server; -pub(crate) mod error; - - -#[actix_web::main] -async fn main() -> std::io::Result<()> { - - init_logger(); - info!("!!! Starting Orca Application v2 !!!"); - run_migration().await.expect("Failed to Migrating the Latest Version"); - info!("Exiting Migrating DDL Command "); - info!("Starting Application Server "); - run_app_server().await?; - Ok(()) -} diff --git a/crates/services/api-old/src/route/app/action.rs b/crates/services/api-old/src/route/app/action.rs deleted file mode 100644 index 2a64b31..0000000 --- a/crates/services/api-old/src/route/app/action.rs +++ /dev/null @@ -1,112 +0,0 @@ -use actix_web::{HttpResponse, web}; -use actix_web::web::Path; -use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, ModelTrait, QueryFilter, QueryOrder}; -use sea_orm::ActiveValue::Set; -use sea_orm::prelude::Uuid; - -use cerium::error::web::OrcaError; -use entity::test::ui::action::action; - -use crate::utils::config::CONFIG; - -/// action_config - this will register all the endpoint in ACTION route -pub fn action_config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/action") - .route("/batch/", web::post().to(batch_update_action)) - .route("/", web::get().to(get_action)) - .route("/", web::post().to(create_action)) - .route("/{action_id}/", web::put().to(update_action)) - .route("/{action_id}/", web::delete().to(delete_action)) - ); - -} - - -/// get_action - list all the Action Group in Specific Application in the Orca Application -async fn get_action(path: Path<(Uuid, Uuid)>) -> Result { - let (_, group_id) = path.into_inner(); - let actions = action::Entity::find().filter(action::Column::ActionGroupId.eq(group_id)) - .order_by_asc(action::Column::ExecutionOrder).all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(actions)) -} - - -/// create_action - this will create new Action Group in Application Application in Orca -async fn create_action(path: Path<(Uuid, Uuid)>, mut body: web::Json) -> Result { - let (_, group_id) = path.into_inner(); - body.id = Uuid::new_v4(); - body.action_group_id = group_id; - let app = body.clone().into_active_model(); - let result = app.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(result)) -} - -/// update_action - this will create new Application in Orca -async fn update_action(path: Path<(Uuid, Uuid, Uuid)>, body: web::Json) -> Result { - let (_, _, action_id) = path.into_inner(); - let action = action::Entity::find_by_id(action_id).one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(_action) = action { - let mut _action: action::ActiveModel = _action.into(); - _action.kind = Set(body.kind.to_owned()); - _action.description = Set(body.description.to_owned()); - _action.target_kind = Set(body.target_kind.to_owned()); - _action.target_value = Set(body.target_value.to_owned()); - _action.data_kind = Set(body.data_kind.to_owned()); - _action.data_value = Set(body.data_value.to_owned()); - _action.execution_order = Set(body.execution_order.to_owned()); - let _ = _action.save(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - return Ok(HttpResponse::NoContent().finish()); - } - Ok(HttpResponse::NoContent().finish()) -} - - - - -/// delete_action - this will delete Action for Action Group in Application in Orca -async fn delete_action(path: Path<(Uuid, Uuid, Uuid)>) -> Result { - let (_, _, action_id) = path.into_inner(); - let action_instance = action::Entity::find_by_id(action_id).one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(_action) = action_instance { - let action_obj: action::ActiveModel = _action.into(); - let action_order = action_obj.clone().execution_order.unwrap(); - action_obj.delete(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - let actions = action::Entity::find().filter(action::Column::ExecutionOrder.gt(action_order)).all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - let actions: Vec = actions.into_iter().map(|mut x| { - x.execution_order = x.execution_order + 1; - x.into_active_model() - }).collect(); - action::Entity::insert_many(actions).exec(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - return Ok(HttpResponse::NoContent().finish()); - } - Ok(HttpResponse::NoContent().finish()) -} - - - -/// batch_update_action - This will update batch Action Group in Application in Orca -async fn batch_update_action(path: Path<(Uuid, Uuid)>, mut body: web::Json>) -> Result { - let (_, group_id) = path.into_inner(); - let db = &CONFIG.get().await.db_client; - - let actions : Vec = body.iter_mut().map(|item| { - item.id = Uuid::new_v4(); - item.action_group_id = group_id; - let _item = item.clone().into_active_model(); - // _item.save(db).await.expect("TODO: panic message"); - return _item; - }).collect(); - - for action in actions{ - action.save(db).await.expect("TODO: panic message"); - } - Ok(HttpResponse::NoContent().finish()) -} - - diff --git a/crates/services/api-old/src/route/app/case.rs b/crates/services/api-old/src/route/app/case.rs deleted file mode 100644 index b446b56..0000000 --- a/crates/services/api-old/src/route/app/case.rs +++ /dev/null @@ -1,215 +0,0 @@ -use std::str::FromStr; - -use actix_web::{HttpResponse, web}; -use actix_web::web::Path; -use futures_util::StreamExt; -use log::{debug, info}; -use sea_orm::{ActiveModelTrait, Condition, InsertResult, IntoActiveModel, QuerySelect}; -use sea_orm::ActiveValue::Set; -use sea_orm::ColumnTrait; -use sea_orm::EntityTrait; -use sea_orm::prelude::Uuid; -use sea_orm::QueryFilter; -use sea_orm::QueryOrder; -use serde::Deserialize; - -use engine::controller::case::CaseController; -use engine::server::driver::UIHelper; -use entity::{prelude::*}; - -use crate::error::OrcaError; -use crate::utils::config::CONFIG; - -#[derive(Debug, Deserialize)] -pub struct QueryParams { - pub index: Option, - pub parent: Option, -} - -/// profile_config - this will register all the endpoint in profile route -pub fn test_case_config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/case") - .route("/", web::get().to(get_cases)) - .route("/", web::post().to(create_case)) - .route("/{case_id}/detail/", web::get().to(get_case_info)) - .route("/{case_id}/batch/", web::post().to(batch_update_case_block)) - - .route("/{case_id}/block/{case_block_id}/", web::post().to(update_case_block)) - .route("/{case_id}/insert/", web::post().to(push_block)) - - .route("/{case_id}/run/", web::post().to(run)) - ); - -} - -/// list all the test cases in the Orca Application -async fn get_cases(path: Path) -> Result { - let app_id = path.into_inner(); - let _filter = Condition::all() - .add(case::Column::AppId.eq(app_id)); - let cases = case::Entity::find().filter(_filter) - .order_by_asc(case::Column::Name).all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(cases)) -} - -/// Create New test case -async fn create_case(path: Path, mut body: web::Json) -> Result { - let app_id = path.into_inner(); - body.id = Uuid::new_v4(); - body.app_id = app_id; - let _case = body.clone().into_active_model(); - let result = _case.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(result)) -} - -/// get_case_info - Get Case Info -async fn get_case_info(path: Path<(Uuid, Uuid)>) -> Result { - let (_, case_id) = path.into_inner(); - let cases = case::Entity::find_by_id(case_id) - .one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(mut case) = cases { - let _filter = Condition::all() - .add(case_block::Column::CaseId.eq(case_id)); - // let mut _case = case.into_active_model(); - let case_blocks = case_block::Entity::find().filter(_filter) - .order_by_asc(case_block::Column::ExecutionOrder).all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - case.case_execution = Some(serde_json::to_value(case_blocks).expect("TODO: panic message")); - return Ok(HttpResponse::Ok().json(case)); - }; - Ok(HttpResponse::NoContent().finish()) -} - -/// batch_update_case_block - update Case Block -async fn batch_update_case_block(path: Path<(Uuid, Uuid)>, mut body: web::Json>) -> Result { - let (_, case_id) = path.into_inner(); - let case_blocks : Vec = body.clone().into_iter().map(|mut block| { - block.case_id = case_id.clone(); - block.into_active_model() - }).collect(); - let blocks = case_block::Entity::insert_many(case_blocks) - .exec(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::NoContent().finish()) -} - -/// push_into_index - This will Append New Block to the code for spe -async fn push_into_index(path: Path<(Uuid, Uuid, i32)>, mut body: web::Json, param: web::Query) -> Result { - let (_, case_id, index) = path.into_inner(); - - let mut _filter = Condition::all() - .add(case_block::Column::CaseId.eq(case_id)); - if param.parent.is_some() { - _filter = _filter.add(case_block::Column::ParentId.eq(param.parent.unwrap())); - } - - let _index : i32 = match param.index { - Some(x) => x, - _ => { - let mut i = 1; - let blocks = case_block::Entity::find().filter(_filter.clone()) - .all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - if let Some(b) = blocks.last() { - i = b.execution_order + 1; - } - i - } - }; - _filter = _filter.add(case_block::Column::ExecutionOrder.gte(index)); - - - let blocks = case_block::Entity::find().filter(_filter) - .all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - for block in blocks { - let new_order = block.execution_order + 1; - let mut action_model = block.into_active_model(); - action_model.execution_order = Set(new_order); - action_model.save(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - } - body.id = Uuid::new_v4(); - body.case_id = case_id; - let _case = body.clone().into_active_model(); - debug!("{:?}", _case); - let result = _case.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - Ok(HttpResponse::NoContent().finish()) -} - - -/// push_block - This will Append New Block to the code for spe -async fn push_block(path: Path<(Uuid, Uuid)>, mut body: web::Json, param: web::Query) -> Result { - let (_, case_id) = path.into_inner(); - - let mut _filter = Condition::all() - .add(case_block::Column::CaseId.eq(case_id)); - if param.parent.is_some() { - _filter = _filter.add(case_block::Column::ParentId.eq(param.parent.unwrap())); - } - let blocks = case_block::Entity::find().filter(_filter.clone()) - .order_by_desc(case_block::Column::ExecutionOrder).limit(1) - .all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - let mut last_index = 1; - if let Some(b) = blocks.last() { - last_index = b.execution_order + 1; - } - let _index : i32 = match param.index { - Some(x) => { - let i = if x > last_index { last_index } else {x}; - i - }, - _ => last_index - }; - _filter = _filter.add(case_block::Column::ExecutionOrder.gte(_index)); - - - let blocks = case_block::Entity::find().filter(_filter) - .all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - for block in blocks { - let new_order = block.execution_order + 1; - let mut action_model = block.into_active_model(); - action_model.execution_order = Set(new_order); - action_model.save(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - } - body.id = Uuid::new_v4(); - body.case_id = case_id; - body.execution_order = _index; - let _case = body.clone().into_active_model(); - debug!("{:?}", _case); - let result = _case.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - Ok(HttpResponse::NoContent().finish()) -} - -/// update_case_block - this will update the single case block -async fn update_case_block(path: Path<(Uuid, Uuid, Uuid)>, body: web::Json) -> Result { - let (_, _, case_block_id) = path.into_inner(); - let case_block = case_block::Entity::find_by_id(case_block_id) - .one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(_case_block) = case_block { - let mut _block: case_block::ActiveModel = _case_block.into(); - _block.kind = Set(body.kind.to_owned()); - // _block.execution_order = Set(body.execution_order.to_owned()); - _block.type_field = Set(body.type_field.to_owned()); - _block.reference = Set(body.reference.to_owned()); - _block.parent_id = Set(body.parent_id.to_owned()); - let _ = _block.save(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - return Ok(HttpResponse::NoContent().finish()); - } - Ok(HttpResponse::NoContent().finish()) -} - -async fn run(path: Path<(Uuid, Uuid)>) -> Result { - let (_, case_id) = path.into_inner(); - let case = case::Entity::find_by_id(case_id) - .one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - - let ui_driver = UIHelper::default().await.expect("error"); - info!("got the driver"); - let controller = CaseController::new(&CONFIG.get().await.db_client, &ui_driver); - info!("got the controller"); - controller.process(&case.unwrap()).await.expect("error"); - ui_driver.driver.quit().await.expect("TODO: panic message"); - Ok(HttpResponse::NoContent().finish()) -} \ No newline at end of file diff --git a/crates/services/api-old/src/route/app/datatable.rs b/crates/services/api-old/src/route/app/datatable.rs deleted file mode 100644 index 46d5c8c..0000000 --- a/crates/services/api-old/src/route/app/datatable.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::fmt::format; -use std::time::SystemTime; -use actix_web::{HttpResponse, web}; -use actix_web::web::Path; -use chrono::Utc; -use log::{debug, info, log}; -use sea_orm::{ActiveModelTrait, ColumnTrait, ConnectionTrait, DatabaseBackend, DbBackend, EntityTrait, ExecResult, IntoActiveModel, JsonValue, ModelTrait, NotSet, QueryFilter, QueryOrder, QueryResult, Statement, TryGetableMany}; -use sea_orm::ActiveValue::Set; -use sea_orm::prelude::Uuid; - -use cerium::error::web::OrcaError; -use entity::test::ui::action::{action, datatable, field}; -use migration::Table; - -use crate::utils::config::CONFIG; -use crate::utils::replace_special_chars; - -/// datatable_config - this will register all the endpoint in Datatable route -pub fn datatable_config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/datatable") - .route("/", web::get().to(get_datatables)) - .route("/", web::post().to(create_datatable)) - .route("/{table_id}/", web::put().to(update_action)) - .route("/{table_id}/", web::delete().to(delete_action)) - .route("/{table_id}/field", web::post().to(create_new_field)) - .route("/{table_id}/data", web::get().to(get_dt_data)) - .route("/{table_id}/meta", web::get().to(get_datatable_meta)) - ); - -} - - - -async fn get_dt_meta(app_id: Uuid, dt_id: i32) -> Option { - let db = &CONFIG.get().await.db_client; - let table = datatable::Entity::find() - .filter(datatable::Column::AppId.eq(app_id)).filter(datatable::Column::Id.eq(dt_id)) - .one(db).await.expect("TODO: panic message"); - if table.is_none() { - return None; - } - let mut _table: datatable::Model = table.unwrap(); - let fields = _table.find_related(field::Entity) - .all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - _table.fields = Some(fields); - Some(_table) -} - -async fn create_new_field(path: Path<(Uuid, i32)>, mut body: web::Json) -> Result { - let (app_id, table_id) = path.into_inner(); - let db = &CONFIG.get().await.db_client; - body.table_id = table_id; - let mut field = body.clone().into_active_model(); - field.field_id = Set(replace_special_chars(field.name.clone().unwrap().as_str(), '_')); - let result = field.insert(db).await.expect("TODO: panic message"); - let tables = field::Entity::find().filter(datatable::Column::AppId.eq(app_id)) - .order_by_asc(datatable::Column::Name).all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(tables)) -} - -async fn get_dt_data(path: Path<(Uuid, i32)>) -> Result { - let (app_id, table_id) = path.into_inner(); - let db = &CONFIG.get().await.db_client; - let _table_meta = get_dt_meta(app_id, table_id).await; - if _table_meta.is_none() { - return Ok(HttpResponse::NotFound().finish()); - } - let _table = _table_meta.unwrap(); - // let query_res_vec: Vec = db - // .query_all(Statement::from_string(db.get_database_backend(), - // format!("SELECT * FROM `{}`;", _table.table_name.clone()).parse().unwrap(), - // )) - // .await.expect("TODO: panic message"); - // let unique: Vec = JsonValue::find_by_statement(Statement::from_string( - // DbBackend::Postgres, - // format!("SELECT * FROM `{}`;", _table.table_name.clone()) - // )) - // .all(db) - // .await.expect("TODO: panic message"); - Ok(HttpResponse::Ok().finish()) - // .json(unique)) -} - - -/// get_datatable - list all the DataTable in Specific Application in the Orca -async fn get_datatables(path: Path<(Uuid)>) -> Result { - let app_id = path.into_inner(); - let tables = datatable::Entity::find().filter(datatable::Column::AppId.eq(app_id)) - .order_by_asc(datatable::Column::Name).all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(tables)) -} - - -/// create_datatable - this will create new DataTable in Application in Orca -async fn create_datatable(path: Path<(Uuid)>, mut body: web::Json) -> Result { - let app_id = path.into_inner(); - let db = &CONFIG.get().await.db_client; - body.app_id = app_id; - let mut table = body.clone().into_active_model(); - table.id = NotSet; - table.table_name = Set(format!("table_{:?}", Utc::now().timestamp_micros())); - let result = table.insert(db).await.expect("TODO: panic message"); - // TODO: this code need to revamp since this is only work on postgres - let stm = format!(r#"CREATE TABLE IF NOT EXISTS {} (id SERIAL NOT NULL PRIMARY KEY )"#, result.table_name); - let exec_res: ExecResult = db.execute( - Statement::from_string(DatabaseBackend::Postgres, stm) - ).await.expect("TODO: panic message"); - info!("{:?}", exec_res.rows_affected()); - Ok(HttpResponse::Created().json(result)) -} - -/// update_action - this will create new Application in Orca -async fn update_action(path: Path<(Uuid, Uuid, Uuid)>, body: web::Json) -> Result { - let (_, _, action_id) = path.into_inner(); - let action = action::Entity::find_by_id(action_id).one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(_action) = action { - let mut _action: action::ActiveModel = _action.into(); - _action.kind = Set(body.kind.to_owned()); - _action.description = Set(body.description.to_owned()); - _action.target_kind = Set(body.target_kind.to_owned()); - _action.target_value = Set(body.target_value.to_owned()); - _action.data_kind = Set(body.data_kind.to_owned()); - _action.data_value = Set(body.data_value.to_owned()); - _action.execution_order = Set(body.execution_order.to_owned()); - let _ = _action.save(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - return Ok(HttpResponse::NoContent().finish()); - } - Ok(HttpResponse::NoContent().finish()) -} - - - - -/// delete_action - this will delete Action for Action Group in Application in Orca -async fn delete_action(path: Path<(Uuid, Uuid, Uuid)>) -> Result { - let (_, _, action_id) = path.into_inner(); - let action_instance = action::Entity::find_by_id(action_id).one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(_action) = action_instance { - let action_obj: action::ActiveModel = _action.into(); - let action_order = action_obj.clone().execution_order.unwrap(); - action_obj.delete(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - let actions = action::Entity::find().filter(action::Column::ExecutionOrder.gt(action_order)).all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - let actions: Vec = actions.into_iter().map(|mut x| { - x.execution_order = x.execution_order + 1; - x.into_active_model() - }).collect(); - action::Entity::insert_many(actions).exec(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - return Ok(HttpResponse::NoContent().finish()); - } - Ok(HttpResponse::NoContent().finish()) -} - - -/// get_datatable_meta - Get the DataTable Metadata -async fn get_datatable_meta(path: Path<(Uuid, i32)>) -> Result { - let (app_id, table_id) = path.into_inner(); - let dtable = get_dt_meta(app_id, table_id).await; - if dtable.is_none(){ - return Ok(HttpResponse::NotFound().finish()); - } - Ok(HttpResponse::Ok().json(dtable.unwrap())) -} - - diff --git a/crates/services/api-old/src/route/app/group.rs b/crates/services/api-old/src/route/app/group.rs deleted file mode 100644 index a7b0479..0000000 --- a/crates/services/api-old/src/route/app/group.rs +++ /dev/null @@ -1,114 +0,0 @@ -use actix_web::{HttpResponse, web}; -use actix_web::web::Path; -use sea_orm::{ActiveModelTrait, ColumnTrait, Condition, EntityTrait, IntoActiveModel, QueryFilter, QueryOrder}; -use sea_orm::ActiveValue::Set; -use sea_orm::prelude::Uuid; - -use cerium::error::web::OrcaError; -use entity::prelude::group; -use entity::prelude::group::ActionGroupKind; -use entity::test::ui::action::action as action_model; - -use crate::route::app::action; -use crate::utils::config::CONFIG; - -/// group_config - this will register all the endpoint in ACTION GROUP route -pub fn group_config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/group") - .route("/", web::get().to(get_groups)) - .route("/", web::post().to(create_group)) - .service( - web::scope("/{group_id}") - .route("/", web::put().to(update_group)) - .route("/", web::delete().to(delete_group)) - .configure(action::action_config) - ) - - ); - -} - - -/// get_groups - list all the Action Group in Specific Application in the Orca Application -async fn get_groups(path: Path) -> Result { - let app_id = path.into_inner(); - let _filter = Condition::all() - .add(group::Column::AppId.eq(app_id)) - .add(group::Column::TypeField.eq(ActionGroupKind::ActionGroup)); - let groups = group::Entity::find().filter(_filter) - .order_by_asc(group::Column::Name).all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(groups)) -} - - -/// create_group - This will create new Action Group in Application in Orca -async fn create_group(path: Path, mut body: web::Json) -> Result { - let app_id = path.into_inner(); - body.id = Uuid::new_v4(); - body.app_id = app_id; - let app = body.clone().into_active_model(); - let result = app.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(result)) -} - -/// update_action_group - this will create new Application in Orca -async fn update_group(path: Path<(Uuid, Uuid)>, body: web::Json) -> Result { - let (app_id, group_id) = path.into_inner(); - let group = group::Entity::find_by_id(group_id).one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(grp) = group { - let mut grp: group::ActiveModel = grp.into(); - grp.name = Set(body.name.to_owned()); - grp.description = Set(body.description.to_owned()); - let grp = grp.save(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - /// TODO: response is wrong status code - return Ok(HttpResponse::NoContent().finish()); - } - Ok(HttpResponse::NoContent().finish()) -} - -/// delete_action_group - this will delete Action Group in Application Application in Orca -async fn delete_group(path: Path<(Uuid, Uuid)>) -> Result { - let (app_id, group_id) = path.into_inner(); - let group = group::Entity::find_by_id(group_id).one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(grp) = group { - let grp: group::ActiveModel = grp.into(); - grp.delete(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - return Ok(HttpResponse::NoContent().finish()); - } - Ok(HttpResponse::NoContent().finish()) -} - - -/// batch_update_action - This will update batch Action Group in Application in Orca -async fn batch_update_action(path: Path<(Uuid, Uuid)>, mut body: web::Json>) -> Result { - let (_, group_id) = path.into_inner(); - let db = &CONFIG.get().await.db_client; - - let actions : Vec = body.iter_mut().map(|item| { - item.id = Uuid::new_v4(); - item.action_group_id = group_id; - let _item = item.clone().into_active_model(); - // _item.save(db).await.expect("TODO: panic message"); - return _item; - }).collect(); - - for action in actions{ - action.save(db).await.expect("TODO: panic message"); - } - - - // let group = group::Entity::find_by_id(group_id).one(&CONFIG.get().await.db_client).await - // .expect("TODO: panic message"); - // if let Some(grp) = group { - // let grp: group::ActiveModel = grp.into(); - // grp.delete(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - // return Ok(HttpResponse::NoContent().finish()); - // } - Ok(HttpResponse::NoContent().finish()) -} - - diff --git a/crates/services/api-old/src/route/app/mod.rs b/crates/services/api-old/src/route/app/mod.rs deleted file mode 100644 index d1448b9..0000000 --- a/crates/services/api-old/src/route/app/mod.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::error::Error; - -use actix_web::{HttpResponse, web}; -use sea_orm::{ActiveModelTrait, EntityTrait, IntoActiveModel, QueryOrder}; -use sea_orm::prelude::Uuid; - -use cerium::error::web::OrcaError; -use entity::app::app; - -use crate::utils::config::CONFIG; - -pub(crate) mod group; -pub(crate) mod action; -pub(crate) mod case; -pub(crate) mod suit; -pub(crate) mod profile; -pub(crate) mod object_repo; -pub(crate) mod datatable; - - -/// app_config - this will register all the endpoint in App route -pub fn app_config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/app") - .route("/", web::get().to(get_apps)) - .route("/", web::post().to(create_app)) - .service( - web::scope("/{app_id}") - .route("/", web::put().to(create_app)) - .configure(group::group_config) - .configure(case::test_case_config) - .configure(profile::profile_config) - .configure(suit::test_suit_config) - - .configure(datatable::datatable_config) - ) - ); - -} - - -/// list all the Application in the Orca Application -async fn get_apps() -> Result { - // let mut request_ctx = RequestContext::default(); - // let db = request_ctx.database(); - let cases = app::Entity::find().order_by_asc(app::Column::Name).all(&CONFIG.get().await.db_client).await; - let response = match cases { - Ok(_cases) => _cases, - Err(error) => panic!("Error while inserting: {:?}", error), - }; - Ok(HttpResponse::Ok().json(response)) -} - - -/// create_app - this will create new Application in Orca -async fn create_app(mut body: web::Json) -> Result { - // let mut request_ctx = RequestContext::default(); - // let db = request_ctx.database(); - body.id = Uuid::new_v4(); - let app = body.clone().into_active_model(); - let result = app.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(result)) -} - -/// create_app - this will create new Application in Orca -async fn update_app(mut body: web::Json) -> Result { - // let mut request_ctx = RequestContext::default(); - // let db = request_ctx.database(); - body.id = Uuid::new_v4(); - let app = body.clone().into_active_model(); - let result = app.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(result)) -} - - - diff --git a/crates/services/api-old/src/route/app/object_repo.rs b/crates/services/api-old/src/route/app/object_repo.rs deleted file mode 100644 index e69de29..0000000 diff --git a/crates/services/api-old/src/route/app/profile.rs b/crates/services/api-old/src/route/app/profile.rs deleted file mode 100644 index e55a81a..0000000 --- a/crates/services/api-old/src/route/app/profile.rs +++ /dev/null @@ -1,119 +0,0 @@ -use actix_web::{HttpResponse, web}; -use actix_web::web::Path; -use sea_orm::{ActiveModelTrait, ColumnTrait, Condition, EntityTrait, IntoActiveModel, QueryFilter, QueryOrder}; -use sea_orm::ActiveValue::Set; -use sea_orm::prelude::Uuid; - -use cerium::error::web::OrcaError; -use entity::test::ui::action::action as action_model; -use entity::test::ui::profile::{data as profile_data, profile}; - -use crate::route::app::action; -use crate::utils::config::CONFIG; - -/// profile_config - profile config will have all the endpoint to Handle the -/// profile and its data -pub fn profile_config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/profile") - .route("/", web::get().to(list_profile)) - .route("/", web::post().to(create_profile)) - .service( - web::scope("/{profile_id}") - .route("/", web::put().to(update_profile)) - .route("/", web::delete().to(delete_profile)) - .route("/data/batch/", web::post().to(update_profile)) - .route("/data/{data_id}/", web::delete().to(delete_profile_data)) - .configure(action::action_config) - ) - ); - -} - - -/// list_profile - list all the Profile that is Binded with Current Application -async fn list_profile(path: Path) -> Result { - let app_id = path.into_inner(); - let _filter = Condition::all() - .add(profile::Column::AppId.eq(app_id)); - let profiles = profile::Entity::find().filter(_filter) - .order_by_asc(profile::Column::Name).all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(profiles)) -} - - -/// create_profile - This will New Profile for the specific Application in Orca -async fn create_profile(path: Path, mut body: web::Json) -> Result { - let app_id = path.into_inner(); - body.id = Uuid::new_v4(); - body.app_id = app_id; - let _profile = body.clone().into_active_model(); - let result = _profile.insert(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(result)) -} - -/// update_profile - this will update the existing profile information in Orca -async fn update_profile(path: Path<(Uuid, Uuid)>, body: web::Json) -> Result { - let (app_id, profile_id) = path.into_inner(); - let _profile = profile::Entity::find_by_id(profile_id).one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(prf) = _profile { - let mut prf: profile::ActiveModel = prf.into(); - prf.name = Set(body.name.to_owned()); - prf.description = Set(body.description.to_owned()); - let _ = prf.save(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - /// TODO: response is wrong status code - return Ok(HttpResponse::NoContent().finish()); - } - Ok(HttpResponse::NoContent().finish()) -} - -/// delete_profile - this will delete existing profile in Application Application in Orca -async fn delete_profile(path: Path<(Uuid, Uuid)>) -> Result { - let (_, profile_id) = path.into_inner(); - let _profile = profile::Entity::delete_by_id(profile_id).exec(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::NoContent().finish()) -} - - -/// delete_profile_data - this will delete existing profile data in Application Application in Orca -async fn delete_profile_data(path: Path<(Uuid, Uuid, Uuid)>) -> Result { - let (_, profile_id, data_id) = path.into_inner(); - let _profile_data = profile_data::Entity::delete_by_id(data_id).exec(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::NoContent().finish()) -} - - -/// batch_update_action - This will update batch Action Group in Application in Orca -async fn batch_update_action(path: Path<(Uuid, Uuid)>, mut body: web::Json>) -> Result { - let (_, group_id) = path.into_inner(); - let db = &CONFIG.get().await.db_client; - - let actions : Vec = body.iter_mut().map(|item| { - item.id = Uuid::new_v4(); - item.action_group_id = group_id; - let _item = item.clone().into_active_model(); - // _item.save(db).await.expect("TODO: panic message"); - return _item; - }).collect(); - - for action in actions{ - action.save(db).await.expect("TODO: panic message"); - } - - - // let group = group::Entity::find_by_id(group_id).one(&CONFIG.get().await.db_client).await - // .expect("TODO: panic message"); - // if let Some(grp) = group { - // let grp: group::ActiveModel = grp.into(); - // grp.delete(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - // return Ok(HttpResponse::NoContent().finish()); - // } - Ok(HttpResponse::NoContent().finish()) -} - - diff --git a/crates/services/api-old/src/route/app/suit.rs b/crates/services/api-old/src/route/app/suit.rs deleted file mode 100644 index 4b253c0..0000000 --- a/crates/services/api-old/src/route/app/suit.rs +++ /dev/null @@ -1,166 +0,0 @@ -use actix_web::{HttpResponse, web}; -use actix_web::web::Path; -use log::debug; -use sea_orm::{ActiveModelTrait, ColumnTrait, Condition, EntityTrait, IntoActiveModel, QueryOrder, QuerySelect}; -use sea_orm::ActiveValue::Set; -use sea_orm::prelude::Uuid; -use entity::test::ui::suit::{suite, suite_block}; -use crate::error::OrcaError; -use crate::utils::config::CONFIG; -use sea_orm::QueryFilter; -use entity::{prelude::*}; -use crate::route::app::case::QueryParams; - -pub fn test_suit_config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/suite") - .route("/", web::get().to(get_suites)) - .route("/", web::post().to(create_suit)) - - .route("/{suite_id}/detail/", web::get().to(get_suite_info)) - .route("/{suite_id}/batch/", web::post().to(batch_update_suite_block)) - - // .route("/{suite_id}/block/{case_block_id}/", web::post().to(update_case_block)) - .route("/{suite_id}/insert/", web::post().to(push_block)) - // .route("/{suit_id}/detail/", web::get().to(get_case_info)) - ); - -} - -/// list all the test suites in the Orca Application -async fn get_suites(path: Path) -> Result { - let app_id = path.into_inner(); - let _filter = Condition::all() - .add(suite::Column::AppId.eq(app_id)); - let suites = suite::Entity::find().filter(_filter) - .order_by_asc(suite::Column::Name).all(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(suites)) -} - - -async fn create_suit(path: Path, mut body: web::Json) -> Result { - let app_id = path.into_inner(); - body.id = Uuid::new_v4(); - body.app_id = app_id; - let _case = body.clone().into_active_model(); - let result = _case.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - Ok(HttpResponse::Ok().json(result)) -} - - - -/// get_suits_info - Get Suite Info and the batch information with the list of block -async fn get_suite_info(path: Path<(Uuid, Uuid)>) -> Result { - let (_, suite_id) = path.into_inner(); - let suites = suite::Entity::find_by_id(suite_id) - .one(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - if let Some(mut suite) = suites { - let _filter = Condition::all() - .add(suite_block::Column::SuiteId.eq(suite_id)); - let suite_blocks = suite_block::Entity::find().filter(_filter) - .order_by_asc(suite_block::Column::ExecutionOrder).all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - suite.suite_execution = Some(serde_json::to_value(suite_blocks).expect("TODO: panic message")); - return Ok(HttpResponse::Ok().json(suite)); - }; - Ok(HttpResponse::NoContent().finish()) -} - -/// batch_update_suite_block - update suite Block -async fn batch_update_suite_block(path: Path<(Uuid, Uuid)>, mut body: web::Json>) -> Result { - let (_, suite_id) = path.into_inner(); - let suite_blocks : Vec = body.clone().into_iter().map(|mut block| { - block.suite_id = suite_id.clone(); - block.into_active_model() - }).collect(); - let blocks = suite_block::Entity::insert_many(suite_blocks) - .exec(&CONFIG.get().await.db_client).await - .expect("TODO: panic message"); - Ok(HttpResponse::NoContent().finish()) -} -// -// /// push_into_index - This will Append New Block to the code for spe -// async fn push_into_index(path: Path<(Uuid, Uuid, i32)>, mut body: web::Json, param: web::Query) -> Result { -// let (_, case_id, index) = path.into_inner(); -// -// let mut _filter = Condition::all() -// .add(case_block::Column::CaseId.eq(case_id)); -// if param.parent.is_some() { -// _filter = _filter.add(case_block::Column::ParentId.eq(param.parent.unwrap())); -// } -// -// let _index : i32 = match param.index { -// Some(x) => x, -// _ => { -// let mut i = 1; -// let blocks = case_block::Entity::find().filter(_filter.clone()) -// .all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); -// if let Some(b) = blocks.last() { -// i = b.execution_order + 1; -// } -// i -// } -// }; -// _filter = _filter.add(case_block::Column::ExecutionOrder.gte(index)); -// -// -// let blocks = case_block::Entity::find().filter(_filter) -// .all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); -// for block in blocks { -// let new_order = block.execution_order + 1; -// let mut action_model = block.into_active_model(); -// action_model.execution_order = Set(new_order); -// action_model.save(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); -// } -// body.id = Uuid::new_v4(); -// body.case_id = case_id; -// let _case = body.clone().into_active_model(); -// debug!("{:?}", _case); -// let result = _case.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); -// Ok(HttpResponse::NoContent().finish()) -// } - - -/// push_block - This will Append New Block to the code for spe -async fn push_block(path: Path<(Uuid, Uuid)>, mut body: web::Json, param: web::Query) -> Result { - let (_, suite_id) = path.into_inner(); - - let mut _filter = Condition::all() - .add(suite_block::Column::SuiteId.eq(suite_id)); - // if param.parent.is_some() { - // _filter = _filter.add(case_block::Column::ParentId.eq(param.parent.unwrap())); - // } - let blocks = suite_block::Entity::find().filter(_filter.clone()) - .order_by_desc(suite_block::Column::ExecutionOrder).limit(1) - .all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - let mut last_index = 1; - if let Some(b) = blocks.last() { - last_index = b.execution_order + 1; - } - let _index : i32 = match param.index { - Some(x) => { - let i = if x > last_index { last_index } else {x}; - i - }, - _ => last_index - }; - _filter = _filter.add(suite_block::Column::ExecutionOrder.gte(_index)); - - - let blocks = suite_block::Entity::find().filter(_filter) - .all(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - for block in blocks { - let new_order = block.execution_order + 1; - let mut action_model = block.into_active_model(); - action_model.execution_order = Set(new_order); - action_model.save(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - } - body.id = Uuid::new_v4(); - body.suite_id = suite_id; - body.execution_order = _index; - let _suite = body.clone().into_active_model(); - debug!("{:?}", _suite); - let result = _suite.insert(&CONFIG.get().await.db_client).await.expect("TODO: panic message"); - Ok(HttpResponse::NoContent().finish()) -} diff --git a/crates/services/api-old/src/route/file.rs b/crates/services/api-old/src/route/file.rs deleted file mode 100644 index f7b8943..0000000 --- a/crates/services/api-old/src/route/file.rs +++ /dev/null @@ -1,71 +0,0 @@ -use actix_http::error; -use actix_web::{HttpResponse, web}; -use actix_web::error::ErrorBadRequest; -use actix_web::web::Path; -use futures_util::StreamExt; -use sea_orm::prelude::Uuid; -use crate::error::OrcaError; - -const MAX_SIZE: usize = 262_144; // max payload size is 256k - -/// file_config - file config will have all the file management endpoint in the application -pub fn file_config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/file") - .route("/{attachment_id}/", web::get().to(get_file_with_attachment_id)) - .route("/", web::post().to(get_file_with_attachment_id)) - ); - -} - - -/// Returns a Response with File object the have been requested for -/// -/// # Arguments -/// * `path` - Path object from the Actix Endpoint that will hold the Identifier from the Request -async fn get_file_with_attachment_id(path: Path) -> Result { - let _attachment_id = path.into_inner(); - // let mut request_ctx = RequestContext::default(); - // let db = request_ctx.database(); - // let cases = app::Entity::find().order_by_asc(app::Column::Name).all(&CONFIG.get().await.db_client).await; - // let response = match cases { - // Ok(_cases) => _cases, - // Err(error) => panic!("Error while inserting: {:?}", error), - // }; - // Ok(HttpResponse::Ok().json(response)) - Ok(HttpResponse::from(HttpResponse::NoContent())) -} - - -/// Returns a Attachment Reference Object that will Hold the Attachment Information -/// -/// # Arguments -/// * `payload` - payload is streaming content of an attachment -async fn upload_attachment(mut payload: web::Payload) -> Result { - let mut body = web::BytesMut::new(); - while let Some(chunk) = payload.next().await { - let chunk = chunk.expect("Error from the Chunk"); - // limit max size of in-memory payload - if (body.len() + chunk.len()) > MAX_SIZE { - // handle the error when the streaming content is overflow - } - body.extend_from_slice(&chunk); - } - - // body is loaded, now we can deserialize serde-json - // let obj = serde_json::from_slice::(&body)?; - // Ok(HttpResponse::Ok().json(obj)) // <- send response - - // let _attachment_id = path.into_inner(); - // let mut request_ctx = RequestContext::default(); - // let db = request_ctx.database(); - // let cases = app::Entity::find().order_by_asc(app::Column::Name).all(&CONFIG.get().await.db_client).await; - // let response = match cases { - // Ok(_cases) => _cases, - // Err(error) => panic!("Error while inserting: {:?}", error), - // }; - // Ok(HttpResponse::Ok().json(response)) - Ok(HttpResponse::from(HttpResponse::NoContent())) -} - - diff --git a/crates/services/api-old/src/route/mod.rs b/crates/services/api-old/src/route/mod.rs deleted file mode 100644 index 2964acc..0000000 --- a/crates/services/api-old/src/route/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -use actix_web::{HttpResponse, web}; - -pub(crate) mod ws; -pub(crate) mod app; -pub(crate) mod file; - -// pub(crate) mod admin; -// pub(crate) mod ws; -// pub(crate) mod profile; -// pub(crate) mod case; -// pub(crate) mod auth; -// pub(crate) mod table; - -/// general_config - this will register all the endpoint in common route -pub fn general_config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/ping").route("", web::get().to(ping)) - ); -} - -/// ping - Api route will use the verify the application is up and running -/// uses Ping-Pong -async fn ping() -> HttpResponse { - HttpResponse::Ok().body("Pong!") -} \ No newline at end of file diff --git a/crates/services/api-old/src/route/ws.rs b/crates/services/api-old/src/route/ws.rs deleted file mode 100644 index 60bfa81..0000000 --- a/crates/services/api-old/src/route/ws.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::time::{Duration, Instant}; - -use actix::prelude::*; -use actix_web::{Error, HttpRequest, HttpResponse, web}; -use actix_web_actors::ws; - -/// How often heartbeat pings are sent -const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); - -/// How long before lack of client response causes a timeout -const CLIENT_TIMEOUT: Duration = Duration::from_secs(10); - -/// websocket connection is long running connection, it easier -/// to handle with an actor -pub struct MyWebSocket { - /// Client must send ping at least once per 10 seconds (CLIENT_TIMEOUT), - /// otherwise we drop connection. - hb: Instant, -} - -impl MyWebSocket { - pub fn new() -> Self { - Self { hb: Instant::now() } - } - - /// helper method that sends ping to client every 5 seconds (HEARTBEAT_INTERVAL). - /// - /// also this method checks heartbeats from client - fn hb(&self, ctx: &mut ::Context) { - ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| { - // check client heartbeats - if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT { - // heartbeat timed out - println!("Websocket Client heartbeat failed, disconnecting!"); - - // stop actor - ctx.stop(); - - // don't try to send a ping - return; - } - - ctx.ping(b""); - }); - } -} - -impl Actor for MyWebSocket { - type Context = ws::WebsocketContext; - - /// Method is called on actor start. We start the heartbeat process here. - fn started(&mut self, ctx: &mut Self::Context) { - self.hb(ctx); - } -} - -/// Handler for `ws::Message` -impl StreamHandler> for MyWebSocket { - fn handle(&mut self, msg: Result, ctx: &mut Self::Context) { - // process websocket messages - println!("WS: {msg:?}"); - match msg { - Ok(ws::Message::Ping(msg)) => { - self.hb = Instant::now(); - ctx.pong(&msg); - } - Ok(ws::Message::Pong(_)) => { - self.hb = Instant::now(); - } - Ok(ws::Message::Text(text)) => ctx.text(text), - Ok(ws::Message::Binary(bin)) => ctx.binary(bin), - Ok(ws::Message::Close(reason)) => { - ctx.close(reason); - ctx.stop(); - } - _ => ctx.stop(), - } - } -} - -/// WebSocket handshake and start `MyWebSocket` actor. -pub async fn ws_init(req: HttpRequest, stream: web::Payload) -> Result { - ws::start(MyWebSocket::new(), &req, stream) -} \ No newline at end of file diff --git a/crates/services/api-old/src/server/context/mod.rs b/crates/services/api-old/src/server/context/mod.rs deleted file mode 100644 index 2d73595..0000000 --- a/crates/services/api-old/src/server/context/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod request; \ No newline at end of file diff --git a/crates/services/api-old/src/server/context/request.rs b/crates/services/api-old/src/server/context/request.rs deleted file mode 100644 index f9fa136..0000000 --- a/crates/services/api-old/src/server/context/request.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::time::{SystemTime, SystemTimeError}; - -use actix_http::HttpMessage; -use actix_web::dev::ServiceRequest; -use log::info; -use sea_orm::DatabaseTransaction; - -// use cerium::config::Database; -use cerium::utils::uuid::request_uuid; - -// use crate::core::client::{CLIENT, Client, database}; - -/// RequestContext - will have all the dependency for the request -/// this will get created on each request and Will Construct required object in lazy -#[derive(Debug)] -pub struct RequestContext { - request_id: String, - start_time: SystemTime, - tx: Option -} - -impl RequestContext { - pub fn new(x: &ServiceRequest) -> Self { - Self { - request_id: request_uuid(), - start_time: SystemTime::now(), - tx: None - } - } - pub fn get_request_id(&self) -> String { - self.request_id.clone() - } - - pub fn end_request(&self) -> Result<(), SystemTimeError> { - let end_time = SystemTime::now(); - let start_time = self.start_time.elapsed()?.as_secs(); - info!("Completed Request {:} after - {:?}", self.get_request_id(), self.start_time.elapsed()); - Ok(()) - } - - pub fn set_request_value(mut req: ServiceRequest) -> ServiceRequest{ - let rc = Self::new(&req); - req.extensions_mut().insert(rc); - req - } - // pub fn database(&self) -> Database { - // CLIENT.lock().unwrap().clone().database() - // } - - // /// Begin transaction for any request in Orca - // pub async fn begin_tx(&mut self) -> Result<&DatabaseTransaction, DbErr> { - // self.tx = Some(self.database().conn.begin().await?); - // Ok(self.tx.as_ref().unwrap()) - // } - // pub fn commit_tx(self) { - // if self.tx.is_some(){ - // let result = self.tx.unwrap().commit(); - // } else { - // log::warn!("There is no transaction started -> Skipping commit") - // } - // } - // - // pub fn rollback(self){ - // if self.tx.is_some(){ - // let result = self.tx.unwrap().rollback(); - // } else { - // log::warn!("There is no transaction started -> Skipping rollback") - // } - // } -} - diff --git a/crates/services/api-old/src/server/middleware/mod.rs b/crates/services/api-old/src/server/middleware/mod.rs deleted file mode 100644 index b17f412..0000000 --- a/crates/services/api-old/src/server/middleware/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod request; \ No newline at end of file diff --git a/crates/services/api-old/src/server/middleware/request.rs b/crates/services/api-old/src/server/middleware/request.rs deleted file mode 100644 index dcbeb1a..0000000 --- a/crates/services/api-old/src/server/middleware/request.rs +++ /dev/null @@ -1,95 +0,0 @@ -use std::future::{ready, Ready}; -use std::sync::Arc; -use std::time::Instant; - -use actix_http::HttpMessage; -use actix_web::{dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform}, Error}; -use futures::future::LocalBoxFuture; -use log::info; -use sea_orm::TransactionTrait; - -use cerium::error::web::OrcaError; -use cerium::utils::uuid::request_uuid; -use migration::async_trait::async_trait; - -use crate::server::context::request::RequestContext; -use crate::utils::config::CONFIG; - -// There are two steps in middleware processing. -// 1. Middleware initialization, middleware factory gets called with -// next service in chain as parameter. -// 2. Middlewares call method gets called with normal request. -#[derive(Debug, Clone, Default)] -pub struct RequestHandler; - -// Middleware factory is `Transform` trait -// `S` - type of the next service -// `B` - type of response's body -impl Transform for RequestHandler -where - S: Service, Error = Error>, - S::Future: 'static, - B: 'static, -{ - type Response = ServiceResponse; - type Error = Error; - type Transform = RequestHandlerMiddleware; - type InitError = (); - type Future = Ready>; - - fn new_transform(&self, service: S) -> Self::Future { - ready(Ok(RequestHandlerMiddleware { service })) - } -} - -pub struct RequestHandlerMiddleware { - service: S, -} - -#[async_trait] -impl Service for RequestHandlerMiddleware -where - S: Service, Error = Error>, - S::Future: 'static, - B: 'static, -{ - type Response = ServiceResponse; - type Error = Error; - type Future = LocalBoxFuture<'static, Result>; - - forward_ready!(service); - - fn call(&self, req: ServiceRequest) -> Self::Future { - let request_id = request_uuid(); - let start_time = Instant::now(); - info!("Starting the Request {}", &request_id.clone()); - - // let authorization = req.headers().get(header::AUTHORIZATION); - // if authorization.is_none() { - // return Box::pin(async { Err(ErrorUnauthorized("err")) }); - // } - - let rc = RequestContext::new(&req); - req.extensions_mut().insert(rc); - let fut = self.service.call(req); - Box::pin(async move { - let db = &CONFIG.get().await.db_client; - let trx = db.begin().await.expect("Error form trx"); - // ext.insert(trx); - // req.extensions_mut().insert(trx); - let mut _response = fut.await; - // res.headers_mut().insert(HeaderName::from_static(REQUEST_ID_HEADER), - // HeaderValue::from_str(&request_id).unwrap()); - // trx.commit().await.expect("error"); - info!("Completed Request after - {:?}", start_time.elapsed()); - // rc.end_request(); - _response - }) - } -} - -pub fn map_io_error(e: std::io::Error) -> OrcaError { - match e.kind() { - _ => OrcaError::IoError(e), - } -} \ No newline at end of file diff --git a/crates/services/api-old/src/server/mod.rs b/crates/services/api-old/src/server/mod.rs deleted file mode 100644 index 199b118..0000000 --- a/crates/services/api-old/src/server/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub(crate) mod context; -pub(crate) mod middleware; \ No newline at end of file diff --git a/crates/services/api-old/src/utils/client/mod.rs b/crates/services/api-old/src/utils/client/mod.rs deleted file mode 100644 index a95d1c9..0000000 --- a/crates/services/api-old/src/utils/client/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! client will have all the Client connect / creation for the application -//! - - -pub async fn get_db_client() { - -} \ No newline at end of file diff --git a/crates/services/api-old/src/utils/config.rs b/crates/services/api-old/src/utils/config.rs deleted file mode 100644 index 7d0bc07..0000000 --- a/crates/services/api-old/src/utils/config.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! config module will have all configuration -//! - -use std::time::Duration; -use async_once::AsyncOnce; -use lazy_static::lazy_static; -use sea_orm::{ConnectOptions, Database, DatabaseConnection}; - -lazy_static! { - pub(crate) static ref CONFIG: AsyncOnce = AsyncOnce::new(async { - Config::new().await - }); -} - -pub(crate) enum Environment { - Dev, - Production -} - - -pub(crate) struct Config { - pub env: Environment, - pub db_client: DatabaseConnection -} - -impl Config { - pub async fn new() -> Self { - Config{ - env: Environment::Dev, - db_client: Self::db_client(None).await, - } - } - - pub fn db(&self) -> &DatabaseConnection { - &self.db_client - } - - /// db_uri will give the default uri if there is not config setup - async fn db_client(mut uri: Option) -> DatabaseConnection { - if uri.is_none(){ - uri = Some(std::env::var("DATABASE_URL").expect("DATABASE_URL must be set.")); - - } - // let mut opt = ConnectOptions::new(uri.unwrap()); - // opt.max_connections(100) - // .min_connections(5) - // .connect_timeout(Duration::from_secs(8)) - // .acquire_timeout(Duration::from_secs(8)) - // .idle_timeout(Duration::from_secs(8)) - // .max_lifetime(Duration::from_secs(8)) - // .sqlx_logging(true) - // .sqlx_logging_level(log::LevelFilter::Info); - // Database::connect(opt).await.expect("Error unable to connect DB") - Database::connect(uri.unwrap()).await.expect("Error unable to connect DB") - } -} \ No newline at end of file diff --git a/crates/services/api-old/src/utils/mod.rs b/crates/services/api-old/src/utils/mod.rs deleted file mode 100644 index 34ed7c5..0000000 --- a/crates/services/api-old/src/utils/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! utils will have all the support functionally for this application -//! And Helper functions -//! - -pub(crate) mod client; -pub(crate) mod config; - - -pub fn replace_special_chars(input: &str, replace_with: char) -> String { - let mut result = String::with_capacity(input.len()); - - for c in input.chars() { - if c.is_ascii_alphanumeric() || c == replace_with { - result.push(c); - } else { - result.push(replace_with); - } - } - result -} \ No newline at end of file diff --git a/crates/services/api-old/tests/mod.rs b/crates/services/api-old/tests/mod.rs deleted file mode 100644 index 96d65d9..0000000 --- a/crates/services/api-old/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod seed_data; diff --git a/crates/services/api-old/tests/seed_data.rs b/crates/services/api-old/tests/seed_data.rs deleted file mode 100644 index 06401b8..0000000 --- a/crates/services/api-old/tests/seed_data.rs +++ /dev/null @@ -1,151 +0,0 @@ -use sea_orm::{ActiveModelTrait, Database, DatabaseConnection, EntityTrait, ModelTrait, Set}; -use sea_orm::prelude::Uuid; - -use entity::prelude::*; -use entity::prelude::case_block::{BlockKind, BlockType}; -use entity::test::ui::action::{action, data, group, target}; -use entity::test::ui::action::action::ActionKind; -use entity::test::ui::action::data::ActionDataKind; -use entity::test::ui::action::target::ActionTargetKind; - -async fn connection() -> DatabaseConnection { - Database::connect("postgres://root:root@localhost:5432/orca".to_string()).await.expect("Error unable to connect DB") -} - - -#[tokio::test] -async fn t0001_seeding_data() -> Result<(), sea_orm::DbErr> { - let db = connection().await; - - let case001 = case::ActiveModel { - id: Set(Uuid::new_v4()), - name: Set("Login Validation testcase".to_owned()), - description: Set(Some("Validate the login for the Applciation".to_owned())), - ..Default::default() - }.insert(&db).await?; - - let case_block = case_block::ActiveModel { - id: Set(Uuid::new_v4()), - execution_order: Set(1), - kind: Set(BlockKind::Reference), - type_field: Set(BlockType::ActionGroup), - reference: Set("ACTION_GRP_001".to_owned()), - parent_id: Set(Some(case001.id.clone())), - ..Default::default() - }.insert(&db).await?; - - let case_block2 = case_block::ActiveModel { - id: Set(Uuid::new_v4()), - execution_order: Set(2), - kind: Set(BlockKind::Loop), - type_field: Set(BlockType::DataTable), - reference: Set("DATATABLE_001".to_owned()), - parent_id: Set(Some(case001.id.clone())), - ..Default::default() - }.insert(&db).await?; - - let case_block2_1 = case_block::ActiveModel { - id: Set(Uuid::new_v4()), - execution_order: Set(1), - kind: Set(BlockKind::Reference), - type_field: Set(BlockType::ActionGroup), - reference: Set("ACTION_GRP_001".to_owned()), - parent_id: Set(Some(case_block2.id.clone())), - ..Default::default() - }.insert(&db).await?; - Ok(()) -} - - -#[tokio::test] -async fn t0002_seeding_action() -> Result<(), sea_orm::DbErr> { - - let db = connection().await; - - let _group001 = group::ActiveModel { - id: Set(Uuid::new_v4()), - name: Set("Login Action Group".to_owned()), - description: Set(Some("login for the Application".to_owned())), - app_id: Set("4680b9b4-4c6e-45be-8c06-0799ec8795c9".to_owned().parse().unwrap()) - }.insert(&db).await?; - - let _action001 = action::ActiveModel { - id: Set(Uuid::new_v4()), - execution_order: Set(1), - description: Set("Click on Submit".to_string()), - kind: Set(ActionKind::Enter), - action_group_id: Set(_group001.id), - }.insert(&db).await?; - let _action001_data = data::ActiveModel { - id: Set(Uuid::new_v4()), - kind: Set(ActionDataKind::Static), - value: Set("mani@gmail.com".to_string()), - action_id: Set(_action001.id), - }.insert(&db).await?; - let _action001_target = target::ActiveModel { - id: Set(Uuid::new_v4()), - kind: Set(ActionTargetKind::Id), - value: Set("#email".to_string()), - action_id: Set(_action001.id), - }.insert(&db).await?; - - - let _action002 = action::ActiveModel { - id: Set(Uuid::new_v4()), - execution_order: Set(2), - description: Set("Enter password".to_string()), - kind: Set(ActionKind::Enter), - action_group_id: Set(_group001.id), - }.insert(&db).await?; - let _action002_data = data::ActiveModel { - id: Set(Uuid::new_v4()), - kind: Set(ActionDataKind::Static), - value: Set("password".to_string()), - action_id: Set(_action002.id), - }.insert(&db).await?; - let _action002_target = target::ActiveModel { - id: Set(Uuid::new_v4()), - kind: Set(ActionTargetKind::Id), - value: Set("#password".to_string()), - action_id: Set(_action002.id), - }.insert(&db).await?; - - - let _action003 = action::ActiveModel { - id: Set(Uuid::new_v4()), - execution_order: Set(3), - description: Set("click login".to_string()), - kind: Set(ActionKind::Click), - action_group_id: Set(_group001.id), - }.insert(&db).await?; - let _action003_target = target::ActiveModel { - id: Set(Uuid::new_v4()), - kind: Set(ActionTargetKind::Id), - value: Set("#login".to_string()), - action_id: Set(_action003.id), - }.insert(&db).await?; - - - Ok(()) -} - -#[tokio::test] -async fn validate_data() -> Result<(), sea_orm::DbErr> { - let db = connection().await; - let c = case::Entity::find_by_id("306b60ac-e27a-4a52-9245-22cee8bce095".parse().unwrap()) - .find_with_related(case_block::Entity) - .all(&db).await?; - eprintln!("{:#?}", c); - for x in c.into_iter() { - eprintln!("Main {:#?}", x.0); - for y in x.1.into_iter() { - eprintln!("Child {:#?}", y.clone()); - let res = y.find_linked(case_block::SelfReferencingLink).all(&db).await?; - // let res = case_block::Entity::find().all(&db).await?; - eprintln!("child 2 {:#?}", res); - } - } - Ok(()) - -} - From 55d5350ddebcd058f8ef822e6835694c6b41db34 Mon Sep 17 00:00:00 2001 From: Vasanth kumar Kalaiselvan Date: Thu, 15 Feb 2024 21:05:32 +0530 Subject: [PATCH 2/2] Added the service and session changes --- .cargo/config.example.toml | 3 + .cargo/config.local.toml | 3 + Cargo.toml | 14 +- crates/libs/cerium/Cargo.toml | 2 + crates/libs/cerium/src/client/driver/web.rs | 10 +- crates/libs/cerium/src/client/mod.rs | 12 ++ crates/libs/cerium/src/client/storage/mod.rs | 12 ++ crates/libs/cerium/src/client/storage/s3.rs | 158 ++++++++++++++++++ crates/libs/cerium/src/env.rs | 14 +- crates/libs/cerium/src/error/mod.rs | 8 + crates/libs/cerium/src/server/mod.rs | 45 +++-- crates/libs/entity/src/test/history.rs | 26 ++- .../entity/src/test/ui/case/case_block.rs | 18 +- crates/libs/entity/src/test/ui/mod.rs | 1 + .../entity/src/test/ui/object_repository.rs | 46 +++++ crates/libs/migration/src/lib.rs | 1 + crates/libs/migration/src/migration002.rs | 52 +++++- crates/libs/migration/src/migration004.rs | 12 +- crates/services/api/src/error.rs | 81 ++++++--- crates/services/api/src/main.rs | 17 +- crates/services/api/src/route/app/case.rs | 19 ++- .../services/api/src/route/app/datatable.rs | 3 +- crates/services/api/src/route/app/history.rs | 24 +++ crates/services/api/src/route/app/mod.rs | 5 +- crates/services/api/src/server/session.rs | 1 + crates/services/api/src/service/app/case.rs | 66 +++++--- .../services/api/src/service/app/datatable.rs | 5 +- .../services/api/src/service/app/history.rs | 46 +++++ crates/services/api/src/service/app/mod.rs | 1 + crates/services/engine/Cargo.toml | 3 +- .../services/engine/src/controller/action.rs | 19 ++- crates/services/engine/src/controller/case.rs | 29 ++-- crates/services/engine/tests/controller.rs | 8 +- crates/workshop/webdriver/Cargo.toml | 16 ++ crates/workshop/webdriver/src/main.rs | 3 + docker-compose.yml | 47 +++++- docs/datamodel/High level.excalidraw | 11 ++ rust-toolchain.toml | 2 + 38 files changed, 711 insertions(+), 132 deletions(-) create mode 100644 crates/libs/cerium/src/client/storage/mod.rs create mode 100644 crates/libs/cerium/src/client/storage/s3.rs create mode 100644 crates/libs/entity/src/test/ui/object_repository.rs create mode 100644 crates/services/api/src/route/app/history.rs create mode 100644 crates/services/api/src/service/app/history.rs create mode 100644 crates/workshop/webdriver/Cargo.toml create mode 100644 crates/workshop/webdriver/src/main.rs create mode 100644 docs/datamodel/High level.excalidraw create mode 100644 rust-toolchain.toml diff --git a/.cargo/config.example.toml b/.cargo/config.example.toml index 517baea..d28525b 100644 --- a/.cargo/config.example.toml +++ b/.cargo/config.example.toml @@ -11,6 +11,9 @@ RUST_LOG="cerium=debug,entity=debug,migration=info,api=debug" DATABASE_URI="" SELENIUM_URI="" +MINIO_ACCESS_KEY = "" +MINIO_ACCESS_SECRET = "" + # -- Encryption salt used for JWT token and other secret keys ENCRYPTION_SALT="" diff --git a/.cargo/config.local.toml b/.cargo/config.local.toml index 1734ac7..b6ee463 100644 --- a/.cargo/config.local.toml +++ b/.cargo/config.local.toml @@ -13,6 +13,9 @@ RUST_LOG="cerium=debug,entity=debug,migration=info,api=debug" DATABASE_URI="postgres://root:root@localhost:5432/orca" SELENIUM_URI="http://localhost:4444/wd/hub/session" +MINIO_ACCESS_KEY = "minioadmin" +MINIO_ACCESS_SECRET = "minioadmin" + # -- Encryption salt used for JWT token and other secret keys ENCRYPTION_SALT="strongencryption" diff --git a/Cargo.toml b/Cargo.toml index 5005d90..0d85d9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members=[ "crates/libs/entity", "crates/libs/migration", "crates/services/engine", - "crates/services/api", + "crates/services/api", "crates/workshop/webdriver", ] [workspace.package] @@ -29,14 +29,14 @@ engine = { path = "crates/services/engine", default-features = true } api = { path = "crates/services/api", default-features = true } thiserror = "1.0.31" -jsonwebtoken = "8" +jsonwebtoken = "9.2.0" serde = { version = "1.0.147"} serde_json = "1.0.87" chrono = { version = "0.4.31"} tracing = "0.1.37" tracing-subscriber = "0.3.16" uuid = { version = "1.6.1", features = ["serde", "v4"] } -config = "0.13.3" +config = "0.14.0" dotenv = "0.15.0" futures = "0.3.29" futures-util = "0.3.29" @@ -52,14 +52,18 @@ sea-orm = { version = "0.12.3", features = [ ] } sea-orm-migration = {version = "0.12.3", features = ["sqlx-postgres"]} axum = "0.7.1" -axum-extra = "0.8.0" +axum-extra = "0.9.1" tokio = { version = "1.34.0", features = ["full"] } tower = "0.4.13" tower-http = { version = "0.5.0", default-features = true, features = ["uuid", "cors", "trace", "compression-br", "catch-panic", "request-id"] } +rust-s3 = "0.33.0" + thirtyfour = "0.31.0" +geckodriver="0.34.0" + [patch.crates-io] -sea-orm = { git="https://github.com/itsparser/sea-orm", branch = "master" } \ No newline at end of file +sea-orm = { git="https://github.com/itsparser/sea-orm", branch = "master" } diff --git a/crates/libs/cerium/Cargo.toml b/crates/libs/cerium/Cargo.toml index 9809d63..d39643d 100644 --- a/crates/libs/cerium/Cargo.toml +++ b/crates/libs/cerium/Cargo.toml @@ -43,9 +43,11 @@ jsonwebtoken.workspace=true thiserror.workspace=true serde.workspace=true serde_json.workspace=true +rust-s3.workspace=true lazy_static = "1.4.0" async_once = "0.2.6" rand = { version = "0.8.5", default-features = false, features = ["std"] } +log = "0.4.20" diff --git a/crates/libs/cerium/src/client/driver/web.rs b/crates/libs/cerium/src/client/driver/web.rs index f2f0e29..2996ff1 100644 --- a/crates/libs/cerium/src/client/driver/web.rs +++ b/crates/libs/cerium/src/client/driver/web.rs @@ -1,4 +1,4 @@ -use thirtyfour::WebDriver as TFWebDriver; +use thirtyfour::{CapabilitiesHelper, WebDriver as TFWebDriver}; use crate::error::CeriumResult; use thirtyfour::{By, DesiredCapabilities, WebElement}; @@ -31,7 +31,8 @@ impl WebDriver { } pub async fn default() -> CeriumResult { - let caps = DesiredCapabilities::firefox(); + let mut caps = DesiredCapabilities::firefox(); + caps.add("se:recordVideo", true)?; let driver = TFWebDriver::new("http://localhost:4444/wd/hub/session", caps).await?; Self::new(driver) } @@ -40,6 +41,11 @@ impl WebDriver { Ok(self.driver.goto(url).await?) } + pub async fn quit(self) -> CeriumResult<()> { + Ok(self.driver.quit().await?) + } + + pub async fn create_window(&self, name: &str) -> CeriumResult<()> { let win_handler = self.driver.new_window().await?; self.driver.switch_to_window(win_handler).await?; diff --git a/crates/libs/cerium/src/client/mod.rs b/crates/libs/cerium/src/client/mod.rs index f182577..29c7981 100644 --- a/crates/libs/cerium/src/client/mod.rs +++ b/crates/libs/cerium/src/client/mod.rs @@ -1,22 +1,34 @@ use std::time::Duration; +use crate::client::storage::s3::S3Client; use sea_orm::{ConnectOptions, Database, DatabaseConnection}; pub mod cache; pub mod db; pub mod driver; +pub mod storage; #[derive(Debug, Clone)] pub struct Client { pub db: DatabaseConnection, + pub storage_cli: S3Client, } impl Client { pub async fn new(db_uri: Option, _redis_uri: Option) -> Self { Client { db: Self::db_client(db_uri).await, + storage_cli: Self::storage_client().await, } } + async fn storage_client() -> S3Client { + return S3Client::new( + &std::env::var("STORAGE_ACCESS_KEY").expect("STORAGE_ACCESS_KEY must be set."), + &std::env::var("STORAGE_ACCESS_SECRET").expect("STORAGE_ACCESS_SECRET must be set."), + &std::env::var("STORAGE_BASE_URL").expect("STORAGE_BASE_URL must be set."), + ) + .expect("Error While create Storage Client"); + } pub fn db(&self) -> &DatabaseConnection { &self.db diff --git a/crates/libs/cerium/src/client/storage/mod.rs b/crates/libs/cerium/src/client/storage/mod.rs new file mode 100644 index 0000000..4dc26ef --- /dev/null +++ b/crates/libs/cerium/src/client/storage/mod.rs @@ -0,0 +1,12 @@ +pub mod s3; + +pub trait StorageTrait { + fn create_bucket(); + fn upload(); + fn delete(self, key: String); +} + + +pub struct StorageClient { + +} diff --git a/crates/libs/cerium/src/client/storage/s3.rs b/crates/libs/cerium/src/client/storage/s3.rs new file mode 100644 index 0000000..f99bbba --- /dev/null +++ b/crates/libs/cerium/src/client/storage/s3.rs @@ -0,0 +1,158 @@ +use s3::bucket::Bucket; +use s3::creds::Credentials; +use s3::Region; +use tracing::info; + +use crate::error::CeriumResult; + +#[derive(Debug, Clone)] +pub struct S3Client { + credentials: Credentials, + region: Region +} + + +impl S3Client { + pub fn new(access_key: &str, secret_key: &str, base_url: &str) -> CeriumResult { + let region = Region::Custom { region: "orca".to_string(), endpoint: base_url.to_string() }; + + let credentials = Credentials::new(Some(access_key), Some(secret_key), None, None, None)?; + + Ok(Self { + credentials, + region + }) + + + // let response_data = bucket.put_object(format!("{id}.png").as_str(), content.as_slice()).await.expect("Got error"); + // + // let base_url = base_url.parse::()?; + // let static_provider = StaticProvider::new(access_key, secret_key, None); + // let client = Client::new(base_url.clone(), Some(Box::new(static_provider)), None, None)?; + // Ok(Self { + // client, + // }) + } + + /// Get Bucket will return the Bucket object for the Any bucket based action + pub fn get_bucket(&self, bucket_name: &str) -> CeriumResult { + let mut bucket = Bucket::new(bucket_name, self.region.clone(), self.credentials.clone())?; + bucket.set_path_style(); + Ok(bucket) + } + + pub async fn list_bucket(&self) -> CeriumResult<()> { + // let _bucket_obj = self.get_bucket(bucket)? + // let buckets =self.client.list_buckets(&args).await?; + Ok(()) + } + + pub async fn create(&self, bucket: &str, key: &str, data: &[u8]) -> CeriumResult<()> { + let _bucket_obj = self.get_bucket(bucket)?; + let result = _bucket_obj.put_object(key, data).await?; + Ok(()) + } + + pub async fn delete(&self, bucket: &String, key: &String) -> CeriumResult<()> { + let _bucket_obj = self.get_bucket(bucket)?; + let response = _bucket_obj.delete_object(key).await?; + info!("Deleted Object for {key} - Response {:?}", response); + Ok(()) + } + +} +// +// #[cfg(test)] +// mod tests { +// use crate::client::storage::s3::S3Client; +// +// // S3Client can be created with valid access_key, secret_key, and base_url +// #[tokio::test] +// async fn test_s3client_creation_with_valid_credentials() { +// let access_key = "minioadmin"; +// let secret_key = "minioadmin"; +// let base_url = "http://localhost:9000"; +// +// let result = S3Client::new(access_key, secret_key, base_url); +// +// +// assert!(result.is_ok()); +// // let r = result.unwrap().list_bucket().await; +// let r = result.unwrap().create("orca", "id.png", "jj").await; +// assert!(r.is_ok()); +// } +// +// // S3Client can delete an object from a bucket with a valid key +// #[tokio::test] +// async fn test_s3client_delete_object_with_valid_key() { +// let access_key = "valid_access_key"; +// let secret_key = "valid_secret_key"; +// let base_url = "valid_base_url"; +// let bucket = String::from("valid_bucket"); +// let key = String::from("valid_key"); +// +// let s3_client = S3Client::new(access_key, secret_key, base_url).unwrap(); +// let result = s3_client.delete(&bucket, &key).await; +// +// assert!(result.is_ok()); +// } +// +// // S3Client cannot be created with invalid access_key, secret_key, or base_url +// #[test] +// fn test_s3client_creation_with_invalid_credentials() { +// let access_key = "invalid_access_key"; +// let secret_key = "invalid_secret_key"; +// let base_url = "invalid_base_url"; +// +// let result = S3Client::new(access_key, secret_key, base_url); +// +// assert!(result.is_err()); +// } +// +// // S3Client cannot delete an object from a non-existent bucket +// #[tokio::test] +// async fn test_s3client_delete_object_from_nonexistent_bucket() { +// let access_key = "valid_access_key"; +// let secret_key = "valid_secret_key"; +// let base_url = "valid_base_url"; +// let bucket = String::from("nonexistent_bucket"); +// let key = String::from("valid_key"); +// +// let s3_client = S3Client::new(access_key, secret_key, base_url).unwrap(); +// let result = s3_client.delete(&bucket, &key).await; +// +// assert!(result.is_err()); +// } +// +// // S3Client cannot delete a non-existent object from a bucket +// #[tokio::test] +// async fn test_s3client_delete_nonexistent_object_from_bucket() { +// let access_key = "valid_access_key"; +// let secret_key = "valid_secret_key"; +// let base_url = "valid_base_url"; +// let bucket = String::from("valid_bucket"); +// let key = String::from("nonexistent_key"); +// +// let s3_client = S3Client::new(access_key, secret_key, base_url).unwrap(); +// let result = s3_client.delete(&bucket, &key).await; +// +// assert!(result.is_err()); +// } +// +// // S3Client can handle errors returned by the S3 service +// #[tokio::test] +// async fn test_s3client_handle_s3_service_errors() { +// let access_key = "valid_access_key"; +// let secret_key = "valid_secret_key"; +// let base_url = "valid_base_url"; +// let bucket = String::from("valid_bucket"); +// let key = String::from("valid_key"); +// +// let s3_client = S3Client::new(access_key, secret_key, base_url).unwrap(); +// let result = s3_client.delete(&bucket, &key).await; +// +// assert!(result.is_err()); +// } +// +// +// } diff --git a/crates/libs/cerium/src/env.rs b/crates/libs/cerium/src/env.rs index 33f7c95..4748d87 100644 --- a/crates/libs/cerium/src/env.rs +++ b/crates/libs/cerium/src/env.rs @@ -1,27 +1,31 @@ use std::env; -use config::{Config as CConfig, File}; use serde::Deserialize; #[derive(Debug, Deserialize, Clone)] -#[allow(unused)] pub struct Environment { pub debug: bool, pub database_uri: String, pub redis_uri: String, pub selenium_uri: String, - pub encryption_salt: String + pub encryption_salt: String, + pub minio_access_key: String, + pub minio_access_secret: String, } - impl Environment { pub fn default() -> Self { Environment { - debug: env::var("DEBUG").unwrap_or("false".to_string()).parse().unwrap(), + debug: env::var("DEBUG") + .unwrap_or("false".to_string()) + .parse() + .unwrap(), database_uri: env::var("DATABASE_URI").unwrap_or("".to_string()), redis_uri: env::var("REDIS_URI").unwrap_or("".to_string()), selenium_uri: env::var("SELENIUM_URI").unwrap_or("".to_string()), encryption_salt: env::var("ENCRYPTION_SALT").unwrap_or("".to_string()), + minio_access_key: env::var("MINIO_ACCESS_KEY").unwrap_or("".to_string()), + minio_access_secret: env::var("MINIO_ACCESS_SECRET").unwrap_or("".to_string()), } } } diff --git a/crates/libs/cerium/src/error/mod.rs b/crates/libs/cerium/src/error/mod.rs index 6afedb4..963fa3f 100644 --- a/crates/libs/cerium/src/error/mod.rs +++ b/crates/libs/cerium/src/error/mod.rs @@ -1,6 +1,8 @@ use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; use axum::Json; +use s3::creds::error::CredentialsError; +use s3::error::S3Error; use sea_orm::DbErr; use serde_json::{json, Error as SerdeJsonError}; use thirtyfour::error::WebDriverError; @@ -22,6 +24,12 @@ pub enum CeriumError { SerializerError(#[from] SerdeJsonError), #[error("Webdriver error: {0}")] WebdriverError(#[from] WebDriverError), + #[error("CredentialsError error: {0}")] + CredentialsError(#[from] CredentialsError), + #[error("CredentialsError error: {0}")] + S3Error(#[from] S3Error), + + } impl IntoResponse for CeriumError { diff --git a/crates/libs/cerium/src/server/mod.rs b/crates/libs/cerium/src/server/mod.rs index 379a1d5..b4ecbd9 100644 --- a/crates/libs/cerium/src/server/mod.rs +++ b/crates/libs/cerium/src/server/mod.rs @@ -1,19 +1,18 @@ use std::sync::{Arc, Mutex}; -use axum::{Router, serve}; use axum::http::{HeaderName, Method}; +use axum::{serve, Router}; use sea_orm::DatabaseConnection; use tokio::net::TcpListener; +use tower_http::request_id::{PropagateRequestIdLayer, SetRequestIdLayer}; +use tower_http::trace::TraceLayer; use tower_http::{ + catch_panic::CatchPanicLayer, compression::CompressionLayer, cors::{Any, CorsLayer}, }; -use tower_http::catch_panic::CatchPanicLayer; -use tower_http::request_id::{PropagateRequestIdLayer, SetRequestIdLayer}; -use tower_http::trace::TraceLayer; use tracing::{info, Level}; use tracing_subscriber::fmt; -use tracing_subscriber::layer::SubscriberExt; use crate::client::Client; use crate::server::request_id::OrcaRequestId; @@ -21,6 +20,16 @@ use crate::server::request_id::OrcaRequestId; mod request_id; mod utils; +/// Represents the application state, containing a database connection wrapped in an `Arc`. +/// This struct is cloneable. +/// +/// # Fields +/// +/// - `db`: An `Arc>` representing the database connection. +/// +/// # Example +/// +/// #[derive(Clone)] pub struct AppState { pub db: Arc>, @@ -45,14 +54,26 @@ impl App { } } + /// Sets the logger with the specified log level filter. + /// + /// # Arguments + /// + /// - `filter`: A `Level` enum representing the log level filter. + /// + /// # Example + /// + /// ``` + /// use tracing::Level; + /// + /// let app = App::new("my_app", client); + /// app.set_logger(Level::INFO); + /// pub fn set_logger(&self, filter: Level) { - fmt() - // .with(tracing_subscriber::fmt::layer()) - // .with_target(true) - // .with_timer(tracing_subscriber::fmt::time::uptime()) - // .with_level(true) - .with_max_level(filter) - .init() + fmt().with_max_level(filter).init() + // .with(tracing_subscriber::fmt::layer()) + // .with_target(true) + // .with_timer(tracing_subscriber::fmt::time::uptime()) + // .with_level(true) } pub fn set_port(&mut self, port: i32) { diff --git a/crates/libs/entity/src/test/history.rs b/crates/libs/entity/src/test/history.rs index 29cfd33..e96e8fa 100644 --- a/crates/libs/entity/src/test/history.rs +++ b/crates/libs/entity/src/test/history.rs @@ -1,6 +1,5 @@ //! SeaORM Entity. Generated by sea-orm-codegen 0.6.0 -use chrono::Utc; use sea_orm::entity::prelude::*; use sea_orm::EntityTrait; use serde::{Deserialize, Serialize}; @@ -35,6 +34,28 @@ pub enum ExecutionKind { Trigger, } + +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Deserialize, Serialize)] +#[sea_orm( +rs_type = "String", +db_type = "String(Some(10))", +enum_name = "execution_status" +)] +pub enum ExecutionStatus { + #[sea_orm(string_value = "Started")] + #[serde(rename = "Started")] + Started, + #[sea_orm(string_value = "Running")] + #[serde(rename = "Running")] + Running, + #[sea_orm(string_value = "Completed")] + #[serde(rename = "Completed")] + Completed, + #[sea_orm(string_value = "Failed")] + #[serde(rename = "Failed")] + Failed, +} + #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)] #[sea_orm(table_name = "history")] pub struct Model { @@ -47,10 +68,11 @@ pub struct Model { #[sea_orm(string_value = "type")] #[serde(rename = "type")] pub history_type: ExecutionType, + pub status: ExecutionStatus, pub args: Option, pub triggered_by: Option, - pub triggered_on: Option>, + pub triggered_on: chrono::NaiveDateTime } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/crates/libs/entity/src/test/ui/case/case_block.rs b/crates/libs/entity/src/test/ui/case/case_block.rs index 3b103aa..3da09d4 100644 --- a/crates/libs/entity/src/test/ui/case/case_block.rs +++ b/crates/libs/entity/src/test/ui/case/case_block.rs @@ -11,12 +11,10 @@ use serde::{Deserialize, Serialize}; enum_name = "block_kind" )] pub enum BlockKind { - #[sea_orm(string_value = "Loop")] - Loop, - #[sea_orm(string_value = "Condition")] - Condition, #[sea_orm(string_value = "Reference")] Reference, + #[sea_orm(string_value = "SelfReference")] + SelfReference, // #[sea_orm(string_value = "ValidationGroup")] // ValidationGroup, } @@ -36,6 +34,18 @@ pub enum BlockType { ActionGroup, #[sea_orm(string_value = "Assertion")] Assertion, + #[sea_orm(string_value = "Loop")] + Loop, + #[sea_orm(string_value = "Condition")] + Condition, + #[sea_orm(string_value = "YesCase")] + YesCase, + #[sea_orm(string_value = "NoCase")] + NoCase, + #[sea_orm(string_value = "Parallel")] + Parallel, + #[sea_orm(string_value = "Block")] + Block, } #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)] diff --git a/crates/libs/entity/src/test/ui/mod.rs b/crates/libs/entity/src/test/ui/mod.rs index 1e24055..58ca900 100644 --- a/crates/libs/entity/src/test/ui/mod.rs +++ b/crates/libs/entity/src/test/ui/mod.rs @@ -3,3 +3,4 @@ pub mod case; pub mod elements; pub mod screen; pub mod suit; +mod object_repository; diff --git a/crates/libs/entity/src/test/ui/object_repository.rs b/crates/libs/entity/src/test/ui/object_repository.rs new file mode 100644 index 0000000..f7563d0 --- /dev/null +++ b/crates/libs/entity/src/test/ui/object_repository.rs @@ -0,0 +1,46 @@ +// //! SeaORM Entity. Generated by sea-orm-codegen 0.6.0 +// +// use sea_orm::entity::prelude::*; +// use sea_orm::EntityTrait; +// use serde::{Deserialize, Serialize}; +// +// +// #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)] +// #[sea_orm(table_name = "object_repository")] +// pub struct Model { +// #[serde(skip_deserializing)] +// #[sea_orm(primary_key)] +// pub id: i32, +// pub path: String, +// pub name: String, +// pub endpoint: String, +// pub endpoint_name: String, +// pub description: String, +// } +// +// #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +// pub enum Relation { +// #[sea_orm(has_many = "super::action::Entity")] +// Action, +// #[sea_orm( +// belongs_to = "crate::app::app::Entity", +// from = "Column::AppId", +// to = "crate::app::app::Column::Id" +// )] +// App, +// } +// +// // `Related` trait has to be implemented by hand +// impl Related for Entity { +// fn to() -> RelationDef { +// Relation::Action.def() +// } +// } +// +// impl Related for Entity { +// fn to() -> RelationDef { +// Relation::App.def() +// } +// } +// +// impl ActiveModelBehavior for ActiveModel {} diff --git a/crates/libs/migration/src/lib.rs b/crates/libs/migration/src/lib.rs index bdc1071..61ec17f 100644 --- a/crates/libs/migration/src/lib.rs +++ b/crates/libs/migration/src/lib.rs @@ -14,6 +14,7 @@ impl MigratorTrait for Migrator { Box::new(migration001::Migration), Box::new(migration002::Migration), Box::new(migration003::Migration), + Box::new(migration004::Migration), ] } } diff --git a/crates/libs/migration/src/migration002.rs b/crates/libs/migration/src/migration002.rs index 6bd27b4..132e0bd 100644 --- a/crates/libs/migration/src/migration002.rs +++ b/crates/libs/migration/src/migration002.rs @@ -76,7 +76,7 @@ impl MigrationTrait for Migration { kind: Set(ActionKind::Click), target_kind: Set(Some(ActionTargetKind::Xpath)), target_value: Set(Some( - "//form[@id='search-form']/fieldset/button/i".to_string(), + "//*[@id='search-form']/fieldset/button".to_string(), )), execution_order: Set(3), action_group_id: Set(app_g.clone().id), @@ -108,7 +108,7 @@ impl MigrationTrait for Migration { data_kind: Set(Some(ActionDataKind::Static)), data_value: Set(Some("Ana de Armas".to_string())), target_kind: Set(Some(ActionTargetKind::Xpath)), - target_value: Set(Some("//*[@id='search-form']/fieldset/button".to_string())), + target_value: Set(Some("//h1[@id='firstHeading']/span".to_string())), execution_order: Set(1), action_group_id: Set(assert_g_m.clone().id), ..Default::default() @@ -125,6 +125,9 @@ impl MigrationTrait for Migration { app_id: Set(app.clone().id), }; let case_m: case::Model = case_am.insert(db).await?; + let uuid1 = Uuid::new_v4(); + let uuid2 = Uuid::new_v4(); + let uuid3 = Uuid::new_v4(); let case_blocks = vec![ case_block::ActiveModel { @@ -149,6 +152,51 @@ impl MigrationTrait for Migration { } .insert(db) .await?, + case_block::ActiveModel { + id: Set(uuid1.clone()), + execution_order: Set(3), + kind: Set(BlockKind::SelfReference), + type_field: Set(BlockType::Condition), + case_id: Set(case_m.clone().id), + ..Default::default() + } + .insert(db) + .await?, + case_block::ActiveModel { + id: Set(uuid2.clone()), + execution_order: Set(1), + kind: Set(BlockKind::SelfReference), + type_field: Set(BlockType::YesCase), + parent_id: Set(Some(uuid1.clone())), + case_id: Set(case_m.clone().id), + ..Default::default() + } + .insert(db) + .await?, + case_block::ActiveModel { + id: Set(uuid3.clone()), + execution_order: Set(2), + kind: Set(BlockKind::SelfReference), + type_field: Set(BlockType::NoCase), + parent_id: Set(Some(uuid1.clone())), + case_id: Set(case_m.clone().id), + ..Default::default() + } + .insert(db) + .await?, + + case_block::ActiveModel { + id: Set(Uuid::new_v4()), + execution_order: Set(1), + kind: Set(BlockKind::Reference), + type_field: Set(BlockType::ActionGroup), + reference: Set(Some(app_g.clone().id)), + parent_id: Set(Some(uuid2.clone())), + case_id: Set(case_m.clone().id), + ..Default::default() + } + .insert(db) + .await?, ]; Ok(()) } diff --git a/crates/libs/migration/src/migration004.rs b/crates/libs/migration/src/migration004.rs index 272a707..4422748 100644 --- a/crates/libs/migration/src/migration004.rs +++ b/crates/libs/migration/src/migration004.rs @@ -33,17 +33,19 @@ impl MigrationTrait for Migration { .boolean() .not_null(), ) + .col( + ColumnDef::new(history::Column::Status) + .string() + .not_null(), + ) .col(ColumnDef::new(history::Column::Args).json()) .col(ColumnDef::new(history::Column::Reference).uuid()) .col( - ColumnDef::new(history::Column::TriggeredOn) - .integer() - .not_null(), + ColumnDef::new(history::Column::TriggeredOn).date_time().null(), ) .col( ColumnDef::new(history::Column::TriggeredBy) - .date_time() - .not_null(), + .integer(), ) .to_owned(), ) diff --git a/crates/services/api/src/error.rs b/crates/services/api/src/error.rs index 7be583f..d00cd90 100644 --- a/crates/services/api/src/error.rs +++ b/crates/services/api/src/error.rs @@ -4,6 +4,8 @@ use axum::response::{IntoResponse, Response}; use sea_orm::DbErr; use serde_json::{Error as SerdeJsonError, json}; use thiserror::Error; +use cerium::error::CeriumError; +use engine::error::EngineError; use crate::error::OrcaError::RepoError; @@ -21,42 +23,73 @@ pub enum OrcaRepoError { } /// Our app's top level error type. +#[derive(Error, Debug)] pub enum OrcaError { /// Something went wrong when calling the user repo. - DataBaseError(DbErr), - RepoError(OrcaRepoError), - SerializerError(SerdeJsonError), -} -/// This makes it possible to use `?` to automatically convert a `DbErr` -/// into an `OrcaError`. -impl From for OrcaError { - fn from(inner: OrcaRepoError) -> Self { - OrcaError::RepoError(inner) - } -} + #[error("DbErr error: {0}")] + DataBaseError(#[from] DbErr), -/// This makes it possible to use `?` to automatically convert a `DbErr` -/// into an `OrcaError`. -impl From for OrcaError { - fn from(inner: DbErr) -> Self { - OrcaError::DataBaseError(inner) - } -} + #[error("OrcaRepoError error: {0}")] + RepoError(#[from] OrcaRepoError), -/// This makes it possible to use `?` to automatically convert a `DbErr` -/// into an `OrcaError`. -impl From for OrcaError { - fn from(inner: SerdeJsonError) -> Self { - OrcaError::SerializerError(inner) - } + #[error("SerializerError error: {0}")] + SerializerError(#[from] SerdeJsonError), + + #[error("EngineError error: {0}")] + EngineError(#[from] EngineError), + + #[error("CeriumError error: {0}")] + CeriumError(#[from] CeriumError), } +// /// This makes it possible to use `?` to automatically convert a `DbErr` +// /// into an `OrcaError`. +// impl From for OrcaError { +// fn from(inner: OrcaRepoError) -> Self { +// OrcaError::RepoError(inner) +// } +// } +// +// /// This makes it possible to use `?` to automatically convert a `DbErr` +// /// into an `OrcaError`. +// impl From for OrcaError { +// fn from(inner: DbErr) -> Self { +// OrcaError::DataBaseError(inner) +// } +// } +// +// /// This makes it possible to use `?` to automatically convert a `EngineError` +// /// into an `OrcaError`. +// impl From for OrcaError { +// fn from(inner: EngineError) -> Self { +// OrcaError::EngineError(inner) +// } +// } +// +// /// This makes it possible to use `?` to automatically convert a `CeriumError` +// /// into an `OrcaError`. +// impl From for OrcaError { +// fn from(inner: CeriumError) -> Self { +// OrcaError::CeriumError(inner) +// } +// } + +// /// This makes it possible to use `?` to automatically convert a `DbErr` +// /// into an `OrcaError`. +// impl From for OrcaError { +// fn from(inner: SerdeJsonError) -> Self { +// OrcaError::SerializerError(inner) +// } +// } + impl IntoResponse for OrcaError { fn into_response(self) -> Response { let (status, error_message) = match self { OrcaError::DataBaseError(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), OrcaError::SerializerError(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), + OrcaError::CeriumError(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), + OrcaError::EngineError(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()), RepoError(err) => (StatusCode::NOT_FOUND, err.to_string()), _ => ( StatusCode::INTERNAL_SERVER_ERROR, diff --git a/crates/services/api/src/main.rs b/crates/services/api/src/main.rs index 5be654c..c179588 100644 --- a/crates/services/api/src/main.rs +++ b/crates/services/api/src/main.rs @@ -1,4 +1,4 @@ -use std::env; +use axum::Extension; use std::sync::Arc; use sea_orm::{DatabaseConnection, DbErr}; @@ -25,11 +25,8 @@ pub(crate) async fn run_migration(db: &DatabaseConnection) -> Result<(), DbErr> Ok(()) } pub(crate) async fn get_config() -> Client { - let env = Environment::default(); - Client::new( - Some(env.database_uri), - Some(env.redis_uri), - ).await + let env = Environment::default(); + Client::new(Some(env.database_uri), Some(env.redis_uri)).await } #[tokio::main] @@ -40,9 +37,11 @@ async fn main() { app.set_port(8080); run_migration(cli.db()).await.expect("TODO: panic message"); - let routers = handle_router().layer(OrcaLayer { - db: Arc::new(cli.db.clone()), - }); + let routers = handle_router() + .layer(Extension(cli.clone())) + .layer(OrcaLayer { + db: Arc::new(cli.db.clone()), + }); app.set_router(routers); app.run().await; } diff --git a/crates/services/api/src/route/app/case.rs b/crates/services/api/src/route/app/case.rs index aa6c61b..19eb6ae 100644 --- a/crates/services/api/src/route/app/case.rs +++ b/crates/services/api/src/route/app/case.rs @@ -6,6 +6,7 @@ use axum::{Extension, Json, Router}; use entity::prelude::case::Model; use entity::prelude::case_block::Model as BlockModel; use uuid::Uuid; +use cerium::client::Client; use crate::error::InternalResult; use crate::server::session::OrcaSession; @@ -32,28 +33,31 @@ pub(crate) fn test_case_route() -> Router { /// list_cases - list all the Case that is Bind with Current Application async fn list_cases( Extension(session): Extension, + Extension(cli): Extension, Path(app_id): Path, ) -> InternalResult { - let result = CaseService::new(session, app_id).list_cases().await?; + let result = CaseService::new(session, cli, app_id).list_cases().await?; Ok(Json(result)) } /// create_case - This will New Test Case for the specific Application in Orca async fn create_case( Extension(session): Extension, + Extension(cli): Extension, Path(app_id): Path, Json(body): Json, ) -> InternalResult { - let result = CaseService::new(session, app_id).create_case(body).await?; + let result = CaseService::new(session, cli, app_id).create_case(body).await?; Ok((StatusCode::CREATED, Json(result))) } /// get_case_info - Get Case Info and the batch information with the list of block async fn get_case_info( Extension(session): Extension, + Extension(cli): Extension, Path((app_id, case_id)): Path<(Uuid, Uuid)>, ) -> InternalResult { - let result = CaseService::new(session, app_id) + let result = CaseService::new(session, cli, app_id) .get_case_info(case_id) .await?; Ok(Json(result)) @@ -62,19 +66,21 @@ async fn get_case_info( /// dry_run - Dry run the Test case async fn dry_run( Extension(session): Extension, + Extension(cli): Extension, Path((app_id, case_id)): Path<(Uuid, Uuid)>, ) -> InternalResult { - let result = CaseService::new(session, app_id).run(case_id).await?; + let result = CaseService::new(session, cli, app_id).run(case_id).await?; Ok(Json(result)) } /// update_block - update test case Block async fn update_block( Extension(session): Extension, + Extension(cli): Extension, Path((app_id, case_id)): Path<(Uuid, Uuid)>, Json(body): Json>, ) -> InternalResult { - let result = CaseService::new(session, app_id) + let result = CaseService::new(session, cli, app_id) .batch_update_case_block(case_id, body) .await?; Ok(Json(result)) @@ -83,10 +89,11 @@ async fn update_block( /// insert_block - This will Append New Block to the code for spe async fn insert_block( Extension(session): Extension, + Extension(cli): Extension, Path((app_id, case_id)): Path<(Uuid, Uuid)>, Json(body): Json, ) -> InternalResult { - let result = CaseService::new(session, app_id) + let result = CaseService::new(session, cli, app_id) .push_block(case_id, body, None, None) .await?; Ok(Json(result)) diff --git a/crates/services/api/src/route/app/datatable.rs b/crates/services/api/src/route/app/datatable.rs index 22219c5..7895d9d 100644 --- a/crates/services/api/src/route/app/datatable.rs +++ b/crates/services/api/src/route/app/datatable.rs @@ -1,11 +1,10 @@ +use axum::{Extension, Json, Router}; use axum::extract::Path; use axum::http::StatusCode; use axum::response::IntoResponse; use axum::routing::{get, post}; -use axum::{Extension, Json, Router}; use sea_orm::prelude::Uuid; use serde_json::{json, Value}; -use tracing::debug; use entity::test::datatable::Model; use entity::test::field::Model as FieldModel; diff --git a/crates/services/api/src/route/app/history.rs b/crates/services/api/src/route/app/history.rs new file mode 100644 index 0000000..3f6ed13 --- /dev/null +++ b/crates/services/api/src/route/app/history.rs @@ -0,0 +1,24 @@ +use axum::{Extension, Json, Router}; +use axum::extract::Path; +use axum::response::IntoResponse; +use axum::routing::get; +use uuid::Uuid; + +use crate::error::InternalResult; +use crate::server::session::OrcaSession; +use crate::service::app::history::HistoryService; + +/// history_route - this will register all the endpoint in Execution history route +pub(crate) fn history_route() -> Router { + Router::new() + .route("/", get(get_history)) +} + +/// get_action - list all the Action Group in Specific Application in the Orca Application +async fn get_history( + Extension(session): Extension, + Path(_app_id): Path, +) -> InternalResult { + let result = HistoryService::new(session).list_history().await?; + Ok(Json(result)) +} diff --git a/crates/services/api/src/route/app/mod.rs b/crates/services/api/src/route/app/mod.rs index d3c9236..ee20921 100644 --- a/crates/services/api/src/route/app/mod.rs +++ b/crates/services/api/src/route/app/mod.rs @@ -12,6 +12,7 @@ use crate::route::app::action::action_route; use crate::route::app::case::test_case_route; use crate::route::app::datatable::datatable_route; use crate::route::app::group::group_route; +use crate::route::app::history::history_route; use crate::route::app::profile::profile_route; use crate::route::app::suit::suite_route; use crate::server::session::OrcaSession; @@ -23,6 +24,7 @@ pub(crate) mod datatable; pub(crate) mod group; pub(crate) mod profile; pub(crate) mod suit; +pub(crate) mod history; pub fn app_route() -> Router { Router::new() @@ -38,7 +40,8 @@ pub fn app_route() -> Router { .nest("/profile", profile_route()) .nest("/datatable", datatable_route()) .nest("/case", test_case_route()) - .nest("/suite", suite_route()), + .nest("/suite", suite_route()) + .nest("/history", history_route()) ) } diff --git a/crates/services/api/src/server/session.rs b/crates/services/api/src/server/session.rs index c48f44d..31d374d 100644 --- a/crates/services/api/src/server/session.rs +++ b/crates/services/api/src/server/session.rs @@ -1,3 +1,4 @@ +use std::sync::Arc; use sea_orm::DatabaseTransaction; #[derive(Clone)] diff --git a/crates/services/api/src/service/app/case.rs b/crates/services/api/src/service/app/case.rs index 4f08e9c..ae59161 100644 --- a/crates/services/api/src/service/app/case.rs +++ b/crates/services/api/src/service/app/case.rs @@ -1,38 +1,43 @@ -use sea_orm::{ - ActiveModelTrait, ColumnTrait, DatabaseTransaction, EntityTrait, IntoActiveModel, QueryFilter, - QueryOrder, QuerySelect, TryIntoModel, -}; +use futures::executor::block_on; +use sea_orm::{ActiveModelTrait, ColumnTrait, DatabaseTransaction, EntityTrait, IntoActiveModel, ModelTrait, NotSet, QueryFilter, QueryOrder, QuerySelect, TryIntoModel}; use sea_orm::ActiveValue::Set; use sea_query::{Condition, Expr}; use tracing::{debug, info}; use uuid::Uuid; +use cerium::client::Client; use cerium::client::driver::web::WebDriver; use engine::controller::case::CaseController; use entity::prelude::case::{Column, Entity, Model}; -use entity::prelude::case_block::{ - ActiveModel as BlockActiveModel, Column as BlockColumn, Entity as BlockEntity, - Model as BlockModel, -}; +use entity::prelude::case_block::{ActiveModel as BlockActiveModel, Column as BlockColumn, Entity as BlockEntity, Model as BlockModel, SelfReferencingLink}; +use entity::test::history; +use entity::test::history::{ExecutionKind, ExecutionStatus, ExecutionType}; use crate::error::{InternalResult, OrcaRepoError}; use crate::server::session::OrcaSession; +use crate::service::app::history::HistoryService; -pub(crate) struct CaseService(OrcaSession, Uuid); +pub(crate) struct CaseService(OrcaSession, Client, Uuid); impl CaseService { - pub fn new(session: OrcaSession, app_id: Uuid) -> Self { - Self(session, app_id) + pub fn new(session: OrcaSession, cli: Client, app_id: Uuid) -> Self { + Self(session, cli, app_id) } pub fn trx(&self) -> &DatabaseTransaction { self.0.trx() } + pub async fn create_history(&self, case_id: Uuid, desc: Option) -> InternalResult { + let history = HistoryService::new(self.0.clone()).create_history(case_id, ExecutionKind::Trigger, + ExecutionType::TestCase, desc, Some(true)).await?; + Ok(history) + } + /// list all the test suites in the Orca Application pub(crate) async fn list_cases(&self) -> InternalResult> { let cases = Entity::find() - .filter(Column::AppId.eq(self.1)) + .filter(Column::AppId.eq(self.2)) .order_by_asc(Column::Name) .all(self.trx()) .await?; @@ -42,7 +47,7 @@ impl CaseService { /// create_case - this will create new Application in Orca pub async fn create_case(&self, mut app: Model) -> InternalResult { app.id = Uuid::new_v4(); - app.app_id = self.1; + app.app_id = self.2; let app = app.into_active_model(); let result = app.insert(self.trx()).await?; Ok(result) @@ -58,11 +63,25 @@ impl CaseService { ))?; } let mut case = case.unwrap(); + + let condition = Condition::all() + .add(BlockColumn::CaseId.eq(case_id)) + .add(BlockColumn::ParentId.is_null()); let case_blocks = BlockEntity::find() - .filter(BlockColumn::CaseId.eq(case_id)) - .order_by_asc(BlockColumn::ExecutionOrder) + // .filter(BlockColumn::CaseId.eq(case_id)) + .filter(condition) + .order_by_asc(BlockColumn::ExecutionOrder).find_with_linked(SelfReferencingLink) .all(self.trx()) .await?; + info!("{:#?}", case_blocks); + + // case_blocks.clone().into_iter().for_each(|case| { + // let d = block_on(case.find_linked(SelfReferencingLink).all(self.trx())).expect("erro"); + // info!("{:?}", d); + // info!("{:?}", case); + // + // }); + case.case_execution = Some(serde_json::to_value(case_blocks)?); Ok(case) } @@ -120,13 +139,16 @@ impl CaseService { case_id.to_string(), ))?; } - - let ui_driver = WebDriver::default().await.expect("error"); - info!("got the driver"); - let controller = CaseController::new(self.trx(), ui_driver.clone()); - info!("got the controller"); - controller.process(&case.unwrap()).await.expect("error"); - ui_driver.driver.quit().await.expect("TODO: panic message"); + let _case = case.unwrap(); + let history = self.create_history(case_id, Some(format!("Executing - {case_name}", case_name=_case.name))).await?; + let ui_driver = WebDriver::default().await?; + let controller = CaseController::new(self.trx(), ui_driver.clone(), self.1.clone()); + controller.process(&_case).await?; + ui_driver.quit().await?; + let mut _history = history.into_active_model(); + _history.status = Set(ExecutionStatus::Completed); + _history.description = Set(Some(format!("Executed - {case_name}", case_name=_case.name))); + _history.save(self.trx()).await?; Ok(()) } diff --git a/crates/services/api/src/service/app/datatable.rs b/crates/services/api/src/service/app/datatable.rs index a715281..457398e 100644 --- a/crates/services/api/src/service/app/datatable.rs +++ b/crates/services/api/src/service/app/datatable.rs @@ -1,5 +1,4 @@ use chrono::Utc; -use futures_util::StreamExt; use sea_orm::{ ActiveModelTrait, ColumnTrait, ConnectionTrait, DatabaseBackend, DatabaseTransaction, EntityTrait, IntoActiveModel, JsonValue, ModelTrait, NotSet, QueryFilter, QueryOrder @@ -92,7 +91,7 @@ impl DatatableService { /// create_new_field - this will create new Field in Data Application in Orca pub async fn create_new_field( &self, - mut table_id: i32, + table_id: i32, mut field: FieldModel, ) -> InternalResult { let table = self.get_datatable(table_id).await?; @@ -151,7 +150,7 @@ impl DatatableService { pub async fn batch_update_data( &self, table_id: i32, - mut table_datas: Vec, + table_datas: Vec, ) -> InternalResult<()> { let table = self.get_datatable(table_id).await?; // let result = table_datas.iter_mut().map(|item| { diff --git a/crates/services/api/src/service/app/history.rs b/crates/services/api/src/service/app/history.rs new file mode 100644 index 0000000..8cc7bd7 --- /dev/null +++ b/crates/services/api/src/service/app/history.rs @@ -0,0 +1,46 @@ +use sea_orm::{ActiveModelTrait, DatabaseTransaction, EntityTrait, QueryOrder}; +use sea_orm::ActiveValue::Set; +use uuid::Uuid; +use entity::test::history; +use entity::test::history::{Entity, Column, Model, ExecutionKind, ExecutionType, ExecutionStatus}; +use crate::error::InternalResult; +use crate::server::session::OrcaSession; + +pub(crate) struct HistoryService(OrcaSession); + +impl HistoryService { + pub fn new(session: OrcaSession) -> Self { + Self(session) + } + + pub fn trx(&self) -> &DatabaseTransaction { + self.0.trx() + } + + /// list all the History Data in the Orca Application + pub async fn list_history(&self) -> InternalResult> { + let histories = Entity::find() + .order_by_desc(Column::Id) + .all(self.trx()) + .await?; + Ok(histories) + } + + pub async fn create_history(&self, id: Uuid, kind: ExecutionKind, history_type: ExecutionType, + desc: Option, is_dry_run: Option) -> InternalResult { + let history = history::ActiveModel { + kind: Set(kind), + is_dry_run: Set(is_dry_run.unwrap_or(false)), + reference: Set(id), + history_type: Set(history_type), + description: Set(desc), + status: Set(ExecutionStatus::Running), + triggered_on: Set(chrono::Utc::now().naive_utc()), + triggered_by: Set(Some(1)), + ..Default::default() + }; + Ok(history.insert(self.trx()).await?) + } + + +} \ No newline at end of file diff --git a/crates/services/api/src/service/app/mod.rs b/crates/services/api/src/service/app/mod.rs index ffc450c..05a47a7 100644 --- a/crates/services/api/src/service/app/mod.rs +++ b/crates/services/api/src/service/app/mod.rs @@ -12,6 +12,7 @@ pub(crate) mod datatable; pub(crate) mod group; pub(crate) mod profile; pub(crate) mod suit; +pub(crate) mod history; pub(crate) struct AppService(OrcaSession); diff --git a/crates/services/engine/Cargo.toml b/crates/services/engine/Cargo.toml index 69322eb..8d8eb50 100644 --- a/crates/services/engine/Cargo.toml +++ b/crates/services/engine/Cargo.toml @@ -27,7 +27,6 @@ default = ["ui-automation", "api-automation"] cerium.workspace = true entity.workspace = true - sea-orm.workspace = true serde.workspace = true serde_json.workspace = true @@ -35,6 +34,8 @@ thiserror.workspace = true tokio.workspace = true tracing.workspace=true tracing-subscriber.workspace=true +rust-s3.workspace=true thirtyfour.workspace = true +anyhow = "1.0.79" diff --git a/crates/services/engine/src/controller/action.rs b/crates/services/engine/src/controller/action.rs index 7129c37..807a86c 100644 --- a/crates/services/engine/src/controller/action.rs +++ b/crates/services/engine/src/controller/action.rs @@ -1,6 +1,4 @@ -use std::fs; -use std::io::Write; - +use s3::Region; use sea_orm::{ ColumnTrait, DatabaseTransaction, EntityTrait, ModelTrait, PaginatorTrait, QueryFilter, QueryOrder, @@ -9,7 +7,9 @@ use sea_orm::prelude::Uuid; use thirtyfour::By; use tracing::info; +use cerium::client::Client; use cerium::client::driver::web::WebDriver; +use cerium::client::storage::s3::S3Client; use entity::prelude::target::ActionTargetKind; use entity::test::ui::action::action; use entity::test::ui::action::action::ActionKind; @@ -19,6 +19,8 @@ use crate::error::{EngineError, EngineResult}; pub struct ActionController<'ccl> { db: &'ccl DatabaseTransaction, driver: WebDriver, + client: Client, + storage_cli: S3Client } impl<'ccl> ActionController<'ccl> { @@ -42,8 +44,9 @@ impl<'ccl> ActionController<'ccl> { /// let driver = WebDriver::default(); /// let controller = ActionController::new(&db, driver); /// ``` - pub fn new(db: &'ccl DatabaseTransaction, driver: WebDriver) -> ActionController<'ccl> { - Self { db, driver } + pub fn new(db: &'ccl DatabaseTransaction, driver: WebDriver, client: Client) -> ActionController<'ccl> { + let storage_cli = client.storage_cli.clone(); + Self { db, driver, client, storage_cli } } /// Asynchronous method that handles the logic for executing the "Open" action in a test case. @@ -216,9 +219,9 @@ impl<'ccl> ActionController<'ccl> { } async fn take_screenshot(&self, id: String) -> EngineResult<()> { - let result = self.driver.take_screenshot().await?; - let mut file = fs::File::create(format!("evidence_{id}.png")).expect("error"); - file.write_all(&*result).expect("error"); + + let content = self.driver.take_screenshot().await?; + let result = self.storage_cli.create("orca", format!("{id}.png").as_str(), content.as_slice()).await; Ok(()) } diff --git a/crates/services/engine/src/controller/case.rs b/crates/services/engine/src/controller/case.rs index 7a6edd1..de5b09e 100644 --- a/crates/services/engine/src/controller/case.rs +++ b/crates/services/engine/src/controller/case.rs @@ -3,6 +3,7 @@ use sea_orm::{ ColumnTrait, DatabaseTransaction, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, }; use tracing::{error, info}; +use cerium::client::Client; use cerium::client::driver::web::WebDriver; use entity::prelude::case::Entity; @@ -15,12 +16,13 @@ use crate::error::EngineResult; pub struct CaseController<'ccl> { db: &'ccl DatabaseTransaction, + cli: Client, drive: WebDriver, } impl<'ccl> CaseController<'ccl> { - pub fn new(db: &'ccl DatabaseTransaction, drive: WebDriver) -> CaseController<'ccl> { - Self { db, drive } + pub fn new(db: &'ccl DatabaseTransaction, drive: WebDriver, cli: Client) -> CaseController<'ccl> { + Self { db, drive, cli} } /// run_case - will execute the test case by the case ID pub async fn run_case(&self, id: Uuid) -> EngineResult<()> { @@ -56,13 +58,16 @@ impl<'ccl> CaseController<'ccl> { /// switch_block - function to switch the block based on the type and kind of the block async fn switch_block(&self, block: &case_block::Model) -> EngineResult<()> { let result = match block.kind { - BlockKind::Loop => match block.type_field { - BlockType::InMemory => self.process_action_group(block), - BlockType::DataTable => self.process_action_group(block), - _ => todo!("Need to raise a error from here since non other supported"), - }, - BlockKind::Condition => match block.type_field { - BlockType::InMemory => self.process_action_group(block), + // BlockKind::Loop => match block.type_field { + // BlockType::InMemory => self.process_action_group(block), + // BlockType::DataTable => self.process_action_group(block), + // _ => todo!("Need to raise a error from here since non other supported"), + // }, + BlockKind::SelfReference => match block.type_field { + BlockType::Condition => self.process_action_group(block), + BlockType::YesCase => self.process_action_group(block), + BlockType::NoCase => self.process_action_group(block), + BlockType::Loop => self.process_action_group(block), _ => todo!("Need to raise a error from here since non other supported"), }, BlockKind::Reference => match block.type_field { @@ -85,8 +90,8 @@ impl<'ccl> CaseController<'ccl> { async fn process_action_group(&self, block: &case_block::Model) -> EngineResult<()> { info!("Starting processing {block_id}", block_id = block.id); - Ok(ActionController::new(self.db, self.drive.clone()) - .execute(block.reference.unwrap()) - .await?) + let controller = ActionController::new(self.db, self.drive.clone(), self.cli.clone()); + let result = controller.execute(block.reference.unwrap_or_default()).await?; + Ok(result) } } diff --git a/crates/services/engine/tests/controller.rs b/crates/services/engine/tests/controller.rs index 0964589..46e5e18 100644 --- a/crates/services/engine/tests/controller.rs +++ b/crates/services/engine/tests/controller.rs @@ -7,6 +7,7 @@ mod tests { use sea_orm::{Database, TransactionTrait}; use tracing::{info, Level}; use tracing_subscriber::fmt; + use cerium::client::Client; use engine::controller::case::CaseController; @@ -14,9 +15,9 @@ mod tests { async fn dry_run_test_controller() { // init_logger(); fmt().with_max_level(Level::DEBUG).init(); - let case_id = "731453aa-95a5-4180-be0d-c211a1e92aad".to_string(); + let case_id = "8b72b6d1-f3a7-4d3e-9dbb-150b5eb0c060".to_string(); - let uri = Some("postgres://root:root@localhost:5432/orca".to_string()); + let uri = Some("postgres://root:root@localhost:5433/orca".to_string()); let db = Database::connect(uri.unwrap()) .await @@ -25,7 +26,8 @@ mod tests { info!("got the db"); let ui_driver = WebDriver::default().await.expect("error"); info!("got the driver"); - let controller = CaseController::new(&trx, ui_driver.clone()); + let client = Client::new(Some("postgres://root:root@localhost:5433/orca".to_string()), None).await; + let controller = CaseController::new(&trx, ui_driver.clone(), client); info!("got the controller"); controller .run_case(Uuid::from_str(case_id.as_str()).expect("")) diff --git a/crates/workshop/webdriver/Cargo.toml b/crates/workshop/webdriver/Cargo.toml new file mode 100644 index 0000000..4f36ac8 --- /dev/null +++ b/crates/workshop/webdriver/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "webdriver" +authors.workspace = true +edition.workspace = true +version.workspace = true +license.workspace = true +documentation.workspace = true +homepage.workspace = true +repository.workspace = true +rust-version.workspace = true +exclude.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +geckodriver.workspace = true diff --git a/crates/workshop/webdriver/src/main.rs b/crates/workshop/webdriver/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/crates/workshop/webdriver/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/docker-compose.yml b/docker-compose.yml index 3dec343..527b0c0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,22 @@ version: '3' services: + minio: + container_name: minio-ser + restart: on-failure + image: minio/minio + ports: + - "9000:9000" + - "9001:9001" + environment: + - MINIO_BROWSER_REDIRECT_URL=http://localhost:9001 + - MINIO_DEFAULT_BUCKETS=orca + command: server /data --console-address ":9001" + volumes: + - './data/minio_data:/data' + chrome: platform: linux/amd64 - image: selenium/node-chrome:4.7.1-20221208 + image: selenium/node-chrome:nightly shm_size: 2gb depends_on: - selenium-hub @@ -13,8 +27,9 @@ services: - SE_NODE_MAX_CONCURRENT_SESSIONS=5 firefox: + container_name: firefox platform: linux/amd64 - image: selenium/node-firefox:4.7.1-20221208 + image: selenium/node-firefox:nightly shm_size: 2gb depends_on: - selenium-hub @@ -22,8 +37,32 @@ services: - SE_EVENT_BUS_HOST=selenium-hub - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + - SE_NODE_MAX_CONCURRENT_SESSIONS=1 + - SE_NODE_MAX_SESSIONS=5 + + firefox_video: + platform: linux/amd64 + image: selenium/video:nightly + depends_on: + - firefox + - minio + environment: + - DISPLAY_CONTAINER_NAME=firefox + - SE_VIDEO_FILE_NAME=auto + - SE_VIDEO_UPLOAD_ENABLED=true + - SE_VIDEO_INTERNAL_UPLOAD=true - SE_NODE_MAX_CONCURRENT_SESSIONS=5 - SE_NODE_MAX_SESSIONS=5 + - SE_UPLOAD_DESTINATION_PREFIX=s3://orca/session + - RCLONE_CONFIG_S3_TYPE=s3 + - RCLONE_CONFIG_S3_PROVIDER=Minio + - RCLONE_CONFIG_S3_ENV_AUTH=false + - RCLONE_CONFIG_S3_REGION=us-east-1 +# - RCLONE_CONFIG_S3_LOCATION_CONSTRAINT=asia-southeast1 + - RCLONE_CONFIG_S3_ACL=private + - RCLONE_CONFIG_S3_ACCESS_KEY_ID=minioadmin + - RCLONE_CONFIG_S3_SECRET_ACCESS_KEY=minioadmin + - RCLONE_CONFIG_S3_ENDPOINT=http://minio-ser:9000 # chrome_video: # image: selenium/video:ffmpeg-4.3.1-20221208 @@ -48,7 +87,7 @@ services: selenium-hub: platform: linux/amd64 - image: selenium/hub:4.7.1-20221208 + image: selenium/hub:nightly container_name: selenium-hub ports: - "4442:4442" @@ -64,7 +103,7 @@ services: - POSTGRES_PASSWORD=root - POSTGRES_DB=orca ports: - - "5432:5432" + - "5433:5432" volumes: - ./data:/var/lib/postgresql/data container_name: postgres-ser diff --git a/docs/datamodel/High level.excalidraw b/docs/datamodel/High level.excalidraw new file mode 100644 index 0000000..11c9e04 --- /dev/null +++ b/docs/datamodel/High level.excalidraw @@ -0,0 +1,11 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..31578d3 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" \ No newline at end of file