@@ -17,28 +17,33 @@ limitations under the License.
1717package problemclient
1818
1919import (
20+ "context"
2021 "encoding/json"
2122 "fmt"
23+ "net/http"
24+ "net/http/httptest"
2225 "testing"
2326 "time"
2427
2528 "github.com/stretchr/testify/assert"
2629 v1 "k8s.io/api/core/v1"
2730 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31+ "k8s.io/apimachinery/pkg/runtime"
32+ typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
33+ "k8s.io/client-go/rest"
2834 "k8s.io/client-go/tools/record"
2935 testclock "k8s.io/utils/clock/testing"
3036)
3137
3238const (
33- testSource = "test"
34- testNode = "test-node"
39+ testSource = "test"
40+ testNode = "test-node"
41+ testNodeUID = "11111111-1111-1111-1111-111111111111"
3542)
3643
3744func newFakeProblemClient () * nodeProblemClient {
3845 return & nodeProblemClient {
39- nodeName : testNode ,
40- // There is no proper fake for *client.Client for now
41- // TODO(random-liu): Add test for SetConditions when we have good fake for *client.Client
46+ nodeName : testNode ,
4247 clock : testclock .NewFakeClock (time .Now ()),
4348 recorders : make (map [string ]record.EventRecorder ),
4449 nodeRef : getNodeRef ("" , testNode ),
@@ -93,3 +98,127 @@ func TestNodeRefHasAPIVersionV1(t *testing.T) {
9398 t .Errorf ("expected nodeRef.APIVersion to be 'v1', got %q" , client .nodeRef .APIVersion )
9499 }
95100}
101+
102+ func TestNodeRefWithUID (t * testing.T ) {
103+ client := newFakeProblemClient ()
104+
105+ if got := client .nodeRefWithUID ().UID ; got != "" {
106+ t .Errorf ("expected no UID before the node is read, got %q" , got )
107+ }
108+
109+ client .cacheNodeRef (testNodeUID )
110+
111+ if got := client .nodeRefWithUID ().UID ; got != testNodeUID {
112+ t .Errorf ("expected UID %q, got %q" , testNodeUID , got )
113+ }
114+ if got := client .nodeRef .UID ; got != "" {
115+ t .Errorf ("expected the shared nodeRef to keep no UID, got %q" , got )
116+ }
117+ }
118+
119+ func TestCacheNodeRefIgnoresEmptyUID (t * testing.T ) {
120+ client := newFakeProblemClient ()
121+
122+ client .cacheNodeRef ("" )
123+
124+ if got := client .nodeRefWithUID ().UID ; got != "" {
125+ t .Errorf ("expected no UID, got %q" , got )
126+ }
127+ }
128+
129+ func TestCacheNodeRefKeepsFirstUID (t * testing.T ) {
130+ client := newFakeProblemClient ()
131+
132+ client .cacheNodeRef (testNodeUID )
133+ client .cacheNodeRef ("22222222-2222-2222-2222-222222222222" )
134+
135+ if got := client .nodeRefWithUID ().UID ; got != testNodeUID {
136+ t .Errorf ("expected the first UID %q, got %q" , testNodeUID , got )
137+ }
138+ }
139+
140+ // capturingRecorder records the object that Eventf reports the event against.
141+ type capturingRecorder struct {
142+ object runtime.Object
143+ }
144+
145+ func (r * capturingRecorder ) Event (object runtime.Object , eventType , reason , message string ) {
146+ r .object = object
147+ }
148+
149+ func (r * capturingRecorder ) Eventf (object runtime.Object , eventType , reason , messageFmt string , args ... interface {}) {
150+ r .object = object
151+ }
152+
153+ func (r * capturingRecorder ) AnnotatedEventf (object runtime.Object , annotations map [string ]string , eventType , reason , messageFmt string , args ... interface {}) {
154+ r .object = object
155+ }
156+
157+ func TestEventfReportsNodeUID (t * testing.T ) {
158+ recorder := & capturingRecorder {}
159+ client := newFakeProblemClient ()
160+ client .recorders [testSource ] = recorder
161+ client .cacheNodeRef (testNodeUID )
162+
163+ client .Eventf (v1 .EventTypeWarning , testSource , "test reason" , "test message" )
164+
165+ ref , ok := recorder .object .(* v1.ObjectReference )
166+ if ! ok {
167+ t .Fatalf ("expected an *v1.ObjectReference, got %T" , recorder .object )
168+ }
169+ if ref .UID != testNodeUID {
170+ t .Errorf ("expected the reported event to carry UID %q, got %q" , testNodeUID , ref .UID )
171+ }
172+ if ref .Name != testNode {
173+ t .Errorf ("expected the reported event to carry name %q, got %q" , testNode , ref .Name )
174+ }
175+ }
176+
177+ // newProblemClientAgainstAPI returns a client that talks to a server which
178+ // always answers with the test node.
179+ func newProblemClientAgainstAPI (t * testing.T ) * nodeProblemClient {
180+ t .Helper ()
181+
182+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
183+ node := & v1.Node {ObjectMeta : metav1.ObjectMeta {Name : testNode , UID : testNodeUID }}
184+ w .Header ().Set ("Content-Type" , "application/json" )
185+ if err := json .NewEncoder (w ).Encode (node ); err != nil {
186+ t .Errorf ("failed to encode the node: %v" , err )
187+ }
188+ }))
189+ t .Cleanup (server .Close )
190+
191+ coreClient , err := typedcorev1 .NewForConfig (& rest.Config {Host : server .URL })
192+ if err != nil {
193+ t .Fatalf ("failed to create the core client: %v" , err )
194+ }
195+
196+ client := newFakeProblemClient ()
197+ client .client = coreClient
198+ return client
199+ }
200+
201+ func TestGetNodeCachesNodeUID (t * testing.T ) {
202+ client := newProblemClientAgainstAPI (t )
203+
204+ if _ , err := client .GetNode (context .Background ()); err != nil {
205+ t .Fatalf ("GetNode returned an error: %v" , err )
206+ }
207+
208+ if got := client .nodeRefWithUID ().UID ; got != testNodeUID {
209+ t .Errorf ("expected GetNode to cache UID %q, got %q" , testNodeUID , got )
210+ }
211+ }
212+
213+ func TestSetConditionsCachesNodeUID (t * testing.T ) {
214+ client := newProblemClientAgainstAPI (t )
215+
216+ conditions := []v1.NodeCondition {{Type : "TestType" , Status : v1 .ConditionTrue }}
217+ if err := client .SetConditions (context .Background (), conditions ); err != nil {
218+ t .Fatalf ("SetConditions returned an error: %v" , err )
219+ }
220+
221+ if got := client .nodeRefWithUID ().UID ; got != testNodeUID {
222+ t .Errorf ("expected SetConditions to cache UID %q, got %q" , testNodeUID , got )
223+ }
224+ }
0 commit comments