@@ -445,3 +445,143 @@ func TestCPUPowerMeter_InitNoZones(t *testing.T) {
445445 assert .Equal (t , "no RAPL zones found" , err .Error (), "Start() should return a specific error message" )
446446 mockReader .AssertExpectations (t )
447447}
448+
449+ // TestPrimaryEnergyZone tests the PrimaryEnergyZone method
450+ func TestPrimaryEnergyZone (t * testing.T ) {
451+ t .Run ("Priority hierarchy" , func (t * testing.T ) {
452+ tests := []struct {
453+ name string
454+ zones []EnergyZone
455+ expected string
456+ }{{
457+ name : "psys has highest priority" ,
458+ zones : []EnergyZone {
459+ mockZone {name : "package" , index : 0 },
460+ mockZone {name : "psys" , index : 0 },
461+ mockZone {name : "core" , index : 0 },
462+ },
463+ expected : "psys" ,
464+ }, {
465+ name : "package has priority over core" ,
466+ zones : []EnergyZone {
467+ mockZone {name : "core" , index : 0 },
468+ mockZone {name : "package" , index : 0 },
469+ mockZone {name : "dram" , index : 0 },
470+ },
471+ expected : "package" ,
472+ }, {
473+ name : "core has priority over dram" ,
474+ zones : []EnergyZone {
475+ mockZone {name : "dram" , index : 0 },
476+ mockZone {name : "core" , index : 0 },
477+ mockZone {name : "uncore" , index : 0 },
478+ },
479+ expected : "core" ,
480+ }, {
481+ name : "dram has priority over uncore" ,
482+ zones : []EnergyZone {
483+ mockZone {name : "uncore" , index : 0 },
484+ mockZone {name : "dram" , index : 0 },
485+ },
486+ expected : "dram" ,
487+ }}
488+
489+ for _ , tt := range tests {
490+ t .Run (tt .name , func (t * testing.T ) {
491+ mockReader := & mockRaplReader {}
492+ mockReader .On ("Zones" ).Return (tt .zones , nil )
493+
494+ meter := & raplPowerMeter {reader : mockReader , logger : slog .Default ()}
495+ zone , err := meter .PrimaryEnergyZone ()
496+
497+ assert .NoError (t , err )
498+ assert .Equal (t , tt .expected , zone .Name ())
499+ mockReader .AssertExpectations (t )
500+ })
501+ }
502+ })
503+
504+ t .Run ("Case insensitive matching" , func (t * testing.T ) {
505+ mockReader := & mockRaplReader {}
506+ mockReader .On ("Zones" ).Return ([]EnergyZone {
507+ mockZone {name : "PACKAGE" , index : 0 },
508+ mockZone {name : "Core" , index : 0 },
509+ }, nil )
510+
511+ meter := & raplPowerMeter {reader : mockReader , logger : slog .Default ()}
512+ zone , err := meter .PrimaryEnergyZone ()
513+
514+ assert .NoError (t , err )
515+ assert .Equal (t , "PACKAGE" , zone .Name ())
516+ mockReader .AssertExpectations (t )
517+ })
518+
519+ t .Run ("Fallback to first zone" , func (t * testing.T ) {
520+ zones := []EnergyZone {
521+ mockZone {name : "unknown1" , index : 0 },
522+ mockZone {name : "unknown2" , index : 1 },
523+ }
524+ mockReader := & mockRaplReader {}
525+ mockReader .On ("Zones" ).Return (zones , nil )
526+
527+ meter := & raplPowerMeter {reader : mockReader , logger : slog .Default ()}
528+ zone , err := meter .PrimaryEnergyZone ()
529+
530+ assert .NoError (t , err )
531+ // NOTE: since reader.Zones() does not guarantee the order after filtering,
532+ // we cannot assert zone.Name() == "unknown1", thus assert the zone returned
533+ // any of the zones passed as input
534+ zoneName := zone .Name ()
535+ assert .Contains (t , []string {"unknown1" , "unknown2" }, zoneName )
536+ mockReader .AssertExpectations (t )
537+ })
538+
539+ t .Run ("Caching behavior" , func (t * testing.T ) {
540+ mockReader := & mockRaplReader {}
541+ mockReader .On ("Zones" ).Return ([]EnergyZone {
542+ mockZone {name : "package" , index : 0 },
543+ }, nil ).Once ()
544+
545+ meter := & raplPowerMeter {reader : mockReader , logger : slog .Default ()}
546+
547+ // First call should read from zones and cache topZone
548+ zone1 , err := meter .PrimaryEnergyZone ()
549+ assert .NoError (t , err )
550+ assert .Equal (t , "package" , zone1 .Name ())
551+
552+ // Second call should use cached topZone directly
553+ zone2 , err := meter .PrimaryEnergyZone ()
554+ assert .NoError (t , err )
555+ assert .Equal (t , "package" , zone2 .Name ())
556+
557+ mockReader .AssertExpectations (t )
558+ })
559+
560+ t .Run ("Error handling" , func (t * testing.T ) {
561+ t .Run ("Zones() returns error" , func (t * testing.T ) {
562+ mockReader := & mockRaplReader {}
563+ mockReader .On ("Zones" ).Return ([]EnergyZone {}, errors .New ("zones error" ))
564+
565+ meter := & raplPowerMeter {reader : mockReader , logger : slog .Default ()}
566+ zone , err := meter .PrimaryEnergyZone ()
567+
568+ assert .Error (t , err )
569+ assert .Nil (t , zone )
570+ assert .Contains (t , err .Error (), "zones error" )
571+ mockReader .AssertExpectations (t )
572+ })
573+
574+ t .Run ("Empty zones list" , func (t * testing.T ) {
575+ mockReader := & mockRaplReader {}
576+ mockReader .On ("Zones" ).Return ([]EnergyZone {}, nil )
577+
578+ meter := & raplPowerMeter {reader : mockReader , logger : slog .Default ()}
579+ zone , err := meter .PrimaryEnergyZone ()
580+
581+ assert .Error (t , err )
582+ assert .Nil (t , zone )
583+ assert .Contains (t , err .Error (), "no RAPL zones found" )
584+ mockReader .AssertExpectations (t )
585+ })
586+ })
587+ }
0 commit comments