From d40cb532a692505a8e5fe176b93cde49e367fad7 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 16 Dec 2024 01:13:31 +0100 Subject: [PATCH 1/6] test(test/resources): add flavor modify tests Signed-off-by: Sandro-Alessio Gierens --- test/tests/resources/flavor_group/mod.rs | 1 + test/tests/resources/flavor_group/modify.rs | 148 ++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 test/tests/resources/flavor_group/modify.rs diff --git a/test/tests/resources/flavor_group/mod.rs b/test/tests/resources/flavor_group/mod.rs index 0f8a89f7..33018c67 100644 --- a/test/tests/resources/flavor_group/mod.rs +++ b/test/tests/resources/flavor_group/mod.rs @@ -1 +1,2 @@ mod delete; +mod modify; diff --git a/test/tests/resources/flavor_group/modify.rs b/test/tests/resources/flavor_group/modify.rs new file mode 100644 index 00000000..c6416b3d --- /dev/null +++ b/test/tests/resources/flavor_group/modify.rs @@ -0,0 +1,148 @@ +use lrzcc::{Api, Token}; +use lrzcc_test::{random_alphanumeric_string, spawn_app}; +use std::str::FromStr; +use tokio::task::spawn_blocking; + +#[tokio::test] +async fn e2e_lib_flavor_group_modify_denies_access_to_normal_user() { + // arrange + let server = spawn_app().await; + let test_project = server + .setup_test_project(0, 0, 1) + .await + .expect("Failed to setup test project"); + let user = test_project.normals[0].user.clone(); + let token = test_project.normals[0].token.clone(); + let project = test_project.project.clone(); + server + .mock_keystone_auth(&token, &user.openstack_id, &user.name) + .mount(&server.keystone_server) + .await; + let flavor_group = server + .setup_test_flavor_group(project.id) + .await + .expect("Failed to setup test server state"); + + spawn_blocking(move || { + // arrange + let client = Api::new( + format!("{}/api", &server.address), + Token::from_str(&token).unwrap(), + None, + None, + ) + .unwrap(); + + // act + let modify = client.flavor_group.modify(flavor_group.id).send(); + + // assert + assert!(modify.is_err()); + assert_eq!( + modify.unwrap_err().to_string(), + format!("Admin privileges required") + ); + }) + .await + .unwrap(); +} + +#[tokio::test] +async fn e2e_lib_flavor_group_modify_denies_access_to_master_user() { + // arrange + let server = spawn_app().await; + let test_project = server + .setup_test_project(0, 1, 0) + .await + .expect("Failed to setup test project"); + let user = test_project.masters[0].user.clone(); + let token = test_project.masters[0].token.clone(); + let project = test_project.project.clone(); + server + .mock_keystone_auth(&token, &user.openstack_id, &user.name) + .mount(&server.keystone_server) + .await; + let flavor_group = server + .setup_test_flavor_group(project.id) + .await + .expect("Failed to setup test server state"); + + spawn_blocking(move || { + // arrange + let client = Api::new( + format!("{}/api", &server.address), + Token::from_str(&token).unwrap(), + None, + None, + ) + .unwrap(); + + // act + let modify = client.flavor_group.modify(flavor_group.id).send(); + + // assert + assert!(modify.is_err()); + assert_eq!( + modify.unwrap_err().to_string(), + format!("Admin privileges required") + ); + }) + .await + .unwrap(); +} + +#[tokio::test] +async fn e2e_lib_flavor_group_modify_and_get_works() { + // arrange + let server = spawn_app().await; + let (user, project, token) = server + .setup_test_user_and_project(true) + .await + .expect("Failed to setup test user and project."); + server + .mock_keystone_auth(&token, &user.openstack_id, &user.name) + .mount(&server.keystone_server) + .await; + let flavor_group = server + .setup_test_flavor_group(project.id) + .await + .expect("Failed to setup test server state"); + + spawn_blocking(move || { + // arrange + let client = Api::new( + format!("{}/api", &server.address), + Token::from_str(&token).unwrap(), + None, + None, + ) + .unwrap(); + + // act and assert 1 - modify + let name = random_alphanumeric_string(10); + let modified = client + .flavor_group + .modify(flavor_group.id) + .name(name.clone()) + // TODO: test changing the project + .send() + .unwrap(); + assert_eq!(&name, &modified.name); + + // act and assert 2 - get + let retrieved = client.flavor_group.get(modified.id).unwrap(); + assert_eq!(modified.id, retrieved.id); + assert_eq!(modified.name, retrieved.name); + assert_eq!(modified.project, retrieved.project.id); + assert_eq!( + modified.flavors, + retrieved + .flavors + .into_iter() + .map(|f| f.id) + .collect::>() + ); + }) + .await + .unwrap(); +} From 8a19fbee428d6c36dce319796366ee7a7461653f Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 16 Dec 2024 01:14:15 +0100 Subject: [PATCH 2/6] fix(api/database): correct field types in select_maybe_flavor_group_from_db Signed-off-by: Sandro-Alessio Gierens --- api/src/database/resources/flavor_group.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/database/resources/flavor_group.rs b/api/src/database/resources/flavor_group.rs index 69ac78c0..62ada530 100644 --- a/api/src/database/resources/flavor_group.rs +++ b/api/src/database/resources/flavor_group.rs @@ -72,9 +72,9 @@ pub async fn select_maybe_flavor_group_from_db( ) -> Result, UnexpectedOnlyError> { #[derive(FromRow)] pub struct FlavorGroupDb { - pub id: u32, + pub id: i32, pub name: String, - pub project_id: u32, + pub project_id: i32, } let query1 = sqlx::query!( r#" @@ -117,9 +117,9 @@ pub async fn select_maybe_flavor_group_from_db( .map(|row| row.id) .collect::>(); Ok(Some(FlavorGroup { - id: flavor_group.id, + id: flavor_group.id as u32, name: flavor_group.name, - project: flavor_group.project_id, + project: flavor_group.project_id as u32, flavors, })) } From 13b22f3cb8bd2d841858b4e9d5288f07cd300a70 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 16 Dec 2024 01:17:16 +0100 Subject: [PATCH 3/6] fix(api/database): correct query in select_maybe_project_minimal_from_db Signed-off-by: Sandro-Alessio Gierens --- api/src/database/user/project.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api/src/database/user/project.rs b/api/src/database/user/project.rs index 71d63c3e..fc4396f9 100644 --- a/api/src/database/user/project.rs +++ b/api/src/database/user/project.rs @@ -53,7 +53,10 @@ pub async fn select_maybe_project_minimal_from_db( ) -> Result, UnexpectedOnlyError> { let query = sqlx::query!( r#" - SELECT id, name + SELECT + id as project__id, + name as project__name, + user_class as project__user_class FROM user_project AS project WHERE project.id = ? "#, From cc4d3645bfed4ba133b07a87156baea6d5e8abf2 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 16 Dec 2024 01:25:29 +0100 Subject: [PATCH 4/6] fix(scripts): increase mariadb connection limit in init_db.sh Signed-off-by: Sandro-Alessio Gierens --- scripts/init_db.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/init_db.sh b/scripts/init_db.sh index fe301cb0..c4dc054e 100755 --- a/scripts/init_db.sh +++ b/scripts/init_db.sh @@ -21,8 +21,7 @@ DB_PASSWORD="${MARIADB_PASSWORD:=password}" DB_NAME="${MARIADB_DB:=lrzcc}" DB_PORT="${MARIADB_PORT:=3306}" -if [[ -z "${SKIP_DOCKER}" ]] -then +if [[ -z "${SKIP_DOCKER}" ]]; then docker stop lrzcc-db || true docker rm lrzcc-db || true docker run \ @@ -40,8 +39,10 @@ done >&2 echo "MariaDB is up and running on ${DB_HOST} on port ${DB_PORT}!" +mariadb -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASSWORD}" -D "" -e "SET GLOBAL max_connections := 1000" + export DATABASE_URL=mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} sqlx database create sqlx migrate run ->&2 echo "MariaDB has been migrated, ready to go!" +>&2 echo "MariaDB has been configured and migrated, ready to go!" From e8c2d6e0abdb00905dc84ff0231843b578c9fb2d Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 16 Dec 2024 01:26:37 +0100 Subject: [PATCH 5/6] fix(lib/budgeting): add user and end in BudgetOverTreeRequest.params Signed-off-by: Sandro-Alessio Gierens --- lib/src/budgeting/budget_over_tree.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/src/budgeting/budget_over_tree.rs b/lib/src/budgeting/budget_over_tree.rs index bef47f6b..06516876 100644 --- a/lib/src/budgeting/budget_over_tree.rs +++ b/lib/src/budgeting/budget_over_tree.rs @@ -41,6 +41,11 @@ impl BudgetOverTreeRequest { params.push(("all", "1".to_string())); } else if let Some(project) = self.project { params.push(("project", project.to_string())); + } else if let Some(user) = self.user { + params.push(("user", user.to_string())); + } + if let Some(end) = self.end { + params.push(("end", end.to_string())); } params } From 44da20fb07269b325b9485fbc986a53b3c233ec5 Mon Sep 17 00:00:00 2001 From: Sandro-Alessio Gierens Date: Mon, 16 Dec 2024 01:28:55 +0100 Subject: [PATCH 6/6] chore(sqlx): update offline query data Signed-off-by: Sandro-Alessio Gierens --- ...fc48bb67eba6087d1506de4ec8a967e8f4d1d.json | 44 +++++++++++++++++++ ...6a69a11cba3c7e0adf1eba18165c85b6bd863.json | 34 -------------- 2 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 .sqlx/query-36a8b0c1f2a7c2a6a9a49f1ce65fc48bb67eba6087d1506de4ec8a967e8f4d1d.json delete mode 100644 .sqlx/query-5c957d441d9c8e1a835f3e9dcbb6a69a11cba3c7e0adf1eba18165c85b6bd863.json diff --git a/.sqlx/query-36a8b0c1f2a7c2a6a9a49f1ce65fc48bb67eba6087d1506de4ec8a967e8f4d1d.json b/.sqlx/query-36a8b0c1f2a7c2a6a9a49f1ce65fc48bb67eba6087d1506de4ec8a967e8f4d1d.json new file mode 100644 index 00000000..5cb45c0f --- /dev/null +++ b/.sqlx/query-36a8b0c1f2a7c2a6a9a49f1ce65fc48bb67eba6087d1506de4ec8a967e8f4d1d.json @@ -0,0 +1,44 @@ +{ + "db_name": "MySQL", + "query": "\n SELECT\n id as project__id,\n name as project__name,\n user_class as project__user_class\n FROM user_project AS project\n WHERE project.id = ?\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "project__id", + "type_info": { + "type": "Long", + "flags": "NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT", + "max_size": 11 + } + }, + { + "ordinal": 1, + "name": "project__name", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | NO_DEFAULT_VALUE", + "max_size": 1020 + } + }, + { + "ordinal": 2, + "name": "project__user_class", + "type_info": { + "type": "Short", + "flags": "NOT_NULL | UNSIGNED | NO_DEFAULT_VALUE", + "max_size": 5 + } + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "36a8b0c1f2a7c2a6a9a49f1ce65fc48bb67eba6087d1506de4ec8a967e8f4d1d" +} diff --git a/.sqlx/query-5c957d441d9c8e1a835f3e9dcbb6a69a11cba3c7e0adf1eba18165c85b6bd863.json b/.sqlx/query-5c957d441d9c8e1a835f3e9dcbb6a69a11cba3c7e0adf1eba18165c85b6bd863.json deleted file mode 100644 index 0984f64f..00000000 --- a/.sqlx/query-5c957d441d9c8e1a835f3e9dcbb6a69a11cba3c7e0adf1eba18165c85b6bd863.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "db_name": "MySQL", - "query": "\n SELECT id, name\n FROM user_project AS project\n WHERE project.id = ?\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": { - "type": "Long", - "flags": "NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT", - "max_size": 11 - } - }, - { - "ordinal": 1, - "name": "name", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | UNIQUE_KEY | NO_DEFAULT_VALUE", - "max_size": 1020 - } - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false - ] - }, - "hash": "5c957d441d9c8e1a835f3e9dcbb6a69a11cba3c7e0adf1eba18165c85b6bd863" -}