-
Notifications
You must be signed in to change notification settings - Fork 244
/
Copy pathfetcher_test.go
161 lines (142 loc) · 4.17 KB
/
fetcher_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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, "./")
}