azure-container-networking/refresh/fetcher_test.go

162 строки
4.2 KiB
Go

package refresh_test
import (
"context"
"fmt"
"net/netip"
"sync"
"testing"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/nodesubnet"
"github.com/Azure/azure-container-networking/nmagent"
"github.com/Azure/azure-container-networking/refresh"
)
// Mock client that simply tracks if refresh has been called
type TestClient struct {
refreshCount int
responses []nmagent.Interfaces
mu sync.Mutex
}
// FetchRefreshCount atomically fetches the refresh count
func (c *TestClient) FetchRefreshCount() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.refreshCount
}
// UpdateRefreshCount atomically updates the refresh count
func (c *TestClient) UpdateRefreshCount() {
c.mu.Lock()
defer c.mu.Unlock()
c.refreshCount++
}
// Mock refresh
func (c *TestClient) GetInterfaceIPInfo(_ context.Context) (nmagent.Interfaces, error) {
defer c.UpdateRefreshCount()
if c.refreshCount >= len(c.responses) {
return c.responses[len(c.responses)-1], nil
}
return c.responses[c.refreshCount], nil
}
var _ nodesubnet.InterfaceRetriever = &TestClient{}
// Mock client that simply consumes fetched IPs
type TestConsumer struct {
consumeCount int
mu sync.Mutex
}
// FetchConsumeCount atomically fetches the consume count
func (c *TestConsumer) FetchConsumeCount() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.consumeCount
}
// UpdateConsumeCount atomically updates the consume count
func (c *TestConsumer) UpdateConsumeCount() {
c.mu.Lock()
defer c.mu.Unlock()
c.consumeCount++
}
// Mock IP update
func (c *TestConsumer) ConsumeInterfaces(intfs nmagent.Interfaces) error {
fmt.Printf("Consumed interfaces: %v\n", intfs)
c.UpdateConsumeCount()
return nil
}
func TestRefresh(t *testing.T) {
clientPtr := &TestClient{
refreshCount: 0,
responses: []nmagent.Interfaces{
{
Entries: []nmagent.Interface{
{
MacAddress: nmagent.MACAddress{0x00, 0x0D, 0x3A, 0xF9, 0xDC, 0xA6},
IsPrimary: true,
InterfaceSubnets: []nmagent.InterfaceSubnet{
{
Prefix: "10.240.0.0/16",
IPAddress: []nmagent.NodeIP{
{
Address: nmagent.IPAddress(netip.AddrFrom4([4]byte{10, 240, 0, 5})),
IsPrimary: true,
},
{
Address: nmagent.IPAddress(netip.AddrFrom4([4]byte{10, 240, 0, 6})),
IsPrimary: false,
},
},
},
},
},
},
},
{
Entries: []nmagent.Interface{
{
MacAddress: nmagent.MACAddress{0x00, 0x0D, 0x3A, 0xF9, 0xDC, 0xA6},
IsPrimary: true,
InterfaceSubnets: []nmagent.InterfaceSubnet{
{
Prefix: "10.240.0.0/16",
IPAddress: []nmagent.NodeIP{
{
Address: nmagent.IPAddress(netip.AddrFrom4([4]byte{10, 240, 0, 5})),
IsPrimary: true,
},
},
},
},
},
},
},
},
mu: sync.Mutex{},
}
consumerPtr := &TestConsumer{}
fetcher := refresh.NewFetcher[nmagent.Interfaces](clientPtr.GetInterfaceIPInfo, 0, 0, consumerPtr.ConsumeInterfaces, logger.Log)
ticker := refresh.NewMockTickProvider()
fetcher.SetTicker(ticker)
ctx, cancel := testContext(t)
defer cancel()
fetcher.Start(ctx)
ticker.Tick() // Trigger a refresh
ticker.Tick() // This tick will be read only after previous refresh is done
ticker.Tick() // This call will block until the prevous tick is read
// At least 2 refreshes - one initial and one after the first tick should be done
if clientPtr.FetchRefreshCount() < 2 {
t.Error("Not enough refreshes")
}
// Exactly 2 consumes - one initial and one after the first tick should be done (responses are different).
// Then no more, since the response is unchanged
if consumerPtr.FetchConsumeCount() != 2 {
t.Error("Exactly two consumes expected (for two different responses)")
}
}
// testContext creates a context from the provided testing.T that will be
// canceled if the test suite is terminated.
func testContext(t *testing.T) (context.Context, context.CancelFunc) {
if deadline, ok := t.Deadline(); ok {
return context.WithDeadline(context.Background(), deadline)
}
return context.WithCancel(context.Background())
}
func init() {
logger.InitLogger("testlogs", 0, 0, "./")
}