@@ -382,6 +382,232 @@ defmodule Guard.GrpcServers.ServiceAccountServerTest do
382
382
end
383
383
end
384
384
385
+ describe "describe_many/2" do
386
+ test "describes multiple service accounts successfully" , % { grpc_channel: channel } do
387
+ sa1_id = Ecto.UUID . generate ( )
388
+ sa2_id = Ecto.UUID . generate ( )
389
+ sa3_id = Ecto.UUID . generate ( )
390
+
391
+ with_mocks ( [
392
+ { Guard.Utils , [ :passthrough ] , [ validate_uuid!: fn _ -> :ok end ] } ,
393
+ { Guard.Store.ServiceAccount , [ :passthrough ] ,
394
+ [
395
+ find_many: fn ids ->
396
+ assert length ( ids ) == 3
397
+ assert sa1_id in ids
398
+ assert sa2_id in ids
399
+ assert sa3_id in ids
400
+
401
+ { :ok ,
402
+ [
403
+ % {
404
+ id: sa1_id ,
405
+ name: "Service Account 1" ,
406
+ description: "Description 1" ,
407
+ org_id: "org-id-1" ,
408
+ creator_id: "creator-1" ,
409
+ created_at: DateTime . utc_now ( ) ,
410
+ updated_at: DateTime . utc_now ( ) ,
411
+ deactivated: false
412
+ } ,
413
+ % {
414
+ id: sa2_id ,
415
+ name: "Service Account 2" ,
416
+ description: "Description 2" ,
417
+ org_id: "org-id-2" ,
418
+ creator_id: "creator-2" ,
419
+ created_at: DateTime . utc_now ( ) ,
420
+ updated_at: DateTime . utc_now ( ) ,
421
+ deactivated: true
422
+ } ,
423
+ % {
424
+ id: sa3_id ,
425
+ name: "Service Account 3" ,
426
+ description: nil ,
427
+ org_id: "org-id-3" ,
428
+ creator_id: nil ,
429
+ created_at: DateTime . utc_now ( ) ,
430
+ updated_at: DateTime . utc_now ( ) ,
431
+ deactivated: false
432
+ }
433
+ ] }
434
+ end
435
+ ] }
436
+ ] ) do
437
+ request = ServiceAccount.DescribeManyRequest . new ( sa_ids: [ sa1_id , sa2_id , sa3_id ] )
438
+
439
+ { :ok , response } = channel |> Stub . describe_many ( request )
440
+
441
+ assert length ( response . service_accounts ) == 3
442
+
443
+ # Verify first service account
444
+ sa1 = Enum . find ( response . service_accounts , & ( & 1 . id == sa1_id ) )
445
+ assert sa1 . name == "Service Account 1"
446
+ assert sa1 . description == "Description 1"
447
+ assert sa1 . org_id == "org-id-1"
448
+ assert sa1 . creator_id == "creator-1"
449
+ assert sa1 . deactivated == false
450
+
451
+ # Verify second service account (deactivated)
452
+ sa2 = Enum . find ( response . service_accounts , & ( & 1 . id == sa2_id ) )
453
+ assert sa2 . name == "Service Account 2"
454
+ assert sa2 . deactivated == true
455
+
456
+ # Verify third service account (nil handling)
457
+ sa3 = Enum . find ( response . service_accounts , & ( & 1 . id == sa3_id ) )
458
+ assert sa3 . name == "Service Account 3"
459
+ assert sa3 . description == ""
460
+ assert sa3 . creator_id == ""
461
+ assert sa3 . deactivated == false
462
+ end
463
+ end
464
+
465
+ test "returns empty list when no service accounts found" , % { grpc_channel: channel } do
466
+ sa1_id = Ecto.UUID . generate ( )
467
+ sa2_id = Ecto.UUID . generate ( )
468
+
469
+ with_mocks ( [
470
+ { Guard.Utils , [ :passthrough ] , [ validate_uuid!: fn _ -> :ok end ] } ,
471
+ { Guard.Store.ServiceAccount , [ :passthrough ] ,
472
+ [
473
+ find_many: fn ids ->
474
+ assert length ( ids ) == 2
475
+ { :ok , [ ] }
476
+ end
477
+ ] }
478
+ ] ) do
479
+ request = ServiceAccount.DescribeManyRequest . new ( sa_ids: [ sa1_id , sa2_id ] )
480
+
481
+ { :ok , response } = channel |> Stub . describe_many ( request )
482
+
483
+ assert response . service_accounts == [ ]
484
+ end
485
+ end
486
+
487
+ test "handles partial matches correctly" , % { grpc_channel: channel } do
488
+ existing_id = Ecto.UUID . generate ( )
489
+ non_existent_id = Ecto.UUID . generate ( )
490
+
491
+ with_mocks ( [
492
+ { Guard.Utils , [ :passthrough ] , [ validate_uuid!: fn _ -> :ok end ] } ,
493
+ { Guard.Store.ServiceAccount , [ :passthrough ] ,
494
+ [
495
+ find_many: fn ids ->
496
+ assert length ( ids ) == 2
497
+ assert existing_id in ids
498
+ assert non_existent_id in ids
499
+
500
+ # Return only the existing one
501
+ { :ok ,
502
+ [
503
+ % {
504
+ id: existing_id ,
505
+ name: "Existing SA" ,
506
+ description: "Exists" ,
507
+ org_id: "org-id" ,
508
+ creator_id: "creator-id" ,
509
+ created_at: DateTime . utc_now ( ) ,
510
+ updated_at: DateTime . utc_now ( ) ,
511
+ deactivated: false
512
+ }
513
+ ] }
514
+ end
515
+ ] }
516
+ ] ) do
517
+ request = ServiceAccount.DescribeManyRequest . new ( sa_ids: [ existing_id , non_existent_id ] )
518
+
519
+ { :ok , response } = channel |> Stub . describe_many ( request )
520
+
521
+ assert length ( response . service_accounts ) == 1
522
+ assert hd ( response . service_accounts ) . id == existing_id
523
+ end
524
+ end
525
+
526
+ test "handles empty input list" , % { grpc_channel: channel } do
527
+ with_mocks ( [
528
+ { Guard.Store.ServiceAccount , [ :passthrough ] ,
529
+ [
530
+ find_many: fn ids ->
531
+ assert ids == [ ]
532
+ { :ok , [ ] }
533
+ end
534
+ ] }
535
+ ] ) do
536
+ request = ServiceAccount.DescribeManyRequest . new ( sa_ids: [ ] )
537
+
538
+ { :ok , response } = channel |> Stub . describe_many ( request )
539
+
540
+ assert response . service_accounts == [ ]
541
+ end
542
+ end
543
+
544
+ test "validates UUID format for all IDs" , % { grpc_channel: channel } do
545
+ valid_id = Ecto.UUID . generate ( )
546
+
547
+ request = ServiceAccount.DescribeManyRequest . new ( sa_ids: [ valid_id , "invalid-uuid" ] )
548
+
549
+ { :error , % GRPC.RPCError { status: 3 } } = channel |> Stub . describe_many ( request )
550
+ end
551
+
552
+ test "handles internal errors" , % { grpc_channel: channel } do
553
+ sa_id = Ecto.UUID . generate ( )
554
+
555
+ with_mocks ( [
556
+ { Guard.Utils , [ :passthrough ] , [ validate_uuid!: fn _ -> :ok end ] } ,
557
+ { Guard.Store.ServiceAccount , [ :passthrough ] ,
558
+ [
559
+ find_many: fn _ -> { :error , :database_error } end
560
+ ] }
561
+ ] ) do
562
+ request = ServiceAccount.DescribeManyRequest . new ( sa_ids: [ sa_id ] )
563
+
564
+ { :error , % GRPC.RPCError { status: 13 , message: message } } =
565
+ channel |> Stub . describe_many ( request )
566
+
567
+ assert String . contains? ( message , "Failed to describe service accounts" )
568
+ end
569
+ end
570
+
571
+ test "handles large number of IDs" , % { grpc_channel: channel } do
572
+ # Generate 50 IDs to test batch processing
573
+ ids = for _ <- 1 .. 50 , do: Ecto.UUID . generate ( )
574
+
575
+ with_mocks ( [
576
+ { Guard.Utils , [ :passthrough ] , [ validate_uuid!: fn _ -> :ok end ] } ,
577
+ { Guard.Store.ServiceAccount , [ :passthrough ] ,
578
+ [
579
+ find_many: fn received_ids ->
580
+ assert length ( received_ids ) == 50
581
+ # Return only the first 10 to simulate partial results
582
+ service_accounts =
583
+ received_ids
584
+ |> Enum . take ( 10 )
585
+ |> Enum . map ( fn id ->
586
+ % {
587
+ id: id ,
588
+ name: "SA #{ id } " ,
589
+ description: "Description" ,
590
+ org_id: "org-id" ,
591
+ creator_id: "creator-id" ,
592
+ created_at: DateTime . utc_now ( ) ,
593
+ updated_at: DateTime . utc_now ( ) ,
594
+ deactivated: false
595
+ }
596
+ end )
597
+
598
+ { :ok , service_accounts }
599
+ end
600
+ ] }
601
+ ] ) do
602
+ request = ServiceAccount.DescribeManyRequest . new ( sa_ids: ids )
603
+
604
+ { :ok , response } = channel |> Stub . describe_many ( request )
605
+
606
+ assert length ( response . service_accounts ) == 10
607
+ end
608
+ end
609
+ end
610
+
385
611
describe "update/2" do
386
612
test "updates service account successfully" , % { grpc_channel: channel } do
387
613
service_account_id = Ecto.UUID . generate ( )
0 commit comments