@@ -662,6 +662,7 @@ func TestMatchExactResourceVersionFallback(t *testing.T) {
662
662
}
663
663
for _ , tc := range tcs {
664
664
t .Run (tc .name , func (t * testing.T ) {
665
+ featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .ListFromCacheSnapshot , true )
665
666
backingStorage := & dummyStorage {}
666
667
expectStoreRequests := 0
667
668
backingStorage .getListFn = func (_ context.Context , key string , opts storage.ListOptions , listObj runtime.Object ) error {
@@ -759,6 +760,125 @@ func TestGetListNonRecursiveCacheBypass(t *testing.T) {
759
760
}
760
761
}
761
762
763
+ func TestGetListNonRecursiveCacheWithConsistentListFromCache (t * testing.T ) {
764
+ // Set feature gates once at the beginning since we only care about ConsistentListFromCache=true and ListFromCacheSnapshot=false
765
+ featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .ConsistentListFromCache , true )
766
+ featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .ListFromCacheSnapshot , false )
767
+ forceRequestWatchProgressSupport (t )
768
+
769
+ tests := []struct {
770
+ name string
771
+ consistentListFromCache bool
772
+ expectGetListCallCount int
773
+ expectGetCurrentRV bool
774
+ injectRVError bool
775
+ expectedError error
776
+ }{
777
+ {
778
+ name : "ConsistentListFromCache enabled - served from cache" ,
779
+ consistentListFromCache : true ,
780
+ expectGetListCallCount : 1 ,
781
+ expectGetCurrentRV : true ,
782
+ injectRVError : false ,
783
+ expectedError : nil ,
784
+ },
785
+ }
786
+
787
+ for _ , tc := range tests {
788
+ t .Run (tc .name , func (t * testing.T ) {
789
+ var getListCount , getCurrentRVCount int
790
+ backingStorage := & dummyStorage {}
791
+
792
+ backingStorage .getListFn = func (ctx context.Context , key string , opts storage.ListOptions , listObj runtime.Object ) error {
793
+ getListCount ++
794
+ if tc .injectRVError {
795
+ return errDummy
796
+ }
797
+ podList := listObj .(* example.PodList )
798
+ podList .ListMeta = metav1.ListMeta {ResourceVersion : "100" }
799
+ return nil
800
+ }
801
+
802
+ backingStorage .getRVFn = func (ctx context.Context ) (uint64 , error ) {
803
+ getCurrentRVCount ++
804
+ rv := uint64 (100 )
805
+ err := error (nil )
806
+ if tc .injectRVError {
807
+ err = errDummy
808
+ return 0 , err
809
+ }
810
+ return rv , nil
811
+ }
812
+
813
+ cacher , v , err := newTestCacher (backingStorage )
814
+ if err != nil {
815
+ t .Fatalf ("Couldn't create cacher: %v" , err )
816
+ }
817
+ defer cacher .Stop ()
818
+
819
+ // Wait for cacher to be ready before injecting errors
820
+ if err := cacher .ready .wait (context .Background ()); err != nil {
821
+ t .Fatalf ("unexpected error waiting for the cache to be ready: %v" , err )
822
+ }
823
+ delegator := NewCacheDelegator (cacher , backingStorage )
824
+ defer delegator .Stop ()
825
+
826
+ // Setup test object
827
+ key := "pods/ns"
828
+ input := & example.Pod {ObjectMeta : metav1.ObjectMeta {Name : "foo" , Namespace : "ns" }}
829
+ if err := v .UpdateObject (input , 100 ); err != nil {
830
+ t .Fatalf ("Unexpected error: %v" , err )
831
+ }
832
+
833
+ // Put object into the store
834
+ if err := cacher .watchCache .Add (input ); err != nil {
835
+ t .Fatalf ("Unexpected error: %v" , err )
836
+ }
837
+
838
+ pred := storage.SelectionPredicate {
839
+ Label : labels .Everything (),
840
+ Field : fields .Everything (),
841
+ Limit : 500 ,
842
+ }
843
+ result := & example.PodList {}
844
+
845
+ // Make the list call with empty RV - delegator will get current RV and use it
846
+ err = delegator .GetList (context .TODO (), key , storage.ListOptions {
847
+ ResourceVersion : "" ,
848
+ Predicate : pred ,
849
+ Recursive : true ,
850
+ }, result )
851
+
852
+ // Verify error matches expectation
853
+ if ! errors .Is (err , tc .expectedError ) {
854
+ t .Errorf ("Expected error %v, got: %v" , tc .expectedError , err )
855
+ }
856
+
857
+ // Verify the correct storage method was called
858
+ if getListCount != tc .expectGetListCallCount {
859
+ t .Errorf ("Expected GetList to be called %d times, but it was called %d times" , tc .expectGetListCallCount , getListCount )
860
+ }
861
+ if tc .expectGetCurrentRV && getCurrentRVCount == 0 {
862
+ t .Error ("Expected GetCurrentResourceVersion to be called, but it wasn't" )
863
+ }
864
+ if ! tc .expectGetCurrentRV && getCurrentRVCount > 0 {
865
+ t .Errorf ("Expected GetCurrentResourceVersion not to be called, but it was called %d times" , getCurrentRVCount )
866
+ }
867
+
868
+ // For successful cache reads, verify the resource version
869
+ if err == nil {
870
+ resultRV , err := cacher .versioner .ParseResourceVersion (result .ResourceVersion )
871
+ if err != nil {
872
+ t .Fatalf ("Failed to parse result resource version: %v" , err )
873
+ }
874
+ expectedRV := uint64 (100 )
875
+ if resultRV != expectedRV {
876
+ t .Errorf ("Expected RV %d but got %d" , expectedRV , resultRV )
877
+ }
878
+ }
879
+ })
880
+ }
881
+ }
762
882
func TestGetCacheBypass (t * testing.T ) {
763
883
backingStorage := & dummyStorage {}
764
884
cacher , _ , err := newTestCacher (backingStorage )
0 commit comments