mirror of
https://github.com/netbirdio/netbird.git
synced 2026-07-19 15:01:29 +02:00
110 lines
2.8 KiB
Go
110 lines
2.8 KiB
Go
package mdm
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// testReloadInterval for speeding up the ticker cadence under `go test`
|
|
const testReloadInterval = 1 * time.Second
|
|
|
|
// fakePolicyFetcher implements PolicyFetcher returning a scripted
|
|
// policy map. Goroutine-safe so the test can mutate the script while
|
|
// the ticker is observing it.
|
|
type fakePolicyFetcher struct {
|
|
mu sync.Mutex
|
|
values map[string]any
|
|
}
|
|
|
|
func (f *fakePolicyFetcher) Fetch() map[string]any {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
if f.values == nil {
|
|
return nil
|
|
}
|
|
out := make(map[string]any, len(f.values))
|
|
for k, v := range f.values {
|
|
out[k] = v
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (f *fakePolicyFetcher) set(values map[string]any) {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
f.values = values
|
|
}
|
|
|
|
func TestTicker_FiresOnChangeWithDelta(t *testing.T) {
|
|
fetcher := &fakePolicyFetcher{} // initial observation: empty (no enforcement)
|
|
loader := NewLoader(fetcher)
|
|
|
|
type change struct{ prev, curr *Policy }
|
|
changes := make(chan change, 1)
|
|
tk := NewTicker(testReloadInterval, loader)
|
|
require.Equal(t, testReloadInterval, tk.interval)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
done := make(chan struct{})
|
|
go func() {
|
|
tk.Run(ctx, func(prev, curr *Policy) error {
|
|
select {
|
|
case changes <- change{prev, curr}:
|
|
default:
|
|
}
|
|
return nil
|
|
})
|
|
close(done)
|
|
}()
|
|
// Stop Run and wait for it to exit before returning, so the test
|
|
// goroutine doesn't race the still-running ticker.
|
|
defer func() { cancel(); <-done }()
|
|
|
|
// Flip the OS-observed policy from empty to one managed key. The
|
|
// next tick must detect the diff and invoke onChange.
|
|
fetcher.set(map[string]any{KeyManagementURL: "https://mdm.example.com:443"})
|
|
|
|
select {
|
|
case c := <-changes:
|
|
assert.True(t, c.prev.IsEmpty(), "prev should be the initial empty policy")
|
|
assert.True(t, c.curr.HasKey(KeyManagementURL), "curr should carry the newly-pushed managed key")
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("onChange not invoked within 5s; ticker should fire every 1s under test")
|
|
}
|
|
}
|
|
|
|
func TestTicker_NoCallbackWhenPolicyUnchanged(t *testing.T) {
|
|
fetcher := &fakePolicyFetcher{values: map[string]any{KeyBlockInbound: true}}
|
|
loader := NewLoader(fetcher)
|
|
|
|
fired := make(chan struct{}, 1)
|
|
tk := NewTicker(testReloadInterval, loader)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
done := make(chan struct{})
|
|
go func() {
|
|
tk.Run(ctx, func(_, _ *Policy) error {
|
|
select {
|
|
case fired <- struct{}{}:
|
|
default:
|
|
}
|
|
return nil
|
|
})
|
|
close(done)
|
|
}()
|
|
defer func() { cancel(); <-done }()
|
|
|
|
// Over ~2 ticks at the 1s test cadence the policy never changes,
|
|
// so the diff guard must suppress the callback entirely.
|
|
select {
|
|
case <-fired:
|
|
t.Fatal("onChange fired despite an unchanged policy")
|
|
case <-time.After(2500 * time.Millisecond):
|
|
}
|
|
}
|