github.com/elfadel/cilium@v1.6.12/pkg/datapath/loader/cache_test.go (about) 1 // Copyright 2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build privileged_tests 16 17 package loader 18 19 import ( 20 "context" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "time" 25 26 "github.com/cilium/cilium/pkg/datapath/linux" 27 "github.com/cilium/cilium/pkg/testutils" 28 29 . "gopkg.in/check.v1" 30 ) 31 32 func (s *LoaderTestSuite) TestobjectCache(c *C) { 33 tmpDir, err := ioutil.TempDir("", "cilium_test") 34 c.Assert(err, IsNil) 35 defer os.RemoveAll(tmpDir) 36 37 ctx, cancel := context.WithTimeout(context.Background(), contextTimeout) 38 defer cancel() 39 40 cache := newObjectCache(linux.NewDatapath(linux.DatapathConfiguration{}, nil), nil, tmpDir) 41 realEP := testutils.NewTestEndpoint() 42 43 // First run should compile and generate the object. 44 _, isNew, err := cache.fetchOrCompile(ctx, &realEP, nil) 45 c.Assert(err, IsNil) 46 c.Assert(isNew, Equals, true) 47 48 // Same EP should not be compiled twice. 49 _, isNew, err = cache.fetchOrCompile(ctx, &realEP, nil) 50 c.Assert(err, IsNil) 51 c.Assert(isNew, Equals, false) 52 53 // Changing the ID should not generate a new object. 54 realEP.Id++ 55 _, isNew, err = cache.fetchOrCompile(ctx, &realEP, nil) 56 c.Assert(err, IsNil) 57 c.Assert(isNew, Equals, false) 58 59 // Changing a setting on the EP should generate a new object. 60 realEP.Opts.SetBool("foo", true) 61 _, isNew, err = cache.fetchOrCompile(ctx, &realEP, nil) 62 c.Assert(err, IsNil) 63 c.Assert(isNew, Equals, true) 64 } 65 66 type buildResult struct { 67 goroutine int 68 path string 69 compiled bool 70 err error 71 } 72 73 func receiveResult(c *C, results chan buildResult) (*buildResult, error) { 74 select { 75 case result := <-results: 76 if result.err != nil { 77 return nil, result.err 78 } 79 return &result, nil 80 case <-time.After(contextTimeout): 81 return nil, fmt.Errorf("Timed out waiting for goroutines to return") 82 } 83 } 84 85 func (s *LoaderTestSuite) TestobjectCacheParallel(c *C) { 86 tmpDir, err := ioutil.TempDir("", "cilium_test") 87 c.Assert(err, IsNil) 88 defer os.RemoveAll(tmpDir) 89 90 ctx, cancel := context.WithTimeout(context.Background(), contextTimeout) 91 defer cancel() 92 93 tests := []struct { 94 description string 95 builds int 96 divisor int 97 }{ 98 { 99 description: "One build, multiple blocking goroutines", 100 builds: 8, 101 divisor: 8, 102 }, 103 { 104 description: "Eight builds, half compile, half block", 105 builds: 8, 106 divisor: 2, 107 }, 108 { 109 description: "Eight unique builds", 110 builds: 8, 111 divisor: 1, 112 }, 113 } 114 115 for _, t := range tests { 116 c.Logf(" %s", t.description) 117 118 results := make(chan buildResult, t.builds) 119 cache := newObjectCache(linux.NewDatapath(linux.DatapathConfiguration{}, nil), nil, tmpDir) 120 for i := 0; i < t.builds; i++ { 121 go func(i int) { 122 ep := testutils.NewTestEndpoint() 123 opt := fmt.Sprintf("OPT%d", i/t.divisor) 124 ep.Opts.SetBool(opt, true) 125 path, isNew, err := cache.fetchOrCompile(ctx, &ep, nil) 126 results <- buildResult{ 127 goroutine: i, 128 path: path, 129 compiled: isNew, 130 err: err, 131 } 132 }(i) 133 } 134 135 // First result will always be a compilation for the new set of options 136 compiled := make(map[string]int, t.builds) 137 used := make(map[string]int, t.builds) 138 for i := 0; i < t.builds; i++ { 139 result, err := receiveResult(c, results) 140 c.Assert(err, IsNil) 141 142 used[result.path] = used[result.path] + 1 143 if result.compiled { 144 compiled[result.path] = compiled[result.path] + 1 145 } 146 } 147 148 c.Assert(len(compiled), Equals, t.builds/t.divisor) 149 c.Assert(len(used), Equals, t.builds/t.divisor) 150 for _, templateCompileCount := range compiled { 151 // Only one goroutine compiles each template 152 c.Assert(templateCompileCount, Equals, 1) 153 } 154 for _, templateUseCount := range used { 155 // Based on the test parameters, a number of goroutines 156 // may share the same template. 157 c.Assert(templateUseCount, Equals, t.divisor) 158 } 159 } 160 }