11use crate :: utils:: DisplayVec ;
2- use goose:: goose:: { GooseMethod , GooseRequest , GooseUser , TransactionResult } ;
2+ use goose:: goose:: { GooseMethod , GooseRequest , GooseUser , TransactionError , TransactionResult } ;
33use reqwest:: { Client , RequestBuilder } ;
44
5+ use rand:: Rng ;
56use serde_json:: json;
67use std:: sync:: {
78 Arc ,
89 atomic:: { AtomicUsize , Ordering } ,
910} ;
11+ use tokio:: sync:: OnceCell ;
1012use urlencoding:: encode;
1113
14+ // Static variable to store advisory total count
15+ static ADVISORY_TOTAL : OnceCell < u64 > = OnceCell :: const_new ( ) ;
16+
1217pub async fn get_advisory ( id : String , user : & mut GooseUser ) -> TransactionResult {
1318 let uri = format ! ( "/api/v2/advisory/{}" , encode( & format!( "urn:uuid:{}" , id) ) ) ;
1419
@@ -46,6 +51,46 @@ pub async fn list_advisory(user: &mut GooseUser) -> TransactionResult {
4651 Ok ( ( ) )
4752}
4853
54+ /// Get advisory total count and store it in static OnceCell
55+ async fn get_advisory_total ( user : & mut GooseUser ) -> Result < u64 , Box < TransactionError > > {
56+ let response = user. get ( "/api/v2/advisory" ) . await ?;
57+ let json_data = response. response ?. json :: < serde_json:: Value > ( ) . await ?;
58+
59+ // Extract total from the response
60+ if let Some ( total) = json_data. get ( "total" ) . and_then ( |t| t. as_u64 ( ) ) {
61+ log:: info!( "Advisory total count: {}" , total) ;
62+ return Ok ( total) ;
63+ }
64+
65+ Err ( Box :: new ( TransactionError :: Custom (
66+ "Failed to get advisory total count" . to_string ( ) ,
67+ ) ) )
68+ }
69+
70+ /// Get cached advisory total count, fetch if not available using get_or_init
71+ async fn get_cached_advisory_total ( user : & mut GooseUser ) -> Result < u64 , Box < TransactionError > > {
72+ // Try to get from cache first
73+ if let Some ( & total) = ADVISORY_TOTAL . get ( ) {
74+ return Ok ( total) ;
75+ }
76+
77+ // If not cached, fetch it and handle errors properly
78+ match get_advisory_total ( user) . await {
79+ Ok ( total) => {
80+ // Store in cache for future use
81+ let _ = ADVISORY_TOTAL . set ( total) ;
82+ Ok ( total)
83+ }
84+ Err ( e) => {
85+ // Propagate the error with context instead of silently returning 0
86+ Err ( Box :: new ( TransactionError :: Custom ( format ! (
87+ "Failed to get advisory total count: {}" ,
88+ e
89+ ) ) ) )
90+ }
91+ }
92+ }
93+
4994pub async fn list_advisory_paginated ( user : & mut GooseUser ) -> TransactionResult {
5095 let _response = user. get ( "/api/v2/advisory?offset=100&limit=10" ) . await ?;
5196
@@ -69,6 +114,37 @@ pub async fn search_advisory(user: &mut GooseUser) -> TransactionResult {
69114 Ok ( ( ) )
70115}
71116
117+ /// List advisory with random offset and limit=1, return advisory ID
118+ async fn list_advisory_random_single (
119+ user : & mut GooseUser ,
120+ ) -> Result < String , Box < TransactionError > > {
121+ let total = get_cached_advisory_total ( user) . await ?;
122+ // Generate random offset
123+ let offset = rand:: thread_rng ( ) . gen_range ( 0 ..=total) ;
124+ let url = format ! ( "/api/v2/advisory?offset={}&limit=1" , offset) ;
125+
126+ let response = user. get ( & url) . await ?;
127+ let json_data = response. response ?. json :: < serde_json:: Value > ( ) . await ?;
128+
129+ // Extract advisory ID from the response
130+ if let Some ( items) = json_data. get ( "items" ) . and_then ( |i| i. as_array ( ) ) {
131+ if let Some ( first_item) = items. first ( ) {
132+ if let Some ( id) = first_item. get ( "uuid" ) . and_then ( |u| u. as_str ( ) ) {
133+ log:: info!( "Listing advisory with offset {}: {}" , offset, id) ;
134+ return Ok ( id. to_string ( ) ) ;
135+ }
136+ }
137+ }
138+
139+ // Return error if no advisory found
140+ Err ( Box :: new ( TransactionError :: Custom ( format ! (
141+ "No advisory found at offset: {}" ,
142+ offset
143+ ) ) ) )
144+ }
145+
146+ //
147+
72148/// Send Advisory labels request
73149async fn send_advisory_label_request (
74150 advisory_id : String ,
@@ -99,13 +175,10 @@ async fn send_advisory_label_request(
99175}
100176
101177/// Send Advisory labels request using PUT method
102- pub async fn put_advisory_labels (
103- advisory_ids : Vec < String > ,
104- counter : Arc < AtomicUsize > ,
105- user : & mut GooseUser ,
106- ) -> TransactionResult {
178+ pub async fn put_advisory_labels ( user : & mut GooseUser ) -> TransactionResult {
179+ let advisory_id = list_advisory_random_single ( user) . await ?;
107180 send_advisory_label_request (
108- advisory_ids [ counter . fetch_add ( 1 , Ordering :: Relaxed ) % advisory_ids . len ( ) ] . clone ( ) ,
181+ advisory_id ,
109182 user,
110183 GooseMethod :: Put ,
111184 "It's a put request" ,
@@ -115,13 +188,10 @@ pub async fn put_advisory_labels(
115188}
116189
117190/// Send Advisory labels request using PATCH method
118- pub async fn patch_advisory_labels (
119- advisory_ids : Vec < String > ,
120- counter : Arc < AtomicUsize > ,
121- user : & mut GooseUser ,
122- ) -> TransactionResult {
191+ pub async fn patch_advisory_labels ( user : & mut GooseUser ) -> TransactionResult {
192+ let advisory_id = list_advisory_random_single ( user) . await ?;
123193 send_advisory_label_request (
124- advisory_ids [ counter . fetch_add ( 1 , Ordering :: Relaxed ) % advisory_ids . len ( ) ] . clone ( ) ,
194+ advisory_id ,
125195 user,
126196 GooseMethod :: Patch ,
127197 "It's a patch request" ,
0 commit comments