@@ -29,7 +29,10 @@ import (
2929 meshproto "github.com/apache/dubbo-admin/api/mesh/v1alpha1"
3030 appconfig "github.com/apache/dubbo-admin/pkg/config/app"
3131 eventbusconfig "github.com/apache/dubbo-admin/pkg/config/eventbus"
32+ "github.com/apache/dubbo-admin/pkg/config/mode"
33+ versioningcfg "github.com/apache/dubbo-admin/pkg/config/versioning"
3234 "github.com/apache/dubbo-admin/pkg/core/events"
35+ "github.com/apache/dubbo-admin/pkg/core/manager"
3336 meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
3437 "github.com/apache/dubbo-admin/pkg/core/resource/model"
3538 coreruntime "github.com/apache/dubbo-admin/pkg/core/runtime"
@@ -74,6 +77,26 @@ func TestAdminHintTTLHitAndMiss(t *testing.T) {
7477 require .False (t , ok )
7578}
7679
80+ func TestAdminHintPrunesExpiredOnPutAndTake (t * testing.T ) {
81+ now := time .Now ()
82+ reg := NewAdminHintRegistry ()
83+ reg .now = func () time.Time { return now }
84+
85+ reg .Put (meshresource .ConditionRouteKind , "m/stale" , "stale" , AdminHint {ExpiresAt : now .Add (- time .Second )})
86+ require .Len (t , reg .hints , 1 )
87+
88+ reg .Put (meshresource .ConditionRouteKind , "m/fresh" , "fresh" , AdminHint {
89+ ExpiresAt : now .Add (time .Second ),
90+ })
91+ require .Len (t , reg .hints , 1 )
92+
93+ reg .Put (meshresource .ConditionRouteKind , "m/stale" , "stale" , AdminHint {ExpiresAt : now .Add (- time .Second )})
94+ hint , ok := reg .Take (meshresource .ConditionRouteKind , "m/fresh" , "fresh" )
95+ require .True (t , ok )
96+ require .Empty (t , hint .Author )
97+ require .Empty (t , reg .hints )
98+ }
99+
77100func TestMemoryStoreRetentionCurrentPointerAndDelete (t * testing.T ) {
78101 store := NewMemoryStore ()
79102 key := "mesh/demo.condition-router"
@@ -219,7 +242,7 @@ func TestSubscriberRespectsRegistrySourceContext(t *testing.T) {
219242 cache .Updated ,
220243 nil ,
221244 upstreamRes ,
222- map [string ]string {"source-registry" : "zookeeper" },
245+ map [string ]string {events . SourceRegistryContextKey : "zookeeper" },
223246 )))
224247
225248 items , err := store .ListVersions (meshresource .ConditionRouteKind , upstreamRes .ResourceKey ())
@@ -241,7 +264,7 @@ func TestSubscriberSkipsNoopUpstreamEchoAfterBootstrap(t *testing.T) {
241264 cache .Updated ,
242265 nil ,
243266 original ,
244- map [string ]string {"source-registry" : "zookeeper" },
267+ map [string ]string {events . SourceRegistryContextKey : "zookeeper" },
245268 )))
246269
247270 items , err := store .ListVersions (meshresource .ConditionRouteKind , original .ResourceKey ())
@@ -256,7 +279,7 @@ func TestSubscriberSkipsNoopUpstreamEchoAfterBootstrap(t *testing.T) {
256279 cache .Updated ,
257280 original ,
258281 changed ,
259- map [string ]string {"source-registry" : "zookeeper" },
282+ map [string ]string {events . SourceRegistryContextKey : "zookeeper" },
260283 )))
261284
262285 items , err = store .ListVersions (meshresource .ConditionRouteKind , original .ResourceKey ())
@@ -267,6 +290,26 @@ func TestSubscriberSkipsNoopUpstreamEchoAfterBootstrap(t *testing.T) {
267290 require .True (t , items [0 ].IsCurrent )
268291}
269292
293+ func TestSubscriberRecordsEmptyCreateAfterDelete (t * testing.T ) {
294+ store := NewMemoryStore ()
295+ hints := NewAdminHintRegistry ()
296+ sub := NewSubscriber (meshresource .ConditionRouteKind , store , hints , 5 , 0 )
297+ res := meshresource .NewConditionRouteResourceWithAttributes ("demo.condition-router" , "mesh" )
298+ res .Spec = & meshproto.ConditionRoute {}
299+
300+ require .NoError (t , sub .ProcessEvent (events .NewResourceChangedEvent (cache .Added , nil , res )))
301+ require .NoError (t , sub .ProcessEvent (events .NewResourceChangedEvent (cache .Deleted , res , nil )))
302+ require .NoError (t , sub .ProcessEvent (events .NewResourceChangedEvent (cache .Added , nil , res )))
303+
304+ items , err := store .ListVersions (meshresource .ConditionRouteKind , res .ResourceKey ())
305+ require .NoError (t , err )
306+ require .Len (t , items , 3 )
307+ require .Equal (t , OperationCreate , items [0 ].Operation )
308+ require .True (t , items [0 ].IsCurrent )
309+ require .Equal (t , OperationDelete , items [1 ].Operation )
310+ require .False (t , items [1 ].IsCurrent )
311+ }
312+
270313func TestSubscriberRecordsDeleteWithAdminHintSnapshot (t * testing.T ) {
271314 store := NewMemoryStore ()
272315 hints := NewAdminHintRegistry ()
@@ -410,6 +453,37 @@ func TestDisabledServiceHistoryReturnsFeatureDisabled(t *testing.T) {
410453 require .ErrorIs (t , err , ErrFeatureDisabled )
411454}
412455
456+ func TestComponentFlushesPendingVersionsOnStop (t * testing.T ) {
457+ store := NewMemoryStore ()
458+ sub := NewSubscriber (meshresource .ConditionRouteKind , store , NewAdminHintRegistry (), 5 , time .Hour )
459+ comp := & component {
460+ store : store ,
461+ subscribers : []* Subscriber {sub },
462+ }
463+ res := meshresource .NewConditionRouteResourceWithAttributes ("demo.condition-router" , "mesh" )
464+ res .Spec = & meshproto.ConditionRoute {Key : "demo" , Priority : 1 }
465+ require .NoError (t , sub .ProcessEvent (events .NewResourceChangedEvent (cache .Added , nil , res )))
466+
467+ stop := make (chan struct {})
468+ require .NoError (t , comp .Start (testRuntime {
469+ cfg : appconfig.AdminConfig {
470+ Versioning : & versioningcfg.Config {
471+ Enabled : true ,
472+ MaxVersionsPerRule : 5 ,
473+ },
474+ },
475+ components : map [coreruntime.ComponentType ]coreruntime.Component {
476+ coreruntime .ResourceManager : testRMComponent {rm : fakeNoopResourceManager {}},
477+ },
478+ }, stop ))
479+ close (stop )
480+
481+ require .Eventually (t , func () bool {
482+ items , err := store .ListVersions (meshresource .ConditionRouteKind , res .ResourceKey ())
483+ return err == nil && len (items ) == 1
484+ }, time .Second , 10 * time .Millisecond )
485+ }
486+
413487type fakeVersionResourceManager struct {
414488 subscriber * Subscriber
415489}
@@ -564,3 +638,70 @@ func (c testBuilderContext) GetActivatedComponent(coreruntime.ComponentType) (co
564638func (c testBuilderContext ) ActivateComponent (coreruntime.Component ) error {
565639 return nil
566640}
641+
642+ type testRuntime struct {
643+ cfg appconfig.AdminConfig
644+ components map [coreruntime.ComponentType ]coreruntime.Component
645+ }
646+
647+ func (r testRuntime ) GetInstanceId () string {
648+ return "test-instance"
649+ }
650+
651+ func (r testRuntime ) GetClusterId () string {
652+ return "test-cluster"
653+ }
654+
655+ func (r testRuntime ) GetStartTime () time.Time {
656+ return time .Now ()
657+ }
658+
659+ func (r testRuntime ) GetMode () mode.Mode {
660+ return mode .Test
661+ }
662+
663+ func (r testRuntime ) Config () appconfig.AdminConfig {
664+ return r .cfg
665+ }
666+
667+ func (r testRuntime ) GetComponent (typ coreruntime.ComponentType ) (coreruntime.Component , error ) {
668+ return r .components [typ ], nil
669+ }
670+
671+ func (r testRuntime ) AppContext () context.Context {
672+ return context .Background ()
673+ }
674+
675+ func (r testRuntime ) Add (... coreruntime.Component ) {}
676+
677+ func (r testRuntime ) Start (<- chan struct {}) error {
678+ return nil
679+ }
680+
681+ type testRMComponent struct {
682+ rm manager.ResourceManager
683+ }
684+
685+ func (c testRMComponent ) Type () coreruntime.ComponentType {
686+ return coreruntime .ResourceManager
687+ }
688+
689+ func (c testRMComponent ) Order () int {
690+ return 0
691+ }
692+
693+ func (c testRMComponent ) RequiredDependencies () []coreruntime.ComponentType {
694+ return nil
695+ }
696+
697+ func (c testRMComponent ) Init (coreruntime.BuilderContext ) error {
698+ return nil
699+ }
700+
701+ func (c testRMComponent ) Start (coreruntime.Runtime , <- chan struct {}) error {
702+ return nil
703+ }
704+
705+ func (c testRMComponent ) ResourceManager () manager.ResourceManager {
706+ return c .rm
707+ }
0 commit comments