mirror of
https://github.com/pomerium/pomerium.git
synced 2025-04-28 18:06:34 +02:00
* remove context, add close * update tests * cleanup * fileutil: reimplement file watcher * remove test, simplify tree set code, fix data race
227 lines
5.6 KiB
Go
227 lines
5.6 KiB
Go
package config
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/pomerium/pomerium/internal/log"
|
|
"github.com/pomerium/pomerium/internal/signal"
|
|
"github.com/pomerium/pomerium/internal/testutil"
|
|
)
|
|
|
|
func TestFileWatcherSource(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpdir := t.TempDir()
|
|
|
|
err := os.WriteFile(filepath.Join(tmpdir, "example.txt"), []byte{1}, 0o600)
|
|
if !assert.NoError(t, err) {
|
|
return
|
|
}
|
|
|
|
err = os.WriteFile(filepath.Join(tmpdir, "kubernetes-example.txt"), []byte{2}, 0o600)
|
|
if !assert.NoError(t, err) {
|
|
return
|
|
}
|
|
|
|
newTest := func(enabled bool) func(*testing.T) {
|
|
return func(t *testing.T) {
|
|
ssrc := NewStaticSource(&Config{
|
|
Options: &Options{
|
|
CAFile: filepath.Join(tmpdir, "example.txt"),
|
|
Policies: []Policy{{
|
|
KubernetesServiceAccountTokenFile: filepath.Join(tmpdir, "kubernetes-example.txt"),
|
|
}},
|
|
RuntimeFlags: map[RuntimeFlag]bool{
|
|
RuntimeFlagConfigHotReload: enabled,
|
|
},
|
|
},
|
|
})
|
|
|
|
src := NewFileWatcherSource(context.Background(), ssrc)
|
|
ch := make(chan struct{}, 10)
|
|
src.OnConfigChange(context.Background(), func(_ context.Context, _ *Config) {
|
|
ch <- struct{}{}
|
|
})
|
|
|
|
err := os.WriteFile(filepath.Join(tmpdir, "example.txt"), []byte{1, 2}, 0o600)
|
|
if !assert.NoError(t, err) {
|
|
return
|
|
}
|
|
|
|
select {
|
|
case <-ch:
|
|
if !enabled {
|
|
t.Error("expected OnConfigChange not to be fired after modifying a file")
|
|
}
|
|
case <-time.After(time.Second):
|
|
if enabled {
|
|
t.Error("expected OnConfigChange to be fired after modifying a file")
|
|
}
|
|
}
|
|
|
|
require.Empty(t, ch, "expected exactly one OnConfigChange event")
|
|
|
|
err = os.WriteFile(filepath.Join(tmpdir, "kubernetes-example.txt"), []byte{2, 3}, 0o600)
|
|
if !assert.NoError(t, err) {
|
|
return
|
|
}
|
|
|
|
select {
|
|
case <-ch:
|
|
if !enabled {
|
|
t.Error("expected OnConfigChange not to be fired after modifying a file")
|
|
}
|
|
case <-time.After(time.Second):
|
|
if enabled {
|
|
t.Error("expected OnConfigChange to be fired after modifying a policy file")
|
|
}
|
|
}
|
|
|
|
require.Empty(t, ch, "expected exactly one OnConfigChange event")
|
|
|
|
ssrc.SetConfig(context.Background(), &Config{
|
|
Options: &Options{
|
|
CAFile: filepath.Join(tmpdir, "example.txt"),
|
|
},
|
|
})
|
|
|
|
select {
|
|
case <-ch:
|
|
case <-time.After(time.Second):
|
|
if enabled {
|
|
t.Error("expected OnConfigChange to be fired after triggering a change to the underlying source")
|
|
}
|
|
}
|
|
|
|
require.Empty(t, ch, "expected exactly one OnConfigChange event")
|
|
}
|
|
}
|
|
|
|
t.Run("Hot Reload Enabled", newTest(true))
|
|
t.Run("Hot Reload Disabled", newTest(false))
|
|
}
|
|
|
|
func TestFileOrEnvironmentSource(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpdir := t.TempDir()
|
|
|
|
err := os.WriteFile(filepath.Join(tmpdir, "example.txt"), []byte{1}, 0o600)
|
|
if !assert.NoError(t, err) {
|
|
return
|
|
}
|
|
|
|
err = os.WriteFile(filepath.Join(tmpdir, "kubernetes-example.txt"), []byte{2}, 0o600)
|
|
if !assert.NoError(t, err) {
|
|
return
|
|
}
|
|
|
|
newTest := func(enabled bool) func(*testing.T) {
|
|
return func(t *testing.T) {
|
|
initialConfigYaml := fmt.Sprintf(`
|
|
certificate_authority_file: %s
|
|
policy:
|
|
- from: https://foo
|
|
to: https://bar
|
|
kubernetes_service_account_token_file: %s
|
|
codec_type: auto
|
|
runtime_flags:
|
|
config_hot_reload: %t
|
|
`,
|
|
filepath.Join(tmpdir, "example.txt"),
|
|
filepath.Join(tmpdir, "kubernetes-example.txt"),
|
|
enabled,
|
|
)
|
|
configFilePath := filepath.Join(tmpdir, "config.yaml")
|
|
err := os.WriteFile(configFilePath, []byte(initialConfigYaml), 0o600)
|
|
require.NoError(t, err)
|
|
|
|
var src Source
|
|
src, err = NewFileOrEnvironmentSource(context.Background(), configFilePath, "")
|
|
require.NoError(t, err)
|
|
src = NewFileWatcherSource(context.Background(), src)
|
|
|
|
ch := make(chan struct{}, 10)
|
|
src.OnConfigChange(context.Background(), func(_ context.Context, _ *Config) {
|
|
ch <- struct{}{}
|
|
})
|
|
|
|
err = os.WriteFile(filepath.Join(tmpdir, "example.txt"), []byte{1, 2}, 0o600)
|
|
require.NoError(t, err)
|
|
|
|
select {
|
|
case <-ch:
|
|
if !enabled {
|
|
t.Error("expected OnConfigChange not to be fired after modifying a file")
|
|
}
|
|
case <-time.After(time.Second):
|
|
if enabled {
|
|
t.Error("expected OnConfigChange to be fired after modifying a file")
|
|
}
|
|
}
|
|
|
|
require.Empty(t, ch, "expected exactly one OnConfigChange event")
|
|
|
|
err = os.WriteFile(filepath.Join(tmpdir, "kubernetes-example.txt"), []byte{2, 3}, 0o600)
|
|
if !assert.NoError(t, err) {
|
|
return
|
|
}
|
|
|
|
select {
|
|
case <-ch:
|
|
if !enabled {
|
|
t.Error("expected OnConfigChange not to be fired after modifying a file")
|
|
}
|
|
case <-time.After(time.Second):
|
|
if enabled {
|
|
t.Error("expected OnConfigChange to be fired after modifying a policy file")
|
|
}
|
|
}
|
|
|
|
require.Empty(t, ch, "expected exactly one OnConfigChange event")
|
|
}
|
|
}
|
|
|
|
t.Run("Hot Reload Enabled", newTest(true))
|
|
t.Run("Hot Reload Disabled", newTest(false))
|
|
|
|
t.Run("SIGHUP", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ready := signal.New()
|
|
readyCh := ready.Bind()
|
|
|
|
ctx := testutil.GetContext(t, time.Minute)
|
|
ctx = log.Ctx(ctx).Hook(zerolog.HookFunc(func(_ *zerolog.Event, _ zerolog.Level, message string) {
|
|
if strings.Contains(message, "received SIGHUP") {
|
|
ready.Broadcast(ctx)
|
|
}
|
|
})).WithContext(ctx)
|
|
tmp := t.TempDir()
|
|
|
|
cfgFP := filepath.Join(tmp, "config.json")
|
|
require.NoError(t, os.WriteFile(cfgFP, []byte(`{}`), 0o600))
|
|
|
|
_, err := NewFileOrEnvironmentSource(ctx, cfgFP, "")
|
|
assert.NoError(t, err)
|
|
|
|
require.NoError(t, syscall.Kill(syscall.Getpid(), syscall.SIGHUP))
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
t.Error("expected to receive SIGHUP log message")
|
|
case <-readyCh:
|
|
}
|
|
})
|
|
}
|