@@ -335,6 +335,27 @@ TEST_F(CmdShowTransceiverTestFixture, queryClient) {
335335 auto model = cmd.queryClient (localhost (), queriedEntries);
336336
337337 EXPECT_THRIFT_EQ (normalizedModel, model);
338+
339+ // Verify that the model contains all transceivers including bypass modules
340+ EXPECT_EQ (model.transceivers ()->size (), 8 );
341+
342+ // Verify bypass module (transceiver 7) is present
343+ EXPECT_TRUE (
344+ model.transceivers ()->find (" eth1/7/1" ) != model.transceivers ()->end ());
345+ auto & bypassModule = model.transceivers ()->at (" eth1/7/1" );
346+ EXPECT_EQ (bypassModule.name ().value (), " eth1/7/1" );
347+ EXPECT_FALSE (
348+ bypassModule.isUp ().has_value ()); // Bypass modules have no port status
349+ EXPECT_TRUE (bypassModule.isPresent ().value ());
350+ EXPECT_EQ (bypassModule.vendor ().value (), " vendorBypass" );
351+
352+ // Verify absent bypass module (transceiver 8) is present
353+ EXPECT_TRUE (
354+ model.transceivers ()->find (" eth1/8/1" ) != model.transceivers ()->end ());
355+ auto & absentBypassModule = model.transceivers ()->at (" eth1/8/1" );
356+ EXPECT_EQ (absentBypassModule.name ().value (), " eth1/8/1" );
357+ EXPECT_FALSE (absentBypassModule.isUp ().has_value ());
358+ EXPECT_FALSE (absentBypassModule.isPresent ().value ());
338359}
339360
340361TEST_F (CmdShowTransceiverTestFixture, queryClientFilteredByPort) {
@@ -350,8 +371,9 @@ TEST_F(CmdShowTransceiverTestFixture, queryClientFilteredByPort) {
350371 // getPortStatus should be called with only the filtered port ID (port 1)
351372 EXPECT_CALL (getMockAgent (), getPortStatus (_, _))
352373 .WillOnce (Invoke ([&](auto & entries, const auto & portIds) {
353- // Verify that only port 1 is requested
354- EXPECT_EQ (portIds->size (), 1 );
374+ // Verify that all ports are requested, filtering is done later in
375+ // createModel
376+ EXPECT_EQ (portIds->size (), 6 );
355377 EXPECT_EQ ((*portIds)[0 ], 1 );
356378
357379 // Return only the status for port 1
@@ -360,12 +382,12 @@ TEST_F(CmdShowTransceiverTestFixture, queryClientFilteredByPort) {
360382 entries = filteredStatuses;
361383 }));
362384
363- // getTransceiverInfo should be called with only the transceiver ID for port 1
385+ // getTransceiverInfo should query all transceivers, filtering is done later
386+ // in createModel
364387 EXPECT_CALL (getQsfpService (), getTransceiverInfo (_, _))
365388 .WillOnce (Invoke ([&](auto & entries, const auto & transceiverIds) {
366- // Verify that only transceiver 1 is requested
367- EXPECT_EQ (transceiverIds->size (), 1 );
368- EXPECT_EQ ((*transceiverIds)[0 ], 1 );
389+ // Verify that all transceivers are requested
390+ EXPECT_EQ (transceiverIds->size (), 0 );
369391
370392 // Return only the transceiver info for transceiver 1
371393 std::map<int32_t , TransceiverInfo> filteredTransceivers;
@@ -413,8 +435,8 @@ TEST_F(CmdShowTransceiverTestFixture, queryClientFilteredByMultiplePorts) {
413435
414436 EXPECT_CALL (getMockAgent (), getPortStatus (_, _))
415437 .WillOnce (Invoke ([&](auto & entries, const auto & portIds) {
416- // Verify that only ports 1 and 6 are requested
417- EXPECT_EQ (portIds->size (), 2 );
438+ // We query all ports, filtering is done in createModel
439+ EXPECT_EQ (portIds->size (), 6 );
418440 EXPECT_TRUE (
419441 std::find (portIds->begin (), portIds->end (), 1 ) != portIds->end ());
420442 EXPECT_TRUE (
@@ -429,14 +451,8 @@ TEST_F(CmdShowTransceiverTestFixture, queryClientFilteredByMultiplePorts) {
429451
430452 EXPECT_CALL (getQsfpService (), getTransceiverInfo (_, _))
431453 .WillOnce (Invoke ([&](auto & entries, const auto & transceiverIds) {
432- // Verify that only transceivers 1 and 6 are requested
433- EXPECT_EQ (transceiverIds->size (), 2 );
434- EXPECT_TRUE (
435- std::find (transceiverIds->begin (), transceiverIds->end (), 1 ) !=
436- transceiverIds->end ());
437- EXPECT_TRUE (
438- std::find (transceiverIds->begin (), transceiverIds->end (), 6 ) !=
439- transceiverIds->end ());
454+ // We query all transceivers, filtering is done later in createModel
455+ EXPECT_EQ (transceiverIds->size (), 0 );
440456
441457 // Return only the transceiver info for transceivers 1 and 6
442458 std::map<int32_t , TransceiverInfo> filteredTransceivers;
@@ -475,6 +491,178 @@ TEST_F(CmdShowTransceiverTestFixture, queryClientFilteredByMultiplePorts) {
475491 EXPECT_EQ (tcvr6.vendor ().value (), " vendorThree" );
476492}
477493
494+ TEST_F (CmdShowTransceiverTestFixture, queryClientFilteredMultiPortModule) {
495+ // Test filtering by a subset of ports for a multi-port module
496+ setupMockedAgentServer ();
497+
498+ // Create a multi-port module (transceiver 10) with 8 interfaces
499+ std::map<int32_t , PortInfoThrift> multiPortPortEntries;
500+ std::map<int32_t , PortStatus> multiPortPortStatusEntries;
501+ for (int i = 1 ; i <= 8 ; i++) {
502+ PortInfoThrift portEntry;
503+ portEntry.portId () = i;
504+ portEntry.name () = folly::to<std::string>(" fab1/1/" , i);
505+ multiPortPortEntries[i] = std::move (portEntry);
506+
507+ PortStatus portStatus;
508+ TransceiverIdxThrift tcvr;
509+ tcvr.transceiverId () = 10 ;
510+ portStatus.transceiverIdx () = tcvr;
511+ portStatus.up () = true ;
512+ multiPortPortStatusEntries[i] = std::move (portStatus);
513+ }
514+
515+ // Create a single transceiver with all 8 interfaces
516+ std::map<int32_t , TransceiverInfo> multiPortTransceiverEntries;
517+ TransceiverInfo multiPortTransceiver;
518+ multiPortTransceiver.tcvrState ()->vendor () = []() {
519+ Vendor vendor;
520+ vendor.name () = " vendorMultiPort" ;
521+ vendor.serialNumber () = " mp123" ;
522+ vendor.partNumber () = " mp-part-1" ;
523+ return vendor;
524+ }();
525+ multiPortTransceiver.tcvrState ()->present () = true ;
526+ multiPortTransceiver.tcvrState ()->moduleMediaInterface () =
527+ MediaInterfaceCode::FR8_800G;
528+ multiPortTransceiver.tcvrState ()->interfaces () = {
529+ " fab1/1/1" ,
530+ " fab1/1/2" ,
531+ " fab1/1/3" ,
532+ " fab1/1/4" ,
533+ " fab1/1/5" ,
534+ " fab1/1/6" ,
535+ " fab1/1/7" ,
536+ " fab1/1/8" };
537+ multiPortTransceiver.tcvrState ()->port () = 10 ;
538+ multiPortTransceiver.tcvrStats ()->sensor () = []() {
539+ Sensor tempSensor;
540+ Sensor voltageSensor;
541+ tempSensor.value () = 45.0 ;
542+ voltageSensor.value () = 28.0 ;
543+ GlobalSensors sensors;
544+ sensors.temp () = tempSensor;
545+ sensors.vcc () = voltageSensor;
546+ return sensors;
547+ }();
548+ multiPortTransceiver.tcvrStats ()->channels () = {};
549+ multiPortTransceiverEntries[10 ] = multiPortTransceiver;
550+
551+ std::map<int32_t , std::string> multiPortValidationEntries;
552+ multiPortValidationEntries[10 ] = " " ;
553+
554+ // Query for a subset of ports (fab1/1/2 and fab1/1/5)
555+ CmdShowTransceiverTraits::ObjectArgType queriedEntries = {
556+ " fab1/1/2" , " fab1/1/5" };
557+
558+ EXPECT_CALL (getMockAgent (), getAllPortInfo (_))
559+ .WillOnce (Invoke ([&](auto & entries) { entries = multiPortPortEntries; }));
560+
561+ EXPECT_CALL (getMockAgent (), getPortStatus (_, _))
562+ .WillOnce (Invoke ([&](auto & entries, const auto & portIds) {
563+ // Verify all ports are requested
564+ EXPECT_EQ (portIds->size (), 8 );
565+
566+ // Return status for all ports
567+ entries = multiPortPortStatusEntries;
568+ }));
569+
570+ EXPECT_CALL (getQsfpService (), getTransceiverInfo (_, _))
571+ .WillOnce (Invoke ([&](auto & entries, const auto & transceiverIds) {
572+ // Verify all tcvrs are requested
573+ EXPECT_EQ (transceiverIds->size (), 0 );
574+
575+ // Return the multi-port transceiver
576+ entries = multiPortTransceiverEntries;
577+ }));
578+
579+ EXPECT_CALL (getQsfpService (), getTransceiverConfigValidationInfo (_, _, _))
580+ .WillOnce (
581+ Invoke ([&](auto & entries, const auto & /* transceiverIds */ , auto ) {
582+ entries = multiPortValidationEntries;
583+ }));
584+
585+ auto cmd = CmdShowTransceiver ();
586+ auto model = cmd.queryClient (localhost (), queriedEntries);
587+
588+ // Verify that the model contains only the requested interfaces
589+ EXPECT_EQ (model.transceivers ()->size (), 2 );
590+ EXPECT_TRUE (
591+ model.transceivers ()->find (" fab1/1/2" ) != model.transceivers ()->end ());
592+ EXPECT_TRUE (
593+ model.transceivers ()->find (" fab1/1/5" ) != model.transceivers ()->end ());
594+
595+ // Verify the entries are correct
596+ auto & tcvr2 = model.transceivers ()->at (" fab1/1/2" );
597+ EXPECT_EQ (tcvr2.name ().value (), " fab1/1/2" );
598+ EXPECT_TRUE (tcvr2.isUp ().has_value ());
599+ EXPECT_TRUE (tcvr2.isUp ().value ());
600+ EXPECT_EQ (tcvr2.vendor ().value (), " vendorMultiPort" );
601+ EXPECT_EQ (tcvr2.serial ().value (), " mp123" );
602+
603+ auto & tcvr5 = model.transceivers ()->at (" fab1/1/5" );
604+ EXPECT_EQ (tcvr5.name ().value (), " fab1/1/5" );
605+ EXPECT_TRUE (tcvr5.isUp ().has_value ());
606+ EXPECT_TRUE (tcvr5.isUp ().value ());
607+ EXPECT_EQ (tcvr5.vendor ().value (), " vendorMultiPort" );
608+ EXPECT_EQ (tcvr5.serial ().value (), " mp123" );
609+ }
610+
611+ TEST_F (CmdShowTransceiverTestFixture, queryClientFilteredBypassModule) {
612+ // Test filtering for a single bypass module (module without port entry)
613+ setupMockedAgentServer ();
614+
615+ // Query for a bypass module interface
616+ CmdShowTransceiverTraits::ObjectArgType queriedEntries = {" eth1/7/1" };
617+
618+ EXPECT_CALL (getMockAgent (), getAllPortInfo (_))
619+ .WillOnce (Invoke ([&](auto & entries) { entries = mockPortEntries; }));
620+
621+ EXPECT_CALL (getMockAgent (), getPortStatus (_, _))
622+ .WillOnce (Invoke ([&](auto & entries, const auto & portIds) {
623+ // All agent ports are queried
624+ EXPECT_EQ (portIds->size (), 6 );
625+
626+ // Return all port statuses (bypass module won't have a port status)
627+ entries = mockPortStatusEntries;
628+ }));
629+
630+ EXPECT_CALL (getQsfpService (), getTransceiverInfo (_, _))
631+ .WillOnce (Invoke ([&](auto & entries, const auto & transceiverIds) {
632+ // Verify that we query all tcvrs
633+ EXPECT_EQ (transceiverIds->size (), 0 );
634+
635+ entries = mockTransceiverEntries;
636+ }));
637+
638+ EXPECT_CALL (getQsfpService (), getTransceiverConfigValidationInfo (_, _, _))
639+ .WillOnce (Invoke ([&](auto & entries, const auto & transceiverIds, auto ) {
640+ // Won't include the bypass modules, since there's no port status
641+ EXPECT_EQ (transceiverIds->size (), 6 );
642+
643+ entries = mockTransceiverValidationEntries;
644+ }));
645+
646+ auto cmd = CmdShowTransceiver ();
647+ auto model = cmd.queryClient (localhost (), queriedEntries);
648+
649+ // Check that only the bypass module is reported
650+ EXPECT_EQ (model.transceivers ()->size (), 1 );
651+ EXPECT_TRUE (
652+ model.transceivers ()->find (" eth1/7/1" ) != model.transceivers ()->end ());
653+
654+ // Check that the contents of the entry are correct (should be listed as
655+ // a bypass module)
656+ auto & bypassModule = model.transceivers ()->at (" eth1/7/1" );
657+ EXPECT_EQ (bypassModule.name ().value (), " eth1/7/1" );
658+ EXPECT_FALSE (
659+ bypassModule.isUp ().has_value ()); // Bypass modules have no port status
660+ EXPECT_TRUE (bypassModule.isPresent ().value ());
661+ EXPECT_EQ (bypassModule.vendor ().value (), " vendorBypass" );
662+ EXPECT_EQ (bypassModule.serial ().value (), " d" );
663+ EXPECT_EQ (bypassModule.partNumber ().value (), " 5" );
664+ }
665+
478666TEST_F (CmdShowTransceiverTestFixture, printOutput) {
479667 std::stringstream ss;
480668 CmdShowTransceiver ().printOutput (normalizedModel, ss);
0 commit comments