blob: 00af7953d034801b9e35e06e255b565e9965a460 [file] [log] [blame]
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package monitor
import (
"errors"
"testing"
"time"
)
import (
"github.com/onsi/gomega"
networking "istio.io/api/networking/v1alpha3"
)
import (
"github.com/apache/dubbo-go-pixiu/pilot/pkg/config/memory"
"github.com/apache/dubbo-go-pixiu/pkg/config"
"github.com/apache/dubbo-go-pixiu/pkg/config/schema/collection"
"github.com/apache/dubbo-go-pixiu/pkg/config/schema/collections"
"github.com/apache/dubbo-go-pixiu/pkg/config/schema/gvk"
"github.com/apache/dubbo-go-pixiu/pkg/test/util/retry"
)
var createConfigSet = []*config.Config{
{
Meta: config.Meta{
Name: "magic",
GroupVersionKind: gvk.Gateway,
},
Spec: &networking.Gateway{
Servers: []*networking.Server{
{
Port: &networking.Port{
Number: 80,
Protocol: "HTTP",
Name: "http",
},
Hosts: []string{"*.example.com"},
},
},
},
},
}
var updateConfigSet = []*config.Config{
{
Meta: config.Meta{
Name: "magic",
GroupVersionKind: gvk.Gateway,
},
Spec: &networking.Gateway{
Servers: []*networking.Server{
{
Port: &networking.Port{
Number: 80,
Protocol: "HTTP2",
Name: "http",
},
Hosts: []string{"*.example.com"},
},
},
},
},
}
func TestMonitorForChange(t *testing.T) {
g := gomega.NewWithT(t)
store := memory.Make(collection.SchemasFor(collections.IstioNetworkingV1Alpha3Gateways))
var (
callCount int
configs []*config.Config
err error
)
someConfigFunc := func() ([]*config.Config, error) {
switch callCount {
case 0:
configs = createConfigSet
err = nil
case 3:
configs = updateConfigSet
case 6:
configs = []*config.Config{}
}
callCount++
return configs, err
}
mon := NewMonitor("", store, someConfigFunc, "")
stop := make(chan struct{})
defer func() { close(stop) }()
mon.Start(stop)
go func() {
for i := 0; i < 10; i++ {
select {
case <-stop:
return
case mon.updateCh <- struct{}{}:
}
time.Sleep(time.Millisecond * 100)
}
}()
g.Eventually(func() error {
c, err := store.List(gvk.Gateway, "")
g.Expect(err).NotTo(gomega.HaveOccurred())
if len(c) != 1 {
return errors.New("no configs")
}
if c[0].Meta.Name != "magic" {
return errors.New("wrong config")
}
return nil
}).Should(gomega.Succeed())
g.Eventually(func() error {
c, err := store.List(gvk.Gateway, "")
g.Expect(err).NotTo(gomega.HaveOccurred())
if len(c) == 0 {
return errors.New("no config")
}
gateway := c[0].Spec.(*networking.Gateway)
if gateway.Servers[0].Port.Protocol != "HTTP2" {
return errors.New("protocol has not been updated")
}
return nil
}).Should(gomega.Succeed())
g.Eventually(func() ([]config.Config, error) {
return store.List(gvk.Gateway, "")
}).Should(gomega.HaveLen(0))
}
func TestMonitorFileSnapshot(t *testing.T) {
ts := &testState{
ConfigFiles: map[string][]byte{"gateway.yml": []byte(statusRegressionYAML)},
}
ts.testSetup(t)
store := memory.Make(collection.SchemasFor(collections.IstioNetworkingV1Alpha3Gateways))
fileWatcher := NewFileSnapshot(ts.rootPath, collection.SchemasFor(), "foo")
mon := NewMonitor("", store, fileWatcher.ReadConfigFiles, "")
stop := make(chan struct{})
defer func() { close(stop) }()
mon.Start(stop)
retry.UntilOrFail(t, func() bool { return store.Get(gvk.Gateway, "test", "test-1") != nil })
}
func TestMonitorForError(t *testing.T) {
g := gomega.NewWithT(t)
store := memory.Make(collection.SchemasFor(collections.IstioNetworkingV1Alpha3Gateways))
var (
callCount int
configs []*config.Config
err error
)
delay := make(chan struct{}, 1)
someConfigFunc := func() ([]*config.Config, error) {
switch callCount {
case 0:
configs = createConfigSet
err = nil
case 3:
configs = nil
err = errors.New("snapshotFunc can't connect")
delay <- struct{}{}
}
callCount++
return configs, err
}
mon := NewMonitor("", store, someConfigFunc, "")
stop := make(chan struct{})
defer func() { close(stop) }()
mon.Start(stop)
go func() {
updateTicker := time.NewTicker(100 * time.Millisecond)
numUpdates := 10
for {
select {
case <-stop:
updateTicker.Stop()
return
case <-updateTicker.C:
mon.updateCh <- struct{}{}
numUpdates--
if numUpdates == 0 {
updateTicker.Stop()
return
}
}
}
}()
// Test ensures that after a coplilot connection error the data remains
// nil data return and error return keeps the existing data aka createConfigSet
<-delay
g.Eventually(func() error {
c, err := store.List(gvk.Gateway, "")
g.Expect(err).NotTo(gomega.HaveOccurred())
if len(c) != 1 {
return errors.New("config files erased on Copilot error")
}
return nil
}).Should(gomega.Succeed())
}