Skip to content

Commit

Permalink
Merge pull request #216 from STCLab-Inc/215-add-date-information-to-a…
Browse files Browse the repository at this point in the history
…pimetrics-apiscaling-components-and-apiplans

feat(data-layer): Add date information in getting metrics, scaling-co…
  • Loading branch information
pueding committed Dec 8, 2023
2 parents d2eecdd + 7969fcb commit 4206cef
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 5 deletions.
32 changes: 29 additions & 3 deletions core/api-server/src/controller/metric_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn init(cfg: &mut web::ServiceConfig) {
#[get("/api/metrics")]
async fn get_metrics(app_state: web::Data<AppState>) -> impl Responder {
debug!("Getting all metrics");
let metrics = app_state.data_layer.get_all_metrics().await;
let metrics = app_state.data_layer.get_all_metrics_json().await;
if metrics.is_err() {
error!("Failed to get metrics: {:?}", metrics);
return HttpResponse::InternalServerError().body(format!("{:?}", metrics));
Expand Down Expand Up @@ -148,11 +148,11 @@ mod tests {
data_layer.get_all_metrics().await.unwrap()
}

// [GET] /api/metrics
// [GET] /api/metrics (get_all_metrics)

#[actix_web::test]
#[tracing_test::traced_test]
async fn test_get_metrics() {
async fn test_get_all_metrics() {
let app_state = get_app_state_for_test().await;
add_metrics_for_test(&app_state.data_layer).await;
let app = test::init_service(App::new().app_data(app_state).configure(init)).await;
Expand All @@ -161,6 +161,32 @@ mod tests {
assert_eq!(resp.len(), 2);
}

// [GET] /api/metrics (get_all_metrics_json)

#[actix_web::test]
#[tracing_test::traced_test]
async fn test_get_all_metrics_json() {
let app_state = get_app_state_for_test().await;
add_metrics_for_test(&app_state.data_layer).await;
let app = test::init_service(App::new().app_data(app_state).configure(init)).await;
let req = test::TestRequest::get().uri("/api/metrics").to_request();
let resp: Vec<serde_json::Value> = test::call_and_read_body_json(&app, req).await;
assert_eq!(resp.len(), 2);
for metric in resp.iter() {
if let Some(created_at) = metric.get("created_at").and_then(|v| v.as_str()) {
assert!(!created_at.is_empty());
} else {
panic!("created_at field is missing or not a string");
}

if let Some(updated_at) = metric.get("updated_at").and_then(|v| v.as_str()) {
assert!(!updated_at.is_empty());
} else {
panic!("updated_at field is missing or not a string");
}
}
}

// [GET] /api/metrics/{db_id}

#[actix_web::test]
Expand Down
87 changes: 86 additions & 1 deletion core/api-server/src/controller/plan_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn init(cfg: &mut web::ServiceConfig) {

#[get("/api/plans")]
async fn get_plans(app_state: web::Data<AppState>) -> impl Responder {
let plans = app_state.data_layer.get_all_plans().await;
let plans = app_state.data_layer.get_all_plans_json().await;
if plans.is_err() {
error!("Failed to get plans: {:?}", plans);
return HttpResponse::InternalServerError().body(format!("{:?}", plans));
Expand Down Expand Up @@ -95,3 +95,88 @@ async fn delete_plan_by_id(
debug!("Deleted plan");
HttpResponse::Ok().body("ok")
}

#[cfg(test)]
mod tests {
use crate::utils::test_utils::get_app_state_for_test;

use super::init;
use actix_web::{test, App};
use data_layer::{
data_layer::DataLayer,
types::{object_kind::ObjectKind, plan_item_definition::PlanItemDefinition},
};
use serde_json::json;
use std::collections::HashMap;

// Utility functions

async fn add_plans_for_test(data_layer: &DataLayer) {
let _ = data_layer
.add_plans(vec![
data_layer::ScalingPlanDefinition {
id: "test1".to_string(),
db_id: "test1".to_string(),
kind: ObjectKind::ScalingPlan,
metadata: HashMap::new(),
plans: vec![PlanItemDefinition {
id: "test1".to_string(),
description: None,
expression: None,
cron_expression: None,
ui: None,
priority: 1,
scaling_components: vec![json!({
"name": "test1",
"value": 1
})],
}],
},
data_layer::ScalingPlanDefinition {
id: "test2".to_string(),
db_id: "test2".to_string(),
kind: ObjectKind::ScalingPlan,
metadata: HashMap::new(),
plans: vec![PlanItemDefinition {
id: "test2".to_string(),
description: None,
expression: None,
cron_expression: None,
ui: None,
priority: 1,
scaling_components: vec![json!({
"name": "test2",
"value": 2
})],
}],
},
])
.await;
}

// [GET] /api/plans (get_all_plans_json)

#[actix_web::test]
#[tracing_test::traced_test]
async fn test_get_all_plans_json() {
let app_state = get_app_state_for_test().await;
add_plans_for_test(&app_state.data_layer).await;
let app = test::init_service(App::new().app_data(app_state).configure(init)).await;
let req = test::TestRequest::get().uri("/api/plans").to_request();
let resp: Vec<serde_json::Value> = test::call_and_read_body_json(&app, req).await;
assert_eq!(resp.len(), 2);
for plan in resp.iter() {
if let Some(created_at) = plan.get("created_at").and_then(|v| v.as_str()) {
assert!(!created_at.is_empty());
} else {
panic!("created_at field is missing or not a string");
}

if let Some(updated_at) = plan.get("updated_at").and_then(|v| v.as_str()) {
assert!(!updated_at.is_empty());
} else {
panic!("updated_at field is missing or not a string");
}
}
}
}
63 changes: 62 additions & 1 deletion core/api-server/src/controller/scaling_component_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub fn init(cfg: &mut web::ServiceConfig) {
async fn get_scaling_components(app_state: web::Data<AppState>) -> impl Responder {
// HttpResponse::Ok().body("Hello world!")
// const scaling_components = &app
let scaling_components = app_state.data_layer.get_all_scaling_components().await;
let scaling_components = app_state.data_layer.get_all_scaling_components_json().await;
if scaling_components.is_err() {
return HttpResponse::InternalServerError().body(format!("{:?}", scaling_components));
}
Expand Down Expand Up @@ -92,3 +92,64 @@ async fn delete_scaling_component_by_id(
}
HttpResponse::Ok().body("ok")
}

#[cfg(test)]
mod tests {
use crate::utils::test_utils::get_app_state_for_test;

use super::init;
use actix_web::{test, App};
use data_layer::{data_layer::DataLayer, types::object_kind::ObjectKind};
use std::collections::HashMap;

// Utility functions

async fn add_scaling_components_for_test(data_layer: &DataLayer) {
let _ = data_layer
.add_scaling_components(vec![
data_layer::ScalingComponentDefinition {
id: "test1".to_string(),
db_id: "test1".to_string(),
component_kind: "test1".to_string(),
kind: ObjectKind::ScalingComponent,
metadata: HashMap::new(),
},
data_layer::ScalingComponentDefinition {
id: "test2".to_string(),
db_id: "test2".to_string(),
component_kind: "test2".to_string(),
kind: ObjectKind::ScalingComponent,
metadata: HashMap::new(),
},
])
.await;
}

// [GET] /api/scaling-components (get_all_scaling_components_json)

#[actix_web::test]
#[tracing_test::traced_test]
async fn test_get_all_scaling_components_json() {
let app_state = get_app_state_for_test().await;
add_scaling_components_for_test(&app_state.data_layer).await;
let app = test::init_service(App::new().app_data(app_state).configure(init)).await;
let req = test::TestRequest::get()
.uri("/api/scaling-components")
.to_request();
let resp: Vec<serde_json::Value> = test::call_and_read_body_json(&app, req).await;
assert_eq!(resp.len(), 2);
for component in resp.iter() {
if let Some(created_at) = component.get("created_at").and_then(|v| v.as_str()) {
assert!(!created_at.is_empty());
} else {
panic!("created_at field is missing or not a string");
}

if let Some(updated_at) = component.get("updated_at").and_then(|v| v.as_str()) {
assert!(!updated_at.is_empty());
} else {
panic!("updated_at field is missing or not a string");
}
}
}
}
73 changes: 73 additions & 0 deletions core/data-layer/src/data_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,31 @@ impl DataLayer {
}
Ok(metrics)
}
// Get all metrics json from the database
pub async fn get_all_metrics_json(&self) -> Result<Vec<serde_json::Value>> {
let mut metrics: Vec<serde_json::Value> = Vec::new();
let query_string =
"SELECT db_id, id, collector, metadata, created_at, updated_at FROM metric";
let result = sqlx::query(query_string).fetch_all(&self.pool).await;
if result.is_err() {
return Err(anyhow!(result.err().unwrap().to_string()));
}
let result = result.unwrap();
for row in result {
let metric = json!({
"kind": ObjectKind::Metric,
"db_id": row.try_get::<String, _>("db_id")?,
"id": row.try_get::<String, _>("id")?,
"collector": row.try_get::<String, _>("collector")?,
"metadata": serde_json::from_str::<serde_json::Value>(row.try_get::<String, _>("metadata")?.as_str())?,
"created_at": row.try_get::<Option<String>, _>("created_at")?,
"updated_at": row.try_get::<Option<String>, _>("updated_at")?,
});
metrics.push(metric);
}

Ok(metrics)
}
// Get a metric from the database
pub async fn get_metric_by_id(&self, db_id: String) -> Result<Option<MetricDefinition>> {
let query_string = "SELECT db_id, id, collector, metadata FROM metric WHERE db_id=$1";
Expand Down Expand Up @@ -433,6 +458,30 @@ impl DataLayer {
}
Ok(scaling_components)
}
// Get all scaling components json from the database
pub async fn get_all_scaling_components_json(&self) -> Result<Vec<serde_json::Value>> {
let mut scaling_components: Vec<serde_json::Value> = Vec::new();
let query_string = "SELECT db_id, id, component_kind, metadata, created_at, updated_at FROM scaling_component";
let result = sqlx::query(query_string).fetch_all(&self.pool).await;
if result.is_err() {
return Err(anyhow!(result.err().unwrap().to_string()));
}
let result = result.unwrap();
for row in result {
let scaling_component = json!({
"kind": ObjectKind::ScalingComponent,
"db_id": row.try_get::<String, _>("db_id")?,
"id": row.try_get::<String, _>("id")?,
"component_kind": row.try_get::<String, _>("component_kind")?,
"metadata": serde_json::from_str::<serde_json::Value>(row.try_get::<String, _>("metadata")?.as_str())?,
"created_at": row.try_get::<Option<String>, _>("created_at")?,
"updated_at": row.try_get::<Option<String>, _>("updated_at")?,
});
scaling_components.push(scaling_component);
}

Ok(scaling_components)
}
// Get a scaling component from the database
pub async fn get_scaling_component_by_id(
&self,
Expand Down Expand Up @@ -558,6 +607,30 @@ impl DataLayer {
}
Ok(plans)
}
// Get all plans json from the database
pub async fn get_all_plans_json(&self) -> Result<Vec<serde_json::Value>> {
let mut plans: Vec<serde_json::Value> = Vec::new();
let query_string =
"SELECT db_id, id, plans, priority, metadata, created_at, updated_at FROM plan";
let result = sqlx::query(query_string).fetch_all(&self.pool).await;
if result.is_err() {
return Err(anyhow!(result.err().unwrap().to_string()));
}
let result = result.unwrap();
for row in result {
let plan = json!({
"kind": ObjectKind::ScalingPlan,
"db_id": row.try_get::<String, _>("db_id")?,
"id": row.try_get::<String, _>("id")?,
"plans": serde_json::from_str::<serde_json::Value>(row.try_get::<String, _>("plans")?.as_str())?,
"metadata": serde_json::from_str::<serde_json::Value>(row.try_get::<String, _>("metadata")?.as_str())?,
"created_at": row.try_get::<Option<String>, _>("created_at")?,
"updated_at": row.try_get::<Option<String>, _>("updated_at")?,
});
plans.push(plan);
}
Ok(plans)
}
// Get a plan from the database
pub async fn get_plan_by_id(&self, db_id: String) -> Result<ScalingPlanDefinition> {
let query_string = "SELECT db_id, id, metadata, plans FROM plan WHERE db_id=$1";
Expand Down

0 comments on commit 4206cef

Please sign in to comment.