k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/cached/cache_test.go (about)

     1  /*
     2  Copyright 2023 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package cached_test
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"math/rand"
    25  	"sort"
    26  	"strings"
    27  	"sync"
    28  	"testing"
    29  	"time"
    30  
    31  	"k8s.io/kube-openapi/pkg/cached"
    32  )
    33  
    34  func TestDataFunc(t *testing.T) {
    35  	count := 0
    36  	source := cached.Func(func() ([]byte, string, error) {
    37  		count += 1
    38  		return []byte("source"), "source", nil
    39  	})
    40  	if _, _, err := source.Get(); err != nil {
    41  		t.Fatalf("unexpected error: %v", err)
    42  	}
    43  	if _, _, err := source.Get(); err != nil {
    44  		t.Fatalf("unexpected error: %v", err)
    45  	}
    46  	if count != 2 {
    47  		t.Fatalf("Expected function called twice, called: %v", count)
    48  	}
    49  }
    50  
    51  func TestDataFuncError(t *testing.T) {
    52  	count := 0
    53  	source := cached.Func(func() ([]byte, string, error) {
    54  		count += 1
    55  		return nil, "", errors.New("source error")
    56  	})
    57  	if _, _, err := source.Get(); err == nil {
    58  		t.Fatalf("expected error, found none")
    59  	}
    60  	if _, _, err := source.Get(); err == nil {
    61  		t.Fatalf("expected error, found none")
    62  	}
    63  	if count != 2 {
    64  		t.Fatalf("Expected function called twice, called: %v", count)
    65  	}
    66  }
    67  
    68  func TestDataFuncAlternate(t *testing.T) {
    69  	count := 0
    70  	source := cached.Func(func() ([]byte, string, error) {
    71  		count += 1
    72  		if count%2 == 0 {
    73  			return nil, "", errors.New("source error")
    74  		}
    75  		return []byte("source"), "source", nil
    76  	})
    77  	if _, _, err := source.Get(); err != nil {
    78  		t.Fatalf("unexpected error: %v", err)
    79  	}
    80  	if _, _, err := source.Get(); err == nil {
    81  		t.Fatalf("expected error, found none")
    82  	}
    83  	if _, _, err := source.Get(); err != nil {
    84  		t.Fatalf("unexpected error: %v", err)
    85  	}
    86  	if _, _, err := source.Get(); err == nil {
    87  		t.Fatalf("expected error, found none")
    88  	}
    89  	if count != 4 {
    90  		t.Fatalf("Expected function called 4x, called: %v", count)
    91  	}
    92  }
    93  
    94  func TestOnce(t *testing.T) {
    95  	count := 0
    96  	source := cached.Once(cached.Func(func() ([]byte, string, error) {
    97  		count += 1
    98  		return []byte("source"), "source", nil
    99  	}))
   100  	if _, _, err := source.Get(); err != nil {
   101  		t.Fatalf("unexpected error: %v", err)
   102  	}
   103  	if _, _, err := source.Get(); err != nil {
   104  		t.Fatalf("unexpected error: %v", err)
   105  	}
   106  	if count != 1 {
   107  		t.Fatalf("Expected function called once, called: %v", count)
   108  	}
   109  }
   110  
   111  func TestOnceError(t *testing.T) {
   112  	count := 0
   113  	source := cached.Once(cached.Func(func() ([]byte, string, error) {
   114  		count += 1
   115  		return nil, "", errors.New("source error")
   116  	}))
   117  	if _, _, err := source.Get(); err == nil {
   118  		t.Fatalf("expected error, found none")
   119  	}
   120  	if _, _, err := source.Get(); err == nil {
   121  		t.Fatalf("expected error, found none")
   122  	}
   123  	if count != 1 {
   124  		t.Fatalf("Expected function called once, called: %v", count)
   125  	}
   126  }
   127  
   128  func TestResultGet(t *testing.T) {
   129  	source := cached.Static([]byte("source"), "etag")
   130  	value, etag, err := source.Get()
   131  	if err != nil {
   132  		t.Fatalf("unexpected error: %v", err)
   133  	}
   134  	if want := "source"; string(value) != want {
   135  		t.Fatalf("expected value %q, got %q", want, string(value))
   136  	}
   137  	if want := "etag"; etag != want {
   138  		t.Fatalf("expected etag %q, got %q", want, etag)
   139  	}
   140  }
   141  
   142  func TestResultGetError(t *testing.T) {
   143  	source := cached.Result[[]byte]{Err: errors.New("source error")}
   144  	value, etag, err := source.Get()
   145  	if err == nil {
   146  		t.Fatalf("expected error, found none")
   147  	}
   148  	if value != nil {
   149  		t.Fatalf("expected nil value, got %v", value)
   150  	}
   151  	if etag != "" {
   152  		t.Fatalf("expected empty etag, got %q", etag)
   153  	}
   154  }
   155  
   156  func TestTransform(t *testing.T) {
   157  	sourceCount := 0
   158  	source := cached.Func(func() ([]byte, string, error) {
   159  		sourceCount += 1
   160  		return []byte("source"), "source", nil
   161  	})
   162  	transformerCount := 0
   163  	transformer := cached.Transform(func(value []byte, etag string, err error) ([]byte, string, error) {
   164  		transformerCount += 1
   165  		if err != nil {
   166  			return nil, "", err
   167  		}
   168  		return []byte("transformed " + string(value)), "transformed " + etag, nil
   169  	}, source)
   170  	if _, _, err := transformer.Get(); err != nil {
   171  		t.Fatalf("unexpected error: %v", err)
   172  	}
   173  	if _, _, err := transformer.Get(); err != nil {
   174  		t.Fatalf("unexpected error: %v", err)
   175  	}
   176  	if sourceCount != 2 {
   177  		t.Fatalf("Expected source function called twice, called: %v", sourceCount)
   178  	}
   179  	if transformerCount != 1 {
   180  		t.Fatalf("Expected transformer function called once, called: %v", transformerCount)
   181  	}
   182  }
   183  
   184  func TestTransformChained(t *testing.T) {
   185  	sourceCount := 0
   186  	source := cached.Func(func() ([]byte, string, error) {
   187  		sourceCount += 1
   188  		return []byte("source"), "source", nil
   189  	})
   190  	transformer1Count := 0
   191  	transformer1 := cached.Transform(func(value []byte, etag string, err error) ([]byte, string, error) {
   192  		transformer1Count += 1
   193  		if err != nil {
   194  			return nil, "", err
   195  		}
   196  		return []byte("transformed " + string(value)), etag, nil
   197  	}, source)
   198  	transformer2Count := 0
   199  	transformer2 := cached.Transform(func(value []byte, etag string, err error) ([]byte, string, error) {
   200  		transformer2Count += 1
   201  		if err != nil {
   202  			return nil, "", err
   203  		}
   204  		return []byte("transformed " + string(value)), etag, nil
   205  	}, transformer1)
   206  	transformer3Count := 0
   207  	transformer3 := cached.Transform(func(value []byte, etag string, err error) ([]byte, string, error) {
   208  		transformer3Count += 1
   209  		if err != nil {
   210  			return nil, "", err
   211  		}
   212  		return []byte("transformed " + string(value)), etag, nil
   213  	}, transformer2)
   214  	if _, _, err := transformer3.Get(); err != nil {
   215  		t.Fatalf("unexpected error: %v", err)
   216  	}
   217  	result, etag, err := transformer3.Get()
   218  	if err != nil {
   219  		t.Fatalf("unexpected error: %v", err)
   220  	}
   221  	if want := "transformed transformed transformed source"; string(result) != want {
   222  		t.Fatalf("expected data = %v, got %v", want, string(result))
   223  	}
   224  	if want := "source"; etag != want {
   225  		t.Fatalf("expected etag = %v, got %v", want, etag)
   226  	}
   227  	if sourceCount != 2 {
   228  		t.Fatalf("Expected source function called twice, called: %v", sourceCount)
   229  	}
   230  	if transformer1Count != 1 {
   231  		t.Fatalf("Expected transformer function called once, called: %v", transformer1Count)
   232  	}
   233  	if transformer2Count != 1 {
   234  		t.Fatalf("Expected transformer function called once, called: %v", transformer2Count)
   235  	}
   236  	if transformer3Count != 1 {
   237  		t.Fatalf("Expected transformer function called once, called: %v", transformer3Count)
   238  	}
   239  }
   240  
   241  func TestTransformError(t *testing.T) {
   242  	sourceCount := 0
   243  	source := cached.Func(func() ([]byte, string, error) {
   244  		sourceCount += 1
   245  		return []byte("source"), "source", nil
   246  	})
   247  	transformerCount := 0
   248  	transformer := cached.Transform(func(value []byte, etag string, err error) ([]byte, string, error) {
   249  		transformerCount += 1
   250  		return nil, "", errors.New("transformer error")
   251  	}, source)
   252  	if _, _, err := transformer.Get(); err == nil {
   253  		t.Fatalf("expected error, none found")
   254  	}
   255  	if _, _, err := transformer.Get(); err == nil {
   256  		t.Fatalf("expected error, none found")
   257  	}
   258  	if sourceCount != 2 {
   259  		t.Fatalf("Expected source function called twice, called: %v", sourceCount)
   260  	}
   261  	if transformerCount != 2 {
   262  		t.Fatalf("Expected transformer function called twice, called: %v", transformerCount)
   263  	}
   264  }
   265  
   266  func TestTransformSourceError(t *testing.T) {
   267  	sourceCount := 0
   268  	source := cached.Func(func() ([]byte, string, error) {
   269  		sourceCount += 1
   270  		return nil, "", errors.New("source error")
   271  	})
   272  	transformerCount := 0
   273  	transformer := cached.Transform(func(value []byte, etag string, err error) ([]byte, string, error) {
   274  		transformerCount += 1
   275  		if err != nil {
   276  			return nil, "", err
   277  		}
   278  		return []byte("transformed " + string(value)), "transformed " + etag, nil
   279  	}, source)
   280  	if _, _, err := transformer.Get(); err == nil {
   281  		t.Fatalf("expected error, none found")
   282  	}
   283  	if _, _, err := transformer.Get(); err == nil {
   284  		t.Fatalf("expected error, none found")
   285  	}
   286  	if sourceCount != 2 {
   287  		t.Fatalf("Expected source function called twice, called: %v", sourceCount)
   288  	}
   289  	if transformerCount != 2 {
   290  		t.Fatalf("Expected transformer function called twice, called: %v", transformerCount)
   291  	}
   292  }
   293  
   294  func TestTransformAlternateSourceError(t *testing.T) {
   295  	sourceCount := 0
   296  	source := cached.Func(func() ([]byte, string, error) {
   297  		sourceCount += 1
   298  		if sourceCount%2 == 0 {
   299  			return nil, "", errors.New("source error")
   300  		}
   301  		return []byte("source"), "source", nil
   302  	})
   303  	transformerCount := 0
   304  	transformer := cached.Transform(func(value []byte, etag string, err error) ([]byte, string, error) {
   305  		transformerCount += 1
   306  		if err != nil {
   307  			return nil, "", err
   308  		}
   309  		return []byte("transformed " + string(value)), "transformed " + etag, err
   310  	}, source)
   311  	result, etag, err := transformer.Get()
   312  	if err != nil {
   313  		t.Fatalf("unexpected error: %v", err)
   314  	}
   315  	if want := "transformed source"; string(result) != want {
   316  		t.Fatalf("expected data = %v, got %v", want, string(result))
   317  	}
   318  	if want := "transformed source"; etag != want {
   319  		t.Fatalf("expected etag = %v, got %v", want, etag)
   320  	}
   321  	if _, _, err := transformer.Get(); err == nil {
   322  		t.Fatalf("expected error, none found")
   323  	}
   324  	result, etag, err = transformer.Get()
   325  	if err != nil {
   326  		t.Fatalf("unexpected error: %v", err)
   327  	}
   328  	if want := "transformed source"; string(result) != want {
   329  		t.Fatalf("expected data = %v, got %v", want, string(result))
   330  	}
   331  	if want := "transformed source"; etag != want {
   332  		t.Fatalf("expected etag = %v, got %v", want, etag)
   333  	}
   334  	if _, _, err := transformer.Get(); err == nil {
   335  		t.Fatalf("expected error, none found")
   336  	}
   337  	if sourceCount != 4 {
   338  		t.Fatalf("Expected source function called 4x, called: %v", sourceCount)
   339  	}
   340  	if transformerCount != 4 {
   341  		t.Fatalf("Expected transformer function called 4x, called: %v", transformerCount)
   342  	}
   343  
   344  }
   345  
   346  func TestMerge(t *testing.T) {
   347  	source1Count := 0
   348  	source1 := cached.Func(func() ([]byte, string, error) {
   349  		source1Count += 1
   350  		return []byte("source1"), "source1", nil
   351  	})
   352  	source2Count := 0
   353  	source2 := cached.Func(func() ([]byte, string, error) {
   354  		source2Count += 1
   355  		return []byte("source2"), "source2", nil
   356  	})
   357  	mergerCount := 0
   358  	merger := cached.Merge(func(results map[string]cached.Result[[]byte]) ([]byte, string, error) {
   359  		mergerCount += 1
   360  		d := []string{}
   361  		e := []string{}
   362  		for _, result := range results {
   363  			if result.Err != nil {
   364  				return nil, "", result.Err
   365  			}
   366  			d = append(d, string(result.Value))
   367  			e = append(e, result.Etag)
   368  		}
   369  		sort.Strings(d)
   370  		sort.Strings(e)
   371  		return []byte("merged " + strings.Join(d, " and ")), "merged " + strings.Join(e, " and "), nil
   372  	}, map[string]cached.Value[[]byte]{
   373  		"source1": source1,
   374  		"source2": source2,
   375  	})
   376  	if _, _, err := merger.Get(); err != nil {
   377  		t.Fatalf("unexpected error: %v", err)
   378  	}
   379  	result, etag, err := merger.Get()
   380  	if err != nil {
   381  		t.Fatalf("unexpected error: %v", err)
   382  	}
   383  	if want := "merged source1 and source2"; string(result) != want {
   384  		t.Fatalf("expected data = %v, got %v", want, string(result))
   385  	}
   386  	if want := "merged source1 and source2"; etag != want {
   387  		t.Fatalf("expected etag = %v, got %v", want, etag)
   388  	}
   389  
   390  	if source1Count != 2 {
   391  		t.Fatalf("Expected source function called twice, called: %v", source1Count)
   392  	}
   393  	if source2Count != 2 {
   394  		t.Fatalf("Expected source function called twice, called: %v", source2Count)
   395  	}
   396  	if mergerCount != 1 {
   397  		t.Fatalf("Expected merger function called once, called: %v", mergerCount)
   398  	}
   399  }
   400  
   401  func TestMergeError(t *testing.T) {
   402  	source1Count := 0
   403  	source1 := cached.Func(func() ([]byte, string, error) {
   404  		source1Count += 1
   405  		return []byte("source1"), "source1", nil
   406  	})
   407  	source2Count := 0
   408  	source2 := cached.Func(func() ([]byte, string, error) {
   409  		source2Count += 1
   410  		return []byte("source2"), "source2", nil
   411  	})
   412  	mergerCount := 0
   413  	merger := cached.Merge(func(results map[string]cached.Result[[]byte]) ([]byte, string, error) {
   414  		mergerCount += 1
   415  		return nil, "", errors.New("merger error")
   416  	}, map[string]cached.Value[[]byte]{
   417  		"source1": source1,
   418  		"source2": source2,
   419  	})
   420  	if _, _, err := merger.Get(); err == nil {
   421  		t.Fatalf("expected error, none found")
   422  	}
   423  	if _, _, err := merger.Get(); err == nil {
   424  		t.Fatalf("expected error, none found")
   425  	}
   426  	if source1Count != 2 {
   427  		t.Fatalf("Expected source function called twice, called: %v", source1Count)
   428  	}
   429  	if source2Count != 2 {
   430  		t.Fatalf("Expected source function called twice, called: %v", source2Count)
   431  	}
   432  	if mergerCount != 2 {
   433  		t.Fatalf("Expected merger function called twice, called: %v", mergerCount)
   434  	}
   435  }
   436  
   437  func TestMergeSourceError(t *testing.T) {
   438  	source1Count := 0
   439  	source1 := cached.Func(func() ([]byte, string, error) {
   440  		source1Count += 1
   441  		return nil, "", errors.New("source1 error")
   442  	})
   443  	source2Count := 0
   444  	source2 := cached.Func(func() ([]byte, string, error) {
   445  		source2Count += 1
   446  		return []byte("source2"), "source2", nil
   447  	})
   448  	mergerCount := 0
   449  	merger := cached.Merge(func(results map[string]cached.Result[[]byte]) ([]byte, string, error) {
   450  		mergerCount += 1
   451  		d := []string{}
   452  		e := []string{}
   453  		for _, result := range results {
   454  			if result.Err != nil {
   455  				return nil, "", result.Err
   456  			}
   457  			d = append(d, string(result.Value))
   458  			e = append(e, result.Etag)
   459  		}
   460  		sort.Strings(d)
   461  		sort.Strings(e)
   462  		return []byte("merged " + strings.Join(d, " and ")), "merged " + strings.Join(e, " and "), nil
   463  	}, map[string]cached.Value[[]byte]{
   464  		"source1": source1,
   465  		"source2": source2,
   466  	})
   467  	if _, _, err := merger.Get(); err == nil {
   468  		t.Fatalf("expected error, none found")
   469  	}
   470  	if _, _, err := merger.Get(); err == nil {
   471  		t.Fatalf("expected error, none found")
   472  	}
   473  	if source1Count != 2 {
   474  		t.Fatalf("Expected source function called twice, called: %v", source1Count)
   475  	}
   476  	if source2Count != 2 {
   477  		t.Fatalf("Expected source function called twice, called: %v", source2Count)
   478  	}
   479  	if mergerCount != 2 {
   480  		t.Fatalf("Expected merger function called twice, called: %v", mergerCount)
   481  	}
   482  }
   483  
   484  func TestMergeAlternateSourceError(t *testing.T) {
   485  	source1Count := 0
   486  	source1 := cached.Func(func() ([]byte, string, error) {
   487  		source1Count += 1
   488  		if source1Count%2 == 0 {
   489  			return nil, "", errors.New("source1 error")
   490  		} else {
   491  			return []byte("source1"), "source1", nil
   492  		}
   493  	})
   494  	source2Count := 0
   495  	source2 := cached.Func(func() ([]byte, string, error) {
   496  		source2Count += 1
   497  		return []byte("source2"), "source2", nil
   498  	})
   499  	mergerCount := 0
   500  	merger := cached.Merge(func(results map[string]cached.Result[[]byte]) ([]byte, string, error) {
   501  		mergerCount += 1
   502  		d := []string{}
   503  		e := []string{}
   504  		for _, result := range results {
   505  			if result.Err != nil {
   506  				return nil, "", result.Err
   507  			}
   508  			d = append(d, string(result.Value))
   509  			e = append(e, result.Etag)
   510  		}
   511  		sort.Strings(d)
   512  		sort.Strings(e)
   513  		return []byte("merged " + strings.Join(d, " and ")), "merged " + strings.Join(e, " and "), nil
   514  	}, map[string]cached.Value[[]byte]{
   515  		"source1": source1,
   516  		"source2": source2,
   517  	})
   518  	result, etag, err := merger.Get()
   519  	if err != nil {
   520  		t.Fatalf("unexpected error: %v", err)
   521  	}
   522  	if want := "merged source1 and source2"; string(result) != want {
   523  		t.Fatalf("expected data = %v, got %v", want, string(result))
   524  	}
   525  	if want := "merged source1 and source2"; etag != want {
   526  		t.Fatalf("expected etag = %v, got %v", want, etag)
   527  	}
   528  	if _, _, err := merger.Get(); err == nil {
   529  		t.Fatalf("expected error, none found")
   530  	}
   531  	result, etag, err = merger.Get()
   532  	if err != nil {
   533  		t.Fatalf("unexpected error: %v", err)
   534  	}
   535  	if want := "merged source1 and source2"; string(result) != want {
   536  		t.Fatalf("expected data = %v, got %v", want, string(result))
   537  	}
   538  	if want := "merged source1 and source2"; etag != want {
   539  		t.Fatalf("expected etag = %v, got %v", want, etag)
   540  	}
   541  	if _, _, err := merger.Get(); err == nil {
   542  		t.Fatalf("expected error, none found")
   543  	}
   544  	if source1Count != 4 {
   545  		t.Fatalf("Expected source function called 4x, called: %v", source1Count)
   546  	}
   547  	if source2Count != 4 {
   548  		t.Fatalf("Expected source function called 4x, called: %v", source2Count)
   549  	}
   550  	if mergerCount != 4 {
   551  		t.Fatalf("Expected merger function called 4x, called: %v", mergerCount)
   552  	}
   553  }
   554  
   555  func TestAtomic(t *testing.T) {
   556  	sourceDataCount := 0
   557  	sourceData := cached.Func(func() ([]byte, string, error) {
   558  		sourceDataCount += 1
   559  		return []byte("source"), "source", nil
   560  	})
   561  	sourceData2Count := 0
   562  	sourceData2 := cached.Func(func() ([]byte, string, error) {
   563  		sourceData2Count += 1
   564  		return []byte("source2"), "source2", nil
   565  	})
   566  	sourceErrCount := 0
   567  	sourceErr := cached.Func(func() ([]byte, string, error) {
   568  		sourceErrCount += 1
   569  		return nil, "", errors.New("source error")
   570  	})
   571  
   572  	replaceable := &cached.Atomic[[]byte]{}
   573  	replaceable.Store(sourceErr)
   574  	if _, _, err := replaceable.Get(); err == nil {
   575  		t.Fatalf("expected error, found none")
   576  	}
   577  
   578  	replaceable.Store(sourceData)
   579  	result, etag, err := replaceable.Get()
   580  	if err != nil {
   581  		t.Fatalf("unexpected error: %v", err)
   582  	}
   583  	if want := "source"; string(result) != want {
   584  		t.Fatalf("expected data = %v, got %v", want, string(result))
   585  	}
   586  	if want := "source"; etag != want {
   587  		t.Fatalf("expected etag = %v, got %v", want, etag)
   588  	}
   589  
   590  	// replace with the same thing, shouldn't change anything
   591  	replaceable.Store(sourceData)
   592  	result, etag, err = replaceable.Get()
   593  	if err != nil {
   594  		t.Fatalf("unexpected error: %v", err)
   595  	}
   596  	if want := "source"; string(result) != want {
   597  		t.Fatalf("expected data = %v, got %v", want, string(result))
   598  	}
   599  	if want := "source"; etag != want {
   600  		t.Fatalf("expected etag = %v, got %v", want, etag)
   601  	}
   602  
   603  	// when replacing with an error source, we see the error again
   604  	replaceable.Store(sourceErr)
   605  	result, etag, err = replaceable.Get()
   606  	if err == nil {
   607  		t.Fatalf("unexpected success")
   608  	}
   609  
   610  	replaceable.Store(sourceData2)
   611  	result, etag, err = replaceable.Get()
   612  	if err != nil {
   613  		t.Fatalf("unexpected error: %v", err)
   614  	}
   615  	if want := "source2"; string(result) != want {
   616  		t.Fatalf("expected data = %v, got %v", want, string(result))
   617  	}
   618  	if want := "source2"; etag != want {
   619  		t.Fatalf("expected etag = %v, got %v", want, etag)
   620  	}
   621  	if sourceDataCount != 2 {
   622  		t.Fatalf("Expected sourceData function called twice, called: %v", sourceDataCount)
   623  	}
   624  	if sourceData2Count != 1 {
   625  		t.Fatalf("Expected sourceData2 function called once, called: %v", sourceData2Count)
   626  	}
   627  	if sourceErrCount != 2 {
   628  		t.Fatalf("Expected error source function called once, called: %v", sourceErrCount)
   629  	}
   630  }
   631  
   632  func TestLastSuccess(t *testing.T) {
   633  	sourceDataCount := 0
   634  	sourceData := cached.Func(func() ([]byte, string, error) {
   635  		sourceDataCount += 1
   636  		return []byte("source"), "source", nil
   637  	})
   638  	sourceData2Count := 0
   639  	sourceData2 := cached.Func(func() ([]byte, string, error) {
   640  		sourceData2Count += 1
   641  		return []byte("source2"), "source2", nil
   642  	})
   643  
   644  	sourceErrCount := 0
   645  	sourceErr := cached.Func(func() ([]byte, string, error) {
   646  		sourceErrCount += 1
   647  		return nil, "", errors.New("source error")
   648  	})
   649  	lastSuccess := &cached.LastSuccess[[]byte]{}
   650  	lastSuccess.Store(sourceErr)
   651  	if _, _, err := lastSuccess.Get(); err == nil {
   652  		t.Fatalf("expected error, found none")
   653  	}
   654  	lastSuccess.Store(sourceData)
   655  	result, etag, err := lastSuccess.Get()
   656  	if err != nil {
   657  		t.Fatalf("unexpected error: %v", err)
   658  	}
   659  	if want := "source"; string(result) != want {
   660  		t.Fatalf("expected data = %v, got %v", want, string(result))
   661  	}
   662  	if want := "source"; etag != want {
   663  		t.Fatalf("expected etag = %v, got %v", want, etag)
   664  	}
   665  	// replace with the same thing, shouldn't change anything
   666  	lastSuccess.Store(sourceData)
   667  	result, etag, err = lastSuccess.Get()
   668  	if err != nil {
   669  		t.Fatalf("unexpected error: %v", err)
   670  	}
   671  	if want := "source"; string(result) != want {
   672  		t.Fatalf("expected data = %v, got %v", want, string(result))
   673  	}
   674  	if want := "source"; etag != want {
   675  		t.Fatalf("expected etag = %v, got %v", want, etag)
   676  	}
   677  	// Even if we replace with something that fails, we continue to return the success.
   678  	lastSuccess.Store(sourceErr)
   679  	result, etag, err = lastSuccess.Get()
   680  	if err != nil {
   681  		t.Fatalf("unexpected error: %v", err)
   682  	}
   683  	if want := "source"; string(result) != want {
   684  		t.Fatalf("expected data = %v, got %v", want, string(result))
   685  	}
   686  	if want := "source"; etag != want {
   687  		t.Fatalf("expected etag = %v, got %v", want, etag)
   688  	}
   689  	lastSuccess.Store(sourceData2)
   690  	result, etag, err = lastSuccess.Get()
   691  	if err != nil {
   692  		t.Fatalf("unexpected error: %v", err)
   693  	}
   694  	if want := "source2"; string(result) != want {
   695  		t.Fatalf("expected data = %v, got %v", want, string(result))
   696  	}
   697  	if want := "source2"; etag != want {
   698  		t.Fatalf("expected etag = %v, got %v", want, etag)
   699  	}
   700  	if sourceDataCount != 2 {
   701  		t.Fatalf("Expected sourceData function called twice, called: %v", sourceDataCount)
   702  	}
   703  	if sourceData2Count != 1 {
   704  		t.Fatalf("Expected sourceData2 function called once, called: %v", sourceData2Count)
   705  	}
   706  	if sourceErrCount != 2 {
   707  		t.Fatalf("Expected error source function called once, called: %v", sourceErrCount)
   708  	}
   709  }
   710  
   711  func TestLastSuccessEtag(t *testing.T) {
   712  	lastSuccess := &cached.LastSuccess[bool]{}
   713  	lastSuccess.Store(cached.Func(func() (bool, string, error) {
   714  		return false, "hash", nil
   715  	}))
   716  	lastSuccess.Store(cached.Static(true, "hash2"))
   717  	result, etag, _ := lastSuccess.Get()
   718  	if actual := etag; actual != "hash2" {
   719  		t.Fatalf(`expected "hash2", got %q`, actual)
   720  	}
   721  	if result != true {
   722  		t.Fatal(`expected "true", got "false"`)
   723  	}
   724  }
   725  
   726  func TestLastSuccessAlternateError(t *testing.T) {
   727  	sourceCount := 0
   728  	source := cached.Func(func() ([]byte, string, error) {
   729  		sourceCount += 1
   730  		if sourceCount%2 == 0 {
   731  			return nil, "", errors.New("source error")
   732  		} else {
   733  			return []byte("source"), "source", nil
   734  		}
   735  	})
   736  	lastSuccess := &cached.LastSuccess[[]byte]{}
   737  	lastSuccess.Store(source)
   738  	result, etag, err := lastSuccess.Get()
   739  	if err != nil {
   740  		t.Fatalf("unexpected error: %v", err)
   741  	}
   742  	if want := "source"; string(result) != want {
   743  		t.Fatalf("expected data = %v, got %v", want, string(result))
   744  	}
   745  	if want := "source"; etag != want {
   746  		t.Fatalf("expected etag = %v, got %v", want, etag)
   747  	}
   748  	result, etag, err = lastSuccess.Get()
   749  	if err != nil {
   750  		t.Fatalf("unexpected error: %v", err)
   751  	}
   752  	if want := "source"; string(result) != want {
   753  		t.Fatalf("expected data = %v, got %v", want, string(result))
   754  	}
   755  	if want := "source"; etag != want {
   756  		t.Fatalf("expected etag = %v, got %v", want, etag)
   757  	}
   758  	result, etag, err = lastSuccess.Get()
   759  	if err != nil {
   760  		t.Fatalf("unexpected error: %v", err)
   761  	}
   762  	if want := "source"; string(result) != want {
   763  		t.Fatalf("expected data = %v, got %v", want, string(result))
   764  	}
   765  	if want := "source"; etag != want {
   766  		t.Fatalf("expected etag = %v, got %v", want, etag)
   767  	}
   768  	result, etag, err = lastSuccess.Get()
   769  	if err != nil {
   770  		t.Fatalf("unexpected error: %v", err)
   771  	}
   772  	if want := "source"; string(result) != want {
   773  		t.Fatalf("expected data = %v, got %v", want, string(result))
   774  	}
   775  	if want := "source"; etag != want {
   776  		t.Fatalf("expected etag = %v, got %v", want, etag)
   777  	}
   778  	if sourceCount != 4 {
   779  		t.Fatalf("Expected sourceData function called 4x, called: %v", sourceCount)
   780  	}
   781  }
   782  
   783  func TestLastSuccessWithTransformer(t *testing.T) {
   784  	lastSuccess := &cached.LastSuccess[[]byte]{}
   785  	lastSuccess.Store(cached.Static([]byte("source"), "source"))
   786  	transformerCount := 0
   787  	transformed := cached.Transform[[]byte](func(value []byte, etag string, err error) ([]byte, string, error) {
   788  		transformerCount += 1
   789  		if err != nil {
   790  			return nil, "", err
   791  		}
   792  		return []byte("transformed " + string(value)), "transformed " + etag, nil
   793  	}, lastSuccess)
   794  	result, etag, err := transformed.Get()
   795  	if err != nil {
   796  		t.Fatalf("unexpected error: %v", err)
   797  	}
   798  	result, etag, err = transformed.Get()
   799  	if err != nil {
   800  		t.Fatalf("unexpected error: %v", err)
   801  	}
   802  	if want := "transformed source"; string(result) != want {
   803  		t.Fatalf("expected data = %v, got %v", want, string(result))
   804  	}
   805  	if want := "transformed source"; etag != want {
   806  		t.Fatalf("expected etag = %v, got %v", want, etag)
   807  	}
   808  	// replace with new cache, transformer shouldn't be affected (or called)
   809  	lastSuccess.Store(cached.Static([]byte("source"), "source"))
   810  	result, etag, err = transformed.Get()
   811  	if err != nil {
   812  		t.Fatalf("unexpected error: %v", err)
   813  	}
   814  	result, etag, err = transformed.Get()
   815  	if err != nil {
   816  		t.Fatalf("unexpected error: %v", err)
   817  	}
   818  	if want := "transformed source"; string(result) != want {
   819  		t.Fatalf("expected data = %v, got %v", want, string(result))
   820  	}
   821  	if want := "transformed source"; etag != want {
   822  		t.Fatalf("expected etag = %v, got %v", want, etag)
   823  	}
   824  	// replace with failing cache, transformer should still not be affected (or called)
   825  	lastSuccess.Store(cached.Result[[]byte]{Err: errors.New("source error")})
   826  	result, etag, err = transformed.Get()
   827  	if err != nil {
   828  		t.Fatalf("unexpected error: %v", err)
   829  	}
   830  	result, etag, err = transformed.Get()
   831  	if err != nil {
   832  		t.Fatalf("unexpected error: %v", err)
   833  	}
   834  	if want := "transformed source"; string(result) != want {
   835  		t.Fatalf("expected data = %v, got %v", want, string(result))
   836  	}
   837  	if want := "transformed source"; etag != want {
   838  		t.Fatalf("expected etag = %v, got %v", want, etag)
   839  	}
   840  
   841  	if transformerCount != 1 {
   842  		t.Fatalf("Expected transformer function called once, called: %v", transformerCount)
   843  	}
   844  }
   845  
   846  // Here is an example of how one can write a cache that will constantly
   847  // be pulled, while actually recomputing the results only as needed.
   848  func Example() {
   849  	// Merge Json is a replaceable cache, since we'll want it to
   850  	// change a few times.
   851  	mergeJson := &cached.LastSuccess[[]byte]{}
   852  
   853  	one := cached.Once(cached.Func(func() ([]byte, string, error) {
   854  		// This one is computed lazily, only when requested, and only once.
   855  		return []byte("one"), "one", nil
   856  	}))
   857  	two := cached.Func(func() ([]byte, string, error) {
   858  		// This cache is re-computed every time.
   859  		return []byte("two"), "two", nil
   860  	})
   861  	// This cache is computed once, and is not lazy at all.
   862  	three := cached.Static([]byte("three"), "three")
   863  
   864  	// This cache will allow us to replace a branch of the tree
   865  	// efficiently.
   866  
   867  	lastSuccess := &cached.LastSuccess[[]byte]{}
   868  	lastSuccess.Store(cached.Static([]byte("four"), "four"))
   869  
   870  	merger := func(results map[string]cached.Result[[]byte]) ([]byte, string, error) {
   871  		var out = []json.RawMessage{}
   872  		var resultEtag string
   873  		for _, result := range results {
   874  			if result.Err != nil {
   875  				return nil, "", result.Err
   876  			}
   877  			resultEtag += result.Etag
   878  			out = append(out, result.Value)
   879  		}
   880  		data, err := json.Marshal(out)
   881  		if err != nil {
   882  			return nil, "", err
   883  		}
   884  		return data, resultEtag, nil
   885  	}
   886  
   887  	mergeJson.Store(cached.Merge(merger, map[string]cached.Value[[]byte]{
   888  		"one":         one,
   889  		"two":         two,
   890  		"three":       three,
   891  		"replaceable": lastSuccess,
   892  	}))
   893  
   894  	// Create a new cache that indents a buffer. This should only be
   895  	// called if the buffer has changed.
   896  	indented := cached.Transform[[]byte](func(js []byte, etag string, err error) ([]byte, string, error) {
   897  		// Get the json from the previous layer of cache, before
   898  		// we indent.
   899  		if err != nil {
   900  			return nil, "", err
   901  		}
   902  		var out bytes.Buffer
   903  		json.Indent(&out, js, "", "\t")
   904  		return out.Bytes(), etag, nil
   905  	}, mergeJson)
   906  
   907  	// We have "clients" that constantly pulls the indented format.
   908  	go func() {
   909  		for {
   910  			if _, _, err := indented.Get(); err != nil {
   911  				panic(fmt.Errorf("invalid error: %v", err))
   912  			}
   913  		}
   914  	}()
   915  
   916  	failure := cached.Result[[]byte]{Err: errors.New("Invalid cache!")}
   917  	// Insert a new sub-cache that fails, it should just be ignored.
   918  	mergeJson.Store(cached.Merge(merger, map[string]cached.Value[[]byte]{
   919  		"one":         one,
   920  		"two":         two,
   921  		"three":       three,
   922  		"replaceable": lastSuccess,
   923  		"failure":     failure,
   924  	}))
   925  
   926  	// We can replace just a branch of the dependency tree.
   927  	lastSuccess.Store(cached.Static([]byte("five"), "five"))
   928  
   929  	// We can replace to remove the failure and one of the sub-cached.
   930  	mergeJson.Store(cached.Merge(merger, map[string]cached.Value[[]byte]{
   931  		"one":         one,
   932  		"two":         two,
   933  		"replaceable": lastSuccess,
   934  	}))
   935  }
   936  
   937  func TestListMerger(t *testing.T) {
   938  	source1Count := 0
   939  	source1 := cached.Func(func() ([]byte, string, error) {
   940  		source1Count += 1
   941  		return []byte("source1"), "source1", nil
   942  	})
   943  	source2Count := 0
   944  	source2 := cached.Func(func() ([]byte, string, error) {
   945  		source2Count += 1
   946  		return []byte("source2"), "source2", nil
   947  	})
   948  	mergerCount := 0
   949  	merger := cached.MergeList(func(results []cached.Result[[]byte]) ([]byte, string, error) {
   950  		mergerCount += 1
   951  		d := []string{}
   952  		e := []string{}
   953  		for _, result := range results {
   954  			if result.Err != nil {
   955  				return nil, "", result.Err
   956  			}
   957  			d = append(d, string(result.Value))
   958  			e = append(e, result.Etag)
   959  		}
   960  		return []byte("merged " + strings.Join(d, " and ")), "merged " + strings.Join(e, " and "), nil
   961  	}, []cached.Value[[]byte]{
   962  		source1, source2,
   963  	})
   964  	if _, _, err := merger.Get(); err != nil {
   965  		t.Fatalf("unexpected error: %v", err)
   966  	}
   967  	result, etag, err := merger.Get()
   968  	if err != nil {
   969  		t.Fatalf("unexpected error: %v", err)
   970  	}
   971  	if want := "merged source1 and source2"; string(result) != want {
   972  		t.Fatalf("expected data = %v, got %v", want, string(result))
   973  	}
   974  	if want := "merged source1 and source2"; etag != want {
   975  		t.Fatalf("expected etag = %v, got %v", want, etag)
   976  	}
   977  
   978  	if source1Count != 2 {
   979  		t.Fatalf("Expected source function called twice, called: %v", source1Count)
   980  	}
   981  	if source2Count != 2 {
   982  		t.Fatalf("Expected source function called twice, called: %v", source2Count)
   983  	}
   984  	if mergerCount != 1 {
   985  		t.Fatalf("Expected merger function called once, called: %v", mergerCount)
   986  	}
   987  }
   988  
   989  func TestMergeListSourceError(t *testing.T) {
   990  	source1Count := 0
   991  	source1 := cached.Func(func() ([]byte, string, error) {
   992  		source1Count += 1
   993  		return nil, "", errors.New("source1 error")
   994  	})
   995  	source2Count := 0
   996  	source2 := cached.Func(func() ([]byte, string, error) {
   997  		source2Count += 1
   998  		return []byte("source2"), "source2", nil
   999  	})
  1000  	mergerCount := 0
  1001  	merger := cached.MergeList(func(results []cached.Result[[]byte]) ([]byte, string, error) {
  1002  		mergerCount += 1
  1003  		d := []string{}
  1004  		e := []string{}
  1005  		for _, result := range results {
  1006  			if result.Err != nil {
  1007  				return nil, "", result.Err
  1008  			}
  1009  			d = append(d, string(result.Value))
  1010  			e = append(e, result.Etag)
  1011  		}
  1012  		return []byte("merged " + strings.Join(d, " and ")), "merged " + strings.Join(e, " and "), nil
  1013  	}, []cached.Value[[]byte]{
  1014  		source1, source2,
  1015  	})
  1016  	if _, _, err := merger.Get(); err == nil {
  1017  		t.Fatalf("expected error, none found")
  1018  	}
  1019  	if _, _, err := merger.Get(); err == nil {
  1020  		t.Fatalf("expected error, none found")
  1021  	}
  1022  	if source1Count != 2 {
  1023  		t.Fatalf("Expected source function called twice, called: %v", source1Count)
  1024  	}
  1025  	if source2Count != 2 {
  1026  		t.Fatalf("Expected source function called twice, called: %v", source2Count)
  1027  	}
  1028  	if mergerCount != 2 {
  1029  		t.Fatalf("Expected merger function called twice, called: %v", mergerCount)
  1030  	}
  1031  }
  1032  
  1033  func TestMergeListAlternateSourceError(t *testing.T) {
  1034  	source1Count := 0
  1035  	source1 := cached.Func(func() ([]byte, string, error) {
  1036  		source1Count += 1
  1037  		if source1Count%2 == 0 {
  1038  			return nil, "", errors.New("source1 error")
  1039  		} else {
  1040  			return []byte("source1"), "source1", nil
  1041  		}
  1042  	})
  1043  	source2Count := 0
  1044  	source2 := cached.Func(func() ([]byte, string, error) {
  1045  		source2Count += 1
  1046  		return []byte("source2"), "source2", nil
  1047  	})
  1048  	mergerCount := 0
  1049  	merger := cached.MergeList(func(results []cached.Result[[]byte]) ([]byte, string, error) {
  1050  		mergerCount += 1
  1051  		d := []string{}
  1052  		e := []string{}
  1053  		for _, result := range results {
  1054  			if result.Err != nil {
  1055  				return nil, "", result.Err
  1056  			}
  1057  			d = append(d, string(result.Value))
  1058  			e = append(e, result.Etag)
  1059  		}
  1060  		return []byte("merged " + strings.Join(d, " and ")), "merged " + strings.Join(e, " and "), nil
  1061  	}, []cached.Value[[]byte]{
  1062  		source1, source2,
  1063  	})
  1064  	result, etag, err := merger.Get()
  1065  	if err != nil {
  1066  		t.Fatalf("unexpected error: %v", err)
  1067  	}
  1068  	if want := "merged source1 and source2"; string(result) != want {
  1069  		t.Fatalf("expected data = %v, got %v", want, string(result))
  1070  	}
  1071  	if want := "merged source1 and source2"; etag != want {
  1072  		t.Fatalf("expected etag = %v, got %v", want, etag)
  1073  	}
  1074  	if _, _, err := merger.Get(); err == nil {
  1075  		t.Fatalf("expected error, none found")
  1076  	}
  1077  	result, etag, err = merger.Get()
  1078  	if err != nil {
  1079  		t.Fatalf("unexpected error: %v", err)
  1080  	}
  1081  	if want := "merged source1 and source2"; string(result) != want {
  1082  		t.Fatalf("expected data = %v, got %v", want, string(result))
  1083  	}
  1084  	if want := "merged source1 and source2"; etag != want {
  1085  		t.Fatalf("expected etag = %v, got %v", want, etag)
  1086  	}
  1087  	if _, _, err := merger.Get(); err == nil {
  1088  		t.Fatalf("expected error, none found")
  1089  	}
  1090  	if source1Count != 4 {
  1091  		t.Fatalf("Expected source function called 4x, called: %v", source1Count)
  1092  	}
  1093  	if source2Count != 4 {
  1094  		t.Fatalf("Expected source function called 4x, called: %v", source2Count)
  1095  	}
  1096  	if mergerCount != 4 {
  1097  		t.Fatalf("Expected merger function called 4x, called: %v", mergerCount)
  1098  	}
  1099  }
  1100  
  1101  func TestListDAG(t *testing.T) {
  1102  	source := cached.Func(func() ([]byte, string, error) {
  1103  		return []byte("source"), "source", nil
  1104  	})
  1105  	transformer1 := cached.Transform(func(value []byte, etag string, err error) ([]byte, string, error) {
  1106  		if err != nil {
  1107  			return nil, "", err
  1108  		}
  1109  		return []byte("transformed1 " + string(value)), "transformed1 " + etag, nil
  1110  	}, source)
  1111  	transformer2 := cached.Transform(func(value []byte, etag string, err error) ([]byte, string, error) {
  1112  		if err != nil {
  1113  			return nil, "", err
  1114  		}
  1115  		return []byte("transformed2 " + string(value)), "transformed2 " + etag, nil
  1116  	}, source)
  1117  	merger := cached.MergeList(func(results []cached.Result[[]byte]) ([]byte, string, error) {
  1118  		d := []string{}
  1119  		e := []string{}
  1120  		for _, result := range results {
  1121  			if result.Err != nil {
  1122  				return nil, "", result.Err
  1123  			}
  1124  			d = append(d, string(result.Value))
  1125  			e = append(e, result.Etag)
  1126  		}
  1127  		return []byte("merged " + strings.Join(d, " and ")), "merged " + strings.Join(e, " and "), nil
  1128  	}, []cached.Value[[]byte]{
  1129  		transformer1, transformer2,
  1130  	})
  1131  	result, etag, err := merger.Get()
  1132  	if err != nil {
  1133  		t.Fatalf("Unexpected error: %v", err)
  1134  	}
  1135  	if want := "merged transformed1 source and transformed2 source"; string(result) != want {
  1136  		t.Fatalf("expected data = %v, got %v", want, string(result))
  1137  	}
  1138  	if want := "merged transformed1 source and transformed2 source"; etag != want {
  1139  		t.Fatalf("expected etag = %v, got %v", want, etag)
  1140  	}
  1141  }
  1142  
  1143  func randomString(length uint) string {
  1144  	bytes := make([]byte, 6)
  1145  	rand.Read(bytes)
  1146  	return string(bytes)
  1147  
  1148  }
  1149  
  1150  func NewRandomSource() cached.Value[int64] {
  1151  	return cached.Once(cached.Func(func() (int64, string, error) {
  1152  		bytes := make([]byte, 6)
  1153  		rand.Read(bytes)
  1154  		return rand.Int63(), randomString(10), nil
  1155  	}))
  1156  }
  1157  
  1158  func repeatedGet(data cached.Value[int64], end time.Time, wg *sync.WaitGroup) {
  1159  	for time.Now().Before(end) {
  1160  		_, _, _ = data.Get()
  1161  	}
  1162  	wg.Done()
  1163  }
  1164  
  1165  func TestThreadSafe(t *testing.T) {
  1166  	end := time.Now().Add(time.Second)
  1167  	wg := sync.WaitGroup{}
  1168  	static := NewRandomSource()
  1169  	wg.Add(1)
  1170  	go repeatedGet(static, end, &wg)
  1171  	result := cached.Static(rand.Int63(), randomString(10))
  1172  	wg.Add(1)
  1173  	go repeatedGet(result, end, &wg)
  1174  	replaceable := &cached.LastSuccess[int64]{}
  1175  	replaceable.Store(NewRandomSource())
  1176  	wg.Add(1)
  1177  	go repeatedGet(replaceable, end, &wg)
  1178  	wg.Add(1)
  1179  	go func(r cached.Replaceable[int64], end time.Time, wg *sync.WaitGroup) {
  1180  		for time.Now().Before(end) {
  1181  			r.Store(NewRandomSource())
  1182  		}
  1183  		wg.Done()
  1184  	}(replaceable, end, &wg)
  1185  	merger := cached.Merge(func(results map[string]cached.Result[int64]) (int64, string, error) {
  1186  		sum := int64(0)
  1187  		for _, result := range results {
  1188  			sum += result.Value
  1189  		}
  1190  		return sum, randomString(10), nil
  1191  	}, map[string]cached.Value[int64]{
  1192  		"one": NewRandomSource(),
  1193  		"two": NewRandomSource(),
  1194  	})
  1195  	wg.Add(1)
  1196  	go repeatedGet(merger, end, &wg)
  1197  	transformer := cached.Transform(func(value int64, etag string, err error) (int64, string, error) {
  1198  		return value + 5, randomString(10), nil
  1199  	}, NewRandomSource())
  1200  	wg.Add(1)
  1201  	go repeatedGet(transformer, end, &wg)
  1202  
  1203  	listmerger := cached.MergeList(func(results []cached.Result[int64]) (int64, string, error) {
  1204  		sum := int64(0)
  1205  		for i := range results {
  1206  			sum += results[i].Value
  1207  		}
  1208  		return sum, randomString(10), nil
  1209  	}, []cached.Value[int64]{static, result, replaceable, merger, transformer})
  1210  	wg.Add(1)
  1211  	go repeatedGet(listmerger, end, &wg)
  1212  
  1213  	wg.Wait()
  1214  }