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  }