Skip to content

Commit 339d6a9

Browse files
committed
test: add delete SBOM scale test (TC-3020)
Signed-off-by: mrizzi <mrizzi@redhat.com> Assisted-by: Claude Code
1 parent 53c396b commit 339d6a9

File tree

5 files changed

+244
-7
lines changed

5 files changed

+244
-7
lines changed

empty.json5

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@
99
"sbom_by_package": null,
1010
"sbom_license_ids": null,
1111
"analyze_purl": null,
12+
"get_purl_details": null,
13+
"delete_sbom_pool": null,
1214
}

scenarios/full-20250604.json5

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,107 @@
99
"sbom_license_ids": "urn:uuid:01973124-d4ab-7163-b104-331632a21144",
1010
"analyze_purl": "pkg:rpm/redhat/eap7-activemq-artemis-native@1.0.2-3.redhat_00004.1.el7eap?arch=noarch&epoch=1",
1111
"get_purl_details": "b00df2ca-df21-5c10-8874-304e9c54e2bd",
12-
"get_recommendations": ["pkg:rpm/redhat/eap7-activemq-artemis-native@1.0.2, pkg:maven/io.quarkus/quarkus-smallrye-metrics@2.13.8"]
12+
"get_recommendations": ["pkg:rpm/redhat/eap7-activemq-artemis-native@1.0.2, pkg:maven/io.quarkus/quarkus-smallrye-metrics@2.13.8"],
13+
"delete_sbom_pool": [
14+
"urn:uuid:01973121-1e94-7112-8bb3-636be0596bdb",
15+
"urn:uuid:01973121-221a-78b0-93ff-4dea01eeaaf7",
16+
"urn:uuid:01973121-251a-70b2-8bec-6c271300128a",
17+
"urn:uuid:01973121-28aa-78d2-b150-8c2e59c8f346",
18+
"urn:uuid:01973121-2be1-7a90-9dcf-9ffd8f324586",
19+
"urn:uuid:01973121-2ecb-7ed3-bdd4-7db215134b77",
20+
"urn:uuid:01973121-3260-7290-8100-227265538de2",
21+
"urn:uuid:01973121-357e-7992-a4b4-dd4076a937fc",
22+
"urn:uuid:01973121-38b1-7760-939e-763b1ddcbf45",
23+
"urn:uuid:01973121-3d67-72c3-a505-62c81ff63baa",
24+
"urn:uuid:01973121-411e-7af0-969b-b4a5f9f84d1f",
25+
"urn:uuid:01973121-4378-7be3-8fb9-da2c6544289c",
26+
"urn:uuid:01973121-464f-76c2-b07e-13d2ecc4eadb",
27+
"urn:uuid:01973121-4998-7d32-bb8b-de8f1e2bc2c4",
28+
"urn:uuid:01973121-4c82-7c11-8074-641e83eed0c5",
29+
"urn:uuid:01973121-4f39-7a90-be4b-4a0d3cfab6f1",
30+
"urn:uuid:01973121-5337-78a2-a8eb-63fe7d106e9e",
31+
"urn:uuid:01973121-5613-7412-8365-6bf9ca9164ae",
32+
"urn:uuid:01973121-590f-7952-8853-f6424188fcd8",
33+
"urn:uuid:01973121-5c6b-7122-a46f-1025dedbe8dd",
34+
"urn:uuid:01973121-5f4c-7d81-8239-001ebe99a389",
35+
"urn:uuid:01973121-6289-72f2-95a9-0c16bb2724e9",
36+
"urn:uuid:01973121-6648-73f3-9e35-2af740a2563a",
37+
"urn:uuid:01973121-6923-7432-9e12-eddae207f35b",
38+
"urn:uuid:01973121-6c4b-7981-b4c2-74650cf09c5e",
39+
"urn:uuid:01973121-6ed1-7051-a0c4-f83a43145f78",
40+
"urn:uuid:01973121-7160-7650-8e5f-ced7c80a5509",
41+
"urn:uuid:01973121-74ca-7762-8136-b848dfb7c7ce",
42+
"urn:uuid:01973121-771a-7cf3-84f2-f91e87306f71",
43+
"urn:uuid:01973121-7acd-7dc1-97fa-43e682a630b9",
44+
"urn:uuid:01973121-7cc5-7d02-bb40-e14421a84dfc",
45+
"urn:uuid:01973121-7f7a-7693-80d4-ed2be905fc8a",
46+
"urn:uuid:01973121-81fa-7d73-a44d-3258e2de289e",
47+
"urn:uuid:01973121-85a8-7fb2-870b-e4ff0de62fa4",
48+
"urn:uuid:01973121-8864-7233-a3f8-e67717cd8083",
49+
"urn:uuid:01973121-8bcd-7643-bccd-2526723de5a6",
50+
"urn:uuid:01973121-8f78-7b90-804b-414ea1456aba",
51+
"urn:uuid:01973121-920b-7943-adfb-7b95defc881a",
52+
"urn:uuid:01973121-9433-7d51-bc03-d55148b3204b",
53+
"urn:uuid:01973121-9640-7491-8790-6695164cb1c1",
54+
"urn:uuid:01973121-9903-7c60-9b28-71d4d79a3e6c",
55+
"urn:uuid:01973121-9bb0-7ef2-ab8e-53fe530a691e",
56+
"urn:uuid:01973121-9e14-7f31-a2b5-a2de14572ce9",
57+
"urn:uuid:01973121-a058-78e1-9e17-47c267a5fc03",
58+
"urn:uuid:01973121-a29b-7c13-b01c-c98b3d0f7412",
59+
"urn:uuid:01973121-a564-7280-92c4-0855e6e39ee6",
60+
"urn:uuid:01973121-a908-7932-868c-2b52e99b0b40",
61+
"urn:uuid:01973121-ab8b-7d21-b1fa-ce2a60703e24",
62+
"urn:uuid:01973121-b01c-7af1-8b80-bf65d202e29f",
63+
"urn:uuid:01973121-b4c8-72a0-ad3e-100a67b746a5",
64+
"urn:uuid:01973121-b7d0-7220-8e76-b57269b9d513",
65+
"urn:uuid:01973121-bad1-7d02-8bac-6d72a7d43ceb",
66+
"urn:uuid:01973121-bdb1-7b80-94d3-237352b2f4cb",
67+
"urn:uuid:01973121-bfe5-7eb3-b36a-711052c70f2b",
68+
"urn:uuid:01973121-c364-7823-8f99-ad819bd2e732",
69+
"urn:uuid:01973121-c652-76e3-8fca-70184db024fd",
70+
"urn:uuid:01973121-ca20-7e33-93a3-2bbd9e2eb33d",
71+
"urn:uuid:01973121-cca9-7aa2-bf2f-216c1de8f8aa",
72+
"urn:uuid:01973121-cf27-7ef3-97b1-e6d6f7f52fc5",
73+
"urn:uuid:01973121-d1fd-7480-825f-2ec926c083d4",
74+
"urn:uuid:01973121-d56e-7922-b3d6-32ebc11f0a16",
75+
"urn:uuid:01973121-d7a6-7883-97b3-012dc4da2123",
76+
"urn:uuid:01973121-da3e-72a0-af50-09a71b641159",
77+
"urn:uuid:01973121-dc0c-7ce1-8763-6ea41ef06586",
78+
"urn:uuid:01973121-dea4-7091-8418-ac150303c1ef",
79+
"urn:uuid:01973121-e20b-72c1-b3d7-8d691a949ce7",
80+
"urn:uuid:01973121-e49a-75d3-941f-8b276222b98c",
81+
"urn:uuid:01973121-e720-7920-bb60-3b935df74219",
82+
"urn:uuid:01973121-ea0d-7102-8dbb-22159c7e8f7c",
83+
"urn:uuid:01973121-ecba-7100-9f1a-9ed0fff0b020",
84+
"urn:uuid:01973121-ef23-76a2-b2ab-352f1bf14b7e",
85+
"urn:uuid:01973121-f0e9-7e21-bfdd-f1b6129f98df",
86+
"urn:uuid:01973121-f427-70d1-b91e-6d3018e3e492",
87+
"urn:uuid:01973121-f68d-72c2-863e-c181bf67ba00",
88+
"urn:uuid:01973121-f914-7c92-9fc5-48fae8dc9599",
89+
"urn:uuid:01973121-fb6e-7ce0-8068-685b8242f775",
90+
"urn:uuid:01973121-fd88-7ff0-9539-1d95f4c8c1fa",
91+
"urn:uuid:01973121-ffba-7432-86fa-5ec42dc4749a",
92+
"urn:uuid:01973122-032a-7563-baf9-c9d8ac99749c",
93+
"urn:uuid:01973122-069b-71f3-b9de-849bb2d94ea7",
94+
"urn:uuid:01973122-0a83-7112-a519-ab748ed33687",
95+
"urn:uuid:01973122-0ce6-7910-8175-841f1f619b0e",
96+
"urn:uuid:01973122-0eef-70a3-9438-1f09fb8007e3",
97+
"urn:uuid:01973122-1111-7c20-bb2a-bea6df54e126",
98+
"urn:uuid:01973122-157a-7173-8476-7fd47e8cb4ce",
99+
"urn:uuid:01973122-1858-7ff3-b830-ab9e61861134",
100+
"urn:uuid:01973122-1b3e-7b02-9189-fd947ad9295c",
101+
"urn:uuid:01973122-1f2e-73a3-b9eb-7556dfb451a1",
102+
"urn:uuid:01973122-21b1-7851-bd7e-4f439a7ae659",
103+
"urn:uuid:01973122-2442-73a3-b250-d8a41f7884ff",
104+
"urn:uuid:01973122-2666-7fa1-ad92-592f5619856a",
105+
"urn:uuid:01973122-299b-74a2-a8a0-98b00e04f48f",
106+
"urn:uuid:01973122-2cc3-70d2-8ae7-f2656277727e",
107+
"urn:uuid:01973122-2f62-7160-b580-733d6b2f11dc",
108+
"urn:uuid:01973122-31ea-74c0-823d-25e422efcb00",
109+
"urn:uuid:01973122-3428-7641-b3ed-9eb0b834f830",
110+
"urn:uuid:01973122-3666-7823-bb4b-d3f610d1820b",
111+
"urn:uuid:01973122-384d-7002-886f-11dddf5040ad",
112+
"urn:uuid:01973122-3a0e-73f0-9596-baceb84383aa",
113+
"urn:uuid:01973122-3bdd-78a3-898a-fb67c06387ed"
114+
]
13115
}

src/main.rs

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,72 @@ const MAX_ID_DISPLAY: usize = 32;
2121

2222
/// Define a transaction and use its function identifier as name
2323
macro_rules! tx {
24+
// No params
2425
($n:ident) => {
2526
transaction!($n).set_name(stringify!($n))
2627
};
28+
29+
// 1 param, auto display (redirects to custom display with auto-generated name)
2730
($n:ident($v1:expr)) => {{
31+
tx!($n($v1), name: &format!("{}[{}]", stringify!($n), utils::truncate_middle($v1, MAX_ID_DISPLAY)))
32+
}};
33+
34+
// 1 param, custom display
35+
($n:ident($v1:expr), name: $display:expr) => {{
2836
let v1 = ($v1).clone();
37+
let display = $display;
2938
Transaction::new(Arc::new({
3039
let v1 = v1.clone();
3140
move |s| Box::pin($n(v1.clone(), s))
3241
}))
33-
.set_name(&format!(
34-
"{}[{}]",
35-
stringify!($n),
36-
utils::truncate_middle(v1, MAX_ID_DISPLAY)
37-
))
42+
.set_name(&display)
43+
}};
44+
45+
// 2 params, auto display
46+
($n:ident($v1:expr, $v2:expr)) => {{
47+
tx!($n($v1, $v2), name: &format!("{}[{}]", stringify!($n), utils::truncate_middle($v1, MAX_ID_DISPLAY)))
48+
}};
49+
50+
// 2 params, custom display
51+
($n:ident($v1:expr, $v2:expr), name: $display:expr) => {{
52+
let v1 = ($v1).clone();
53+
let v2 = ($v2).clone();
54+
let display = $display;
55+
Transaction::new(Arc::new({
56+
let v1 = v1.clone();
57+
let v2 = v2.clone();
58+
move |s| Box::pin($n(v1.clone(), v2.clone(), s))
59+
}))
60+
.set_name(&display)
3861
}};
62+
63+
// Optional, 1 param, auto display
3964
($s:ident.$n:ident?($v1:expr)) => {
4065
if let Some(value) = ($v1).clone() {
4166
$s = $s.register_transaction(tx!($n(value.clone())));
4267
}
4368
};
69+
70+
// Optional, 1 param, custom display
71+
($s:ident.$n:ident?($v1:expr), name: $display:expr) => {
72+
if let Some(value) = ($v1).clone() {
73+
$s = $s.register_transaction(tx!($n(value.clone()), name: $display));
74+
}
75+
};
76+
77+
// Optional, 2 params, auto display
78+
($s:ident.$n:ident?($v1:expr, $v2:expr)) => {
79+
if let Some(value) = ($v1).clone() {
80+
$s = $s.register_transaction(tx!($n(value.clone(), $v2)));
81+
}
82+
};
83+
84+
// Optional, 2 params, custom display
85+
($s:ident.$n:ident?($v1:expr, $v2:expr), name: $display:expr) => {
86+
if let Some(value) = ($v1).clone() {
87+
$s = $s.register_transaction(tx!($n(value.clone(), $v2), name: $display));
88+
}
89+
};
4490
}
4591

4692
#[tokio::main]
@@ -78,6 +124,9 @@ async fn main() -> Result<(), anyhow::Error> {
78124
})))
79125
};
80126

127+
// Create atomic counter for sequential delete strategy
128+
let delete_counter = Arc::new(std::sync::atomic::AtomicUsize::new(0));
129+
81130
GooseAttack::initialize()?
82131
.test_start(
83132
Transaction::new(Arc::new({
@@ -150,13 +199,32 @@ async fn main() -> Result<(), anyhow::Error> {
150199
"RestAPIUserSlow",
151200
wait_time_from,
152201
wait_time_to,
153-
custom_client,
202+
custom_client.clone(),
154203
)?
155204
.set_weight(1)?
156205
.register_transaction(tx!(search_licenses))
157206
.register_transaction(tx!(search_sboms_by_license))
158207
.register_transaction(tx!(search_purls_by_license))
159208
})
209+
.register_scenario({
210+
let mut s = create_scenario(
211+
"RestAPIUserDelete",
212+
wait_time_from,
213+
wait_time_to,
214+
custom_client,
215+
)?
216+
.set_weight(1)?
217+
// With 100 SBOM IDs this ensure they all delete something in the sequential situation
218+
.set_wait_time(Duration::from_secs(3), Duration::from_secs(4))?;
219+
// Register delete transaction if pool is available
220+
if let Some(pool) = scenario.delete_sbom_pool.clone() {
221+
tx!(s.delete_sbom_from_pool_sequential?(
222+
scenario.delete_sbom_pool.clone(),
223+
delete_counter.clone()
224+
), name: format!("delete_sbom_from_pool_sequential[{} SBOMs]", pool.len()))
225+
}
226+
s
227+
})
160228
// .register_scenario(
161229
// scenario!("GraphQLUser")
162230
// // .set_weight(1)?

src/restapi.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use goose::goose::{GooseUser, TransactionResult};
22
use serde_json::json;
3+
use std::sync::{
4+
Arc,
5+
atomic::{AtomicUsize, Ordering},
6+
};
37
use urlencoding::encode;
48

59
use crate::utils::DisplayVec;
@@ -219,3 +223,19 @@ pub async fn get_recommendations(
219223
.await?;
220224
Ok(())
221225
}
226+
227+
/// Delete an SBOM by ID from a pre-populated pool using sequential iteration
228+
/// Sequentially iterates through the pool using an atomic counter
229+
pub async fn delete_sbom_from_pool_sequential(
230+
pool: Vec<String>,
231+
counter: Arc<AtomicUsize>,
232+
user: &mut GooseUser,
233+
) -> TransactionResult {
234+
// Get next index atomically and increment, wrapping around pool size
235+
let index = counter.fetch_add(1, Ordering::Relaxed);
236+
if index < pool.len() {
237+
let sbom_id = &pool[index];
238+
let _response = user.delete(&format!("/api/v2/sbom/{sbom_id}")).await?;
239+
}
240+
Ok(())
241+
}

src/scenario/mod.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ pub(crate) struct Scenario {
9393
pub get_purl_details: Option<String>,
9494

9595
pub get_recommendations: Option<DisplayVec<String>>,
96+
97+
#[serde(default, skip_serializing_if = "Option::is_none")]
98+
pub delete_sbom_pool: Option<Vec<String>>,
9699
}
97100

98101
impl Scenario {
@@ -124,6 +127,14 @@ impl Scenario {
124127
let analyze_purl = Some(loader.analysis_purl().await?);
125128
let get_purl_details = Some(loader.purl_details().await?);
126129
let recommendations_purl = Some(loader.purl_with_recommendations().await?);
130+
let delete_sbom_pool = Some(
131+
loader
132+
.deletable_sboms()
133+
.await?
134+
.iter()
135+
.map(|sbom_id| format!("urn:uuid:{sbom_id}"))
136+
.collect(),
137+
);
127138

128139
Ok(Self {
129140
get_sbom: large_sbom_digest.clone(),
@@ -138,6 +149,7 @@ impl Scenario {
138149
analyze_purl,
139150
get_purl_details,
140151
get_recommendations: recommendations_purl,
152+
delete_sbom_pool,
141153
})
142154
}
143155
}
@@ -311,6 +323,39 @@ LIMIT 10;
311323
Ok(DisplayVec(result))
312324
})
313325
}
326+
327+
/// Get a pool of deletable SBOMs (up to 100)
328+
/// These SBOMs are selected based on having certain licenses that make them good candidates for deletion testing
329+
pub async fn deletable_sboms(&self) -> anyhow::Result<Vec<String>> {
330+
let mut db = crate::db::connect(&self.db).await?;
331+
332+
let rows = sqlx::query(
333+
r#"
334+
SELECT
335+
a.sbom_id::text as id
336+
FROM
337+
sbom a
338+
JOIN sbom_node b ON a.sbom_id = b.sbom_id
339+
JOIN sbom_package c ON b.sbom_id = c.sbom_id AND b.node_id = c.node_id
340+
JOIN sbom_package_license d ON c.sbom_id = d.sbom_id AND c.node_id = d.node_id
341+
JOIN license e ON d.license_id = e.id
342+
WHERE
343+
e.text IN ('GPLv3+ with exceptions', 'Apache-2.0', 'MIT', 'BSD-3-Clause')
344+
GROUP BY
345+
a.sbom_id
346+
ORDER BY
347+
a.sbom_id
348+
LIMIT 100
349+
"#,
350+
)
351+
.fetch_all(&mut db)
352+
.await?;
353+
354+
Ok(rows
355+
.into_iter()
356+
.map(|row| row.get::<String, _>("id"))
357+
.collect())
358+
}
314359
}
315360

316361
#[cfg(test)]

0 commit comments

Comments
 (0)