istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/mesh/watcher_test.go (about) 1 // Copyright Istio Authors 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 package mesh_test 16 17 import ( 18 "os" 19 "path/filepath" 20 "testing" 21 "time" 22 23 . "github.com/onsi/gomega" 24 "google.golang.org/protobuf/proto" 25 26 meshconfig "istio.io/api/mesh/v1alpha1" 27 "istio.io/istio/pkg/config/mesh" 28 "istio.io/istio/pkg/filewatcher" 29 "istio.io/istio/pkg/test/util/assert" 30 "istio.io/istio/pkg/util/protomarshal" 31 ) 32 33 func TestNewWatcherWithBadInputShouldFail(t *testing.T) { 34 g := NewWithT(t) 35 _, err := mesh.NewFileWatcher(filewatcher.NewWatcher(), "", false) 36 g.Expect(err).ToNot(BeNil()) 37 } 38 39 func TestWatcherShouldNotifyHandlers(t *testing.T) { 40 watcherShouldNotifyHandlers(t, false) 41 } 42 43 func TestMultiWatcherShouldNotifyHandlers(t *testing.T) { 44 watcherShouldNotifyHandlers(t, true) 45 } 46 47 func watcherShouldNotifyHandlers(t *testing.T, multi bool) { 48 path := newTempFile(t) 49 50 m := mesh.DefaultMeshConfig() 51 writeMessage(t, path, m) 52 53 w := newWatcher(t, path, multi) 54 assert.Equal(t, w.Mesh(), m) 55 56 doneCh := make(chan struct{}, 1) 57 58 var newM *meshconfig.MeshConfig 59 w.AddMeshHandler(func() { 60 newM = w.Mesh() 61 close(doneCh) 62 }) 63 64 // Change the file to trigger the update. 65 m.IngressClass = "foo" 66 writeMessage(t, path, m) 67 68 select { 69 case <-doneCh: 70 assert.Equal(t, newM, m) 71 assert.Equal(t, w.Mesh(), newM) 72 break 73 case <-time.After(time.Second * 5): 74 t.Fatal("timed out waiting for update") 75 } 76 } 77 78 func newWatcher(t testing.TB, filename string, multi bool) mesh.Watcher { 79 t.Helper() 80 w, err := mesh.NewFileWatcher(filewatcher.NewWatcher(), filename, multi) 81 if err != nil { 82 t.Fatal(err) 83 } 84 return w 85 } 86 87 func newTempFile(t testing.TB) string { 88 t.Helper() 89 90 f, err := os.CreateTemp(t.TempDir(), t.Name()) 91 if err != nil { 92 t.Fatal(err) 93 } 94 t.Cleanup(func() { _ = f.Close() }) 95 96 path, err := filepath.Abs(f.Name()) 97 if err != nil { 98 t.Fatal(err) 99 } 100 return path 101 } 102 103 func writeMessage(t testing.TB, path string, msg proto.Message) { 104 t.Helper() 105 yml, err := protomarshal.ToYAML(msg) 106 if err != nil { 107 t.Fatal(err) 108 } 109 writeFile(t, path, yml) 110 } 111 112 func writeFile(t testing.TB, path, content string) { 113 t.Helper() 114 if err := os.WriteFile(path, []byte(content), 0o666); err != nil { 115 t.Fatal(err) 116 } 117 } 118 119 func removeSilent(path string) { 120 _ = os.RemoveAll(path) 121 } 122 123 func BenchmarkGetMesh(b *testing.B) { 124 b.StopTimer() 125 126 path := newTempFile(b) 127 defer removeSilent(path) 128 129 m := mesh.DefaultMeshConfig() 130 writeMessage(b, path, m) 131 132 w := newWatcher(b, path, false) 133 134 b.StartTimer() 135 136 handler := func(mc *meshconfig.MeshConfig) { 137 // Do nothing 138 } 139 140 for i := 0; i < b.N; i++ { 141 handler(w.Mesh()) 142 } 143 }