mirror of
https://github.com/pomerium/pomerium.git
synced 2025-04-29 02:16:28 +02:00
This also replaces instances where we manually write "return ctx.Err()" with "return context.Cause(ctx)" which is functionally identical, but will also correctly propagate cause errors if present.
204 lines
5.2 KiB
Go
204 lines
5.2 KiB
Go
package config
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestFileWatcherSource(t *testing.T) {
|
|
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) {
|
|
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")
|
|
|
|
// the file watcher checks modification time, not contents
|
|
err = os.Chtimes(configFilePath, time.Now(), time.Now())
|
|
require.NoError(t, err)
|
|
|
|
select {
|
|
case <-ch:
|
|
if !enabled {
|
|
t.Error("expected OnConfigChange not to be fired after triggering a change to the underlying source")
|
|
}
|
|
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))
|
|
}
|