@@ -11,6 +11,7 @@ use crate::db::model::RendezvousDebugDataset;
11
11
use crate :: db:: model:: SupportBundle ;
12
12
use crate :: db:: model:: SupportBundleState ;
13
13
use crate :: db:: pagination:: paginated;
14
+ use crate :: db:: pagination:: paginated_multicolumn;
14
15
use crate :: db:: update_and_check:: { UpdateAndCheck , UpdateStatus } ;
15
16
use async_bb8_diesel:: AsyncRunQueryDsl ;
16
17
use diesel:: prelude:: * ;
@@ -166,21 +167,25 @@ impl DataStore {
166
167
Ok ( db_bundle)
167
168
}
168
169
169
- /// Lists one page of support bundles
170
+ /// Lists one page of support bundles ordered by creation time
170
171
pub async fn support_bundle_list (
171
172
& self ,
172
173
opctx : & OpContext ,
173
- pagparams : & DataPageParams < ' _ , Uuid > ,
174
+ pagparams : & DataPageParams < ' _ , ( chrono :: DateTime < chrono :: Utc > , Uuid ) > ,
174
175
) -> ListResultVec < SupportBundle > {
175
176
opctx. authorize ( authz:: Action :: Read , & authz:: FLEET ) . await ?;
176
177
use nexus_db_schema:: schema:: support_bundle:: dsl;
177
178
178
179
let conn = self . pool_connection_authorized ( opctx) . await ?;
179
- paginated ( dsl:: support_bundle, dsl:: id, pagparams)
180
- . select ( SupportBundle :: as_select ( ) )
181
- . load_async ( & * conn)
182
- . await
183
- . map_err ( |e| public_error_from_diesel ( e, ErrorHandler :: Server ) )
180
+ paginated_multicolumn (
181
+ dsl:: support_bundle,
182
+ ( dsl:: time_created, dsl:: id) ,
183
+ pagparams,
184
+ )
185
+ . select ( SupportBundle :: as_select ( ) )
186
+ . load_async ( & * conn)
187
+ . await
188
+ . map_err ( |e| public_error_from_diesel ( e, ErrorHandler :: Server ) )
184
189
}
185
190
186
191
/// Lists one page of support bundles in a particular state, assigned to
@@ -1417,4 +1422,70 @@ mod test {
1417
1422
db. terminate ( ) . await ;
1418
1423
logctx. cleanup_successful ( ) ;
1419
1424
}
1425
+
1426
+ #[ tokio:: test]
1427
+ async fn test_bundle_list_time_ordering ( ) {
1428
+ let logctx = dev:: test_setup_log ( "test_bundle_list_time_ordering" ) ;
1429
+ let db = TestDatabase :: new_with_datastore ( & logctx. log ) . await ;
1430
+ let ( opctx, datastore) = ( db. opctx ( ) , db. datastore ( ) ) ;
1431
+
1432
+ let _test_sled = create_sled_and_zpools ( & datastore, & opctx, 3 ) . await ;
1433
+ let this_nexus_id = OmicronZoneUuid :: new_v4 ( ) ;
1434
+
1435
+ // Create multiple bundles with slight time delays to ensure different creation times
1436
+ let mut bundle_ids = Vec :: new ( ) ;
1437
+ let mut bundle_times = Vec :: new ( ) ;
1438
+
1439
+ for _i in 0 ..3 {
1440
+ let bundle = datastore
1441
+ . support_bundle_create (
1442
+ & opctx,
1443
+ "Bundle for time ordering test" ,
1444
+ this_nexus_id,
1445
+ )
1446
+ . await
1447
+ . expect ( "Should be able to create bundle" ) ;
1448
+ bundle_ids. push ( bundle. id ) ;
1449
+ bundle_times. push ( bundle. time_created ) ;
1450
+
1451
+ // Small delay to ensure different creation times
1452
+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_millis ( 10 ) ) . await ;
1453
+ }
1454
+
1455
+ // List bundles using time-based pagination
1456
+ let pagparams = DataPageParams :: max_page ( ) ;
1457
+ let observed_bundles = datastore
1458
+ . support_bundle_list ( & opctx, & pagparams)
1459
+ . await
1460
+ . expect ( "Should be able to list bundles" ) ;
1461
+
1462
+ assert_eq ! ( 3 , observed_bundles. len( ) ) ;
1463
+
1464
+ // Verify bundles are ordered by creation time (ascending)
1465
+ for i in 0 ..observed_bundles. len ( ) - 1 {
1466
+ assert ! (
1467
+ observed_bundles[ i] . time_created
1468
+ <= observed_bundles[ i + 1 ] . time_created,
1469
+ "Bundles should be ordered by creation time (ascending). Bundle at index {} has time {:?}, but bundle at index {} has time {:?}" ,
1470
+ i,
1471
+ observed_bundles[ i] . time_created,
1472
+ i + 1 ,
1473
+ observed_bundles[ i + 1 ] . time_created
1474
+ ) ;
1475
+ }
1476
+
1477
+ // Verify that the bundles are our created bundles
1478
+ let returned_ids: Vec < _ > =
1479
+ observed_bundles. iter ( ) . map ( |b| b. id ) . collect ( ) ;
1480
+ for bundle_id in & bundle_ids {
1481
+ assert ! (
1482
+ returned_ids. contains( bundle_id) ,
1483
+ "Bundle ID {:?} should be in the returned list" ,
1484
+ bundle_id
1485
+ ) ;
1486
+ }
1487
+
1488
+ db. terminate ( ) . await ;
1489
+ logctx. cleanup_successful ( ) ;
1490
+ }
1420
1491
}
0 commit comments