test_utils.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package testutil
  14. import (
  15. "context"
  16. "encoding/json"
  17. "errors"
  18. "fmt"
  19. "reflect"
  20. "sync"
  21. "testing"
  22. "time"
  23. apierrors "k8s.io/apimachinery/pkg/api/errors"
  24. "k8s.io/apimachinery/pkg/api/resource"
  25. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  26. "k8s.io/apimachinery/pkg/runtime"
  27. "k8s.io/apimachinery/pkg/types"
  28. "k8s.io/apimachinery/pkg/util/sets"
  29. "k8s.io/apimachinery/pkg/util/strategicpatch"
  30. "k8s.io/apimachinery/pkg/watch"
  31. "k8s.io/apimachinery/pkg/util/clock"
  32. ref "k8s.io/client-go/tools/reference"
  33. v1 "k8s.io/api/core/v1"
  34. "k8s.io/client-go/kubernetes/fake"
  35. v1core "k8s.io/client-go/kubernetes/typed/core/v1"
  36. "k8s.io/client-go/tools/cache"
  37. "k8s.io/kubernetes/pkg/api/legacyscheme"
  38. api "k8s.io/kubernetes/pkg/apis/core"
  39. utilnode "k8s.io/kubernetes/pkg/util/node"
  40. jsonpatch "github.com/evanphx/json-patch"
  41. "k8s.io/klog"
  42. )
  43. var (
  44. keyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc
  45. )
  46. // FakeNodeHandler is a fake implementation of NodesInterface and NodeInterface. It
  47. // allows test cases to have fine-grained control over mock behaviors. We also need
  48. // PodsInterface and PodInterface to test list & delete pods, which is implemented in
  49. // the embedded client.Fake field.
  50. type FakeNodeHandler struct {
  51. *fake.Clientset
  52. // Input: Hooks determine if request is valid or not
  53. CreateHook func(*FakeNodeHandler, *v1.Node) bool
  54. Existing []*v1.Node
  55. // Output
  56. CreatedNodes []*v1.Node
  57. DeletedNodes []*v1.Node
  58. UpdatedNodes []*v1.Node
  59. UpdatedNodeStatuses []*v1.Node
  60. RequestCount int
  61. // Synchronization
  62. lock sync.Mutex
  63. DeleteWaitChan chan struct{}
  64. PatchWaitChan chan struct{}
  65. }
  66. // FakeLegacyHandler is a fake implementation of CoreV1Interface.
  67. type FakeLegacyHandler struct {
  68. v1core.CoreV1Interface
  69. n *FakeNodeHandler
  70. }
  71. // GetUpdatedNodesCopy returns a slice of Nodes with updates applied.
  72. func (m *FakeNodeHandler) GetUpdatedNodesCopy() []*v1.Node {
  73. m.lock.Lock()
  74. defer m.lock.Unlock()
  75. updatedNodesCopy := make([]*v1.Node, len(m.UpdatedNodes), len(m.UpdatedNodes))
  76. for i, ptr := range m.UpdatedNodes {
  77. updatedNodesCopy[i] = ptr
  78. }
  79. return updatedNodesCopy
  80. }
  81. // Core returns fake CoreInterface.
  82. func (m *FakeNodeHandler) Core() v1core.CoreV1Interface {
  83. return &FakeLegacyHandler{m.Clientset.CoreV1(), m}
  84. }
  85. // CoreV1 returns fake CoreV1Interface
  86. func (m *FakeNodeHandler) CoreV1() v1core.CoreV1Interface {
  87. return &FakeLegacyHandler{m.Clientset.CoreV1(), m}
  88. }
  89. // Nodes return fake NodeInterfaces.
  90. func (m *FakeLegacyHandler) Nodes() v1core.NodeInterface {
  91. return m.n
  92. }
  93. // Create adds a new Node to the fake store.
  94. func (m *FakeNodeHandler) Create(_ context.Context, node *v1.Node, _ metav1.CreateOptions) (*v1.Node, error) {
  95. m.lock.Lock()
  96. defer func() {
  97. m.RequestCount++
  98. m.lock.Unlock()
  99. }()
  100. for _, n := range m.Existing {
  101. if n.Name == node.Name {
  102. return nil, apierrors.NewAlreadyExists(api.Resource("nodes"), node.Name)
  103. }
  104. }
  105. if m.CreateHook == nil || m.CreateHook(m, node) {
  106. nodeCopy := *node
  107. m.CreatedNodes = append(m.CreatedNodes, &nodeCopy)
  108. return node, nil
  109. }
  110. return nil, errors.New("create error")
  111. }
  112. // Get returns a Node from the fake store.
  113. func (m *FakeNodeHandler) Get(_ context.Context, name string, opts metav1.GetOptions) (*v1.Node, error) {
  114. m.lock.Lock()
  115. defer func() {
  116. m.RequestCount++
  117. m.lock.Unlock()
  118. }()
  119. for i := range m.UpdatedNodes {
  120. if m.UpdatedNodes[i].Name == name {
  121. nodeCopy := *m.UpdatedNodes[i]
  122. return &nodeCopy, nil
  123. }
  124. }
  125. for i := range m.Existing {
  126. if m.Existing[i].Name == name {
  127. nodeCopy := *m.Existing[i]
  128. return &nodeCopy, nil
  129. }
  130. }
  131. return nil, nil
  132. }
  133. // List returns a list of Nodes from the fake store.
  134. func (m *FakeNodeHandler) List(_ context.Context, opts metav1.ListOptions) (*v1.NodeList, error) {
  135. m.lock.Lock()
  136. defer func() {
  137. m.RequestCount++
  138. m.lock.Unlock()
  139. }()
  140. var nodes []*v1.Node
  141. for i := 0; i < len(m.UpdatedNodes); i++ {
  142. if !contains(m.UpdatedNodes[i], m.DeletedNodes) {
  143. nodes = append(nodes, m.UpdatedNodes[i])
  144. }
  145. }
  146. for i := 0; i < len(m.Existing); i++ {
  147. if !contains(m.Existing[i], m.DeletedNodes) && !contains(m.Existing[i], nodes) {
  148. nodes = append(nodes, m.Existing[i])
  149. }
  150. }
  151. for i := 0; i < len(m.CreatedNodes); i++ {
  152. if !contains(m.CreatedNodes[i], m.DeletedNodes) && !contains(m.CreatedNodes[i], nodes) {
  153. nodes = append(nodes, m.CreatedNodes[i])
  154. }
  155. }
  156. nodeList := &v1.NodeList{}
  157. for _, node := range nodes {
  158. nodeList.Items = append(nodeList.Items, *node)
  159. }
  160. return nodeList, nil
  161. }
  162. // Delete deletes a Node from the fake store.
  163. func (m *FakeNodeHandler) Delete(_ context.Context, id string, opt *metav1.DeleteOptions) error {
  164. m.lock.Lock()
  165. defer func() {
  166. m.RequestCount++
  167. if m.DeleteWaitChan != nil {
  168. m.DeleteWaitChan <- struct{}{}
  169. }
  170. m.lock.Unlock()
  171. }()
  172. m.DeletedNodes = append(m.DeletedNodes, NewNode(id))
  173. return nil
  174. }
  175. // DeleteCollection deletes a collection of Nodes from the fake store.
  176. func (m *FakeNodeHandler) DeleteCollection(_ context.Context, opt *metav1.DeleteOptions, listOpts metav1.ListOptions) error {
  177. return nil
  178. }
  179. // Update updates a Node in the fake store.
  180. func (m *FakeNodeHandler) Update(_ context.Context, node *v1.Node, _ metav1.UpdateOptions) (*v1.Node, error) {
  181. m.lock.Lock()
  182. defer func() {
  183. m.RequestCount++
  184. m.lock.Unlock()
  185. }()
  186. nodeCopy := *node
  187. for i, updateNode := range m.UpdatedNodes {
  188. if updateNode.Name == nodeCopy.Name {
  189. m.UpdatedNodes[i] = &nodeCopy
  190. return node, nil
  191. }
  192. }
  193. m.UpdatedNodes = append(m.UpdatedNodes, &nodeCopy)
  194. return node, nil
  195. }
  196. // UpdateStatus updates a status of a Node in the fake store.
  197. func (m *FakeNodeHandler) UpdateStatus(_ context.Context, node *v1.Node, _ metav1.UpdateOptions) (*v1.Node, error) {
  198. m.lock.Lock()
  199. defer func() {
  200. m.RequestCount++
  201. m.lock.Unlock()
  202. }()
  203. var origNodeCopy v1.Node
  204. found := false
  205. for i := range m.Existing {
  206. if m.Existing[i].Name == node.Name {
  207. origNodeCopy = *m.Existing[i]
  208. found = true
  209. break
  210. }
  211. }
  212. updatedNodeIndex := -1
  213. for i := range m.UpdatedNodes {
  214. if m.UpdatedNodes[i].Name == node.Name {
  215. origNodeCopy = *m.UpdatedNodes[i]
  216. updatedNodeIndex = i
  217. found = true
  218. break
  219. }
  220. }
  221. if !found {
  222. return nil, fmt.Errorf("not found node %v", node)
  223. }
  224. origNodeCopy.Status = node.Status
  225. if updatedNodeIndex < 0 {
  226. m.UpdatedNodes = append(m.UpdatedNodes, &origNodeCopy)
  227. } else {
  228. m.UpdatedNodes[updatedNodeIndex] = &origNodeCopy
  229. }
  230. nodeCopy := *node
  231. m.UpdatedNodeStatuses = append(m.UpdatedNodeStatuses, &nodeCopy)
  232. return node, nil
  233. }
  234. // PatchStatus patches a status of a Node in the fake store.
  235. func (m *FakeNodeHandler) PatchStatus(ctx context.Context, nodeName string, data []byte) (*v1.Node, error) {
  236. m.RequestCount++
  237. return m.Patch(ctx, nodeName, types.StrategicMergePatchType, data, metav1.PatchOptions{}, "status")
  238. }
  239. // Watch watches Nodes in a fake store.
  240. func (m *FakeNodeHandler) Watch(_ context.Context, opts metav1.ListOptions) (watch.Interface, error) {
  241. return watch.NewFake(), nil
  242. }
  243. // Patch patches a Node in the fake store.
  244. func (m *FakeNodeHandler) Patch(_ context.Context, name string, pt types.PatchType, data []byte, _ metav1.PatchOptions, subresources ...string) (*v1.Node, error) {
  245. m.lock.Lock()
  246. defer func() {
  247. m.RequestCount++
  248. if m.PatchWaitChan != nil {
  249. m.PatchWaitChan <- struct{}{}
  250. }
  251. m.lock.Unlock()
  252. }()
  253. var nodeCopy v1.Node
  254. for i := range m.Existing {
  255. if m.Existing[i].Name == name {
  256. nodeCopy = *m.Existing[i]
  257. }
  258. }
  259. updatedNodeIndex := -1
  260. for i := range m.UpdatedNodes {
  261. if m.UpdatedNodes[i].Name == name {
  262. nodeCopy = *m.UpdatedNodes[i]
  263. updatedNodeIndex = i
  264. }
  265. }
  266. originalObjJS, err := json.Marshal(nodeCopy)
  267. if err != nil {
  268. klog.Errorf("Failed to marshal %v", nodeCopy)
  269. return nil, nil
  270. }
  271. var originalNode v1.Node
  272. if err = json.Unmarshal(originalObjJS, &originalNode); err != nil {
  273. klog.Errorf("Failed to unmarshal original object: %v", err)
  274. return nil, nil
  275. }
  276. var patchedObjJS []byte
  277. switch pt {
  278. case types.JSONPatchType:
  279. patchObj, err := jsonpatch.DecodePatch(data)
  280. if err != nil {
  281. klog.Error(err.Error())
  282. return nil, nil
  283. }
  284. if patchedObjJS, err = patchObj.Apply(originalObjJS); err != nil {
  285. klog.Error(err.Error())
  286. return nil, nil
  287. }
  288. case types.MergePatchType:
  289. if patchedObjJS, err = jsonpatch.MergePatch(originalObjJS, data); err != nil {
  290. klog.Error(err.Error())
  291. return nil, nil
  292. }
  293. case types.StrategicMergePatchType:
  294. if patchedObjJS, err = strategicpatch.StrategicMergePatch(originalObjJS, data, originalNode); err != nil {
  295. klog.Error(err.Error())
  296. return nil, nil
  297. }
  298. default:
  299. klog.Errorf("unknown Content-Type header for patch: %v", pt)
  300. return nil, nil
  301. }
  302. var updatedNode v1.Node
  303. if err = json.Unmarshal(patchedObjJS, &updatedNode); err != nil {
  304. klog.Errorf("Failed to unmarshal patched object: %v", err)
  305. return nil, nil
  306. }
  307. if updatedNodeIndex < 0 {
  308. m.UpdatedNodes = append(m.UpdatedNodes, &updatedNode)
  309. } else {
  310. m.UpdatedNodes[updatedNodeIndex] = &updatedNode
  311. }
  312. return &updatedNode, nil
  313. }
  314. // FakeRecorder is used as a fake during testing.
  315. type FakeRecorder struct {
  316. sync.Mutex
  317. source v1.EventSource
  318. Events []*v1.Event
  319. clock clock.Clock
  320. }
  321. // Event emits a fake event to the fake recorder
  322. func (f *FakeRecorder) Event(obj runtime.Object, eventtype, reason, message string) {
  323. f.generateEvent(obj, metav1.Now(), eventtype, reason, message)
  324. }
  325. // Eventf emits a fake formatted event to the fake recorder
  326. func (f *FakeRecorder) Eventf(obj runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) {
  327. f.Event(obj, eventtype, reason, fmt.Sprintf(messageFmt, args...))
  328. }
  329. // AnnotatedEventf emits a fake formatted event to the fake recorder
  330. func (f *FakeRecorder) AnnotatedEventf(obj runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) {
  331. f.Eventf(obj, eventtype, reason, messageFmt, args...)
  332. }
  333. func (f *FakeRecorder) generateEvent(obj runtime.Object, timestamp metav1.Time, eventtype, reason, message string) {
  334. f.Lock()
  335. defer f.Unlock()
  336. ref, err := ref.GetReference(legacyscheme.Scheme, obj)
  337. if err != nil {
  338. klog.Errorf("Encountered error while getting reference: %v", err)
  339. return
  340. }
  341. event := f.makeEvent(ref, eventtype, reason, message)
  342. event.Source = f.source
  343. if f.Events != nil {
  344. f.Events = append(f.Events, event)
  345. }
  346. }
  347. func (f *FakeRecorder) makeEvent(ref *v1.ObjectReference, eventtype, reason, message string) *v1.Event {
  348. t := metav1.Time{Time: f.clock.Now()}
  349. namespace := ref.Namespace
  350. if namespace == "" {
  351. namespace = metav1.NamespaceDefault
  352. }
  353. clientref := v1.ObjectReference{
  354. Kind: ref.Kind,
  355. Namespace: ref.Namespace,
  356. Name: ref.Name,
  357. UID: ref.UID,
  358. APIVersion: ref.APIVersion,
  359. ResourceVersion: ref.ResourceVersion,
  360. FieldPath: ref.FieldPath,
  361. }
  362. return &v1.Event{
  363. ObjectMeta: metav1.ObjectMeta{
  364. Name: fmt.Sprintf("%v.%x", ref.Name, t.UnixNano()),
  365. Namespace: namespace,
  366. },
  367. InvolvedObject: clientref,
  368. Reason: reason,
  369. Message: message,
  370. FirstTimestamp: t,
  371. LastTimestamp: t,
  372. Count: 1,
  373. Type: eventtype,
  374. }
  375. }
  376. // NewFakeRecorder returns a pointer to a newly constructed FakeRecorder.
  377. func NewFakeRecorder() *FakeRecorder {
  378. return &FakeRecorder{
  379. source: v1.EventSource{Component: "nodeControllerTest"},
  380. Events: []*v1.Event{},
  381. clock: clock.NewFakeClock(time.Now()),
  382. }
  383. }
  384. // NewNode is a helper function for creating Nodes for testing.
  385. func NewNode(name string) *v1.Node {
  386. return &v1.Node{
  387. ObjectMeta: metav1.ObjectMeta{Name: name},
  388. Status: v1.NodeStatus{
  389. Capacity: v1.ResourceList{
  390. v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
  391. v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
  392. },
  393. },
  394. }
  395. }
  396. // NewPod is a helper function for creating Pods for testing.
  397. func NewPod(name, host string) *v1.Pod {
  398. pod := &v1.Pod{
  399. ObjectMeta: metav1.ObjectMeta{
  400. Namespace: "default",
  401. Name: name,
  402. },
  403. Spec: v1.PodSpec{
  404. NodeName: host,
  405. },
  406. Status: v1.PodStatus{
  407. Conditions: []v1.PodCondition{
  408. {
  409. Type: v1.PodReady,
  410. Status: v1.ConditionTrue,
  411. },
  412. },
  413. },
  414. }
  415. return pod
  416. }
  417. func contains(node *v1.Node, nodes []*v1.Node) bool {
  418. for i := 0; i < len(nodes); i++ {
  419. if node.Name == nodes[i].Name {
  420. return true
  421. }
  422. }
  423. return false
  424. }
  425. // GetZones returns list of zones for all Nodes stored in FakeNodeHandler
  426. func GetZones(nodeHandler *FakeNodeHandler) []string {
  427. nodes, _ := nodeHandler.List(context.TODO(), metav1.ListOptions{})
  428. zones := sets.NewString()
  429. for _, node := range nodes.Items {
  430. zones.Insert(utilnode.GetZoneKey(&node))
  431. }
  432. return zones.List()
  433. }
  434. // CreateZoneID returns a single zoneID for a given region and zone.
  435. func CreateZoneID(region, zone string) string {
  436. return region + ":\x00:" + zone
  437. }
  438. // GetKey is a helper function used by controllers unit tests to get the
  439. // key for a given kubernetes resource.
  440. func GetKey(obj interface{}, t *testing.T) string {
  441. tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
  442. if ok {
  443. // if tombstone , try getting the value from tombstone.Obj
  444. obj = tombstone.Obj
  445. }
  446. val := reflect.ValueOf(obj).Elem()
  447. name := val.FieldByName("Name").String()
  448. kind := val.FieldByName("Kind").String()
  449. // Note kind is not always set in the tests, so ignoring that for now
  450. if len(name) == 0 || len(kind) == 0 {
  451. t.Errorf("Unexpected object %v", obj)
  452. }
  453. key, err := keyFunc(obj)
  454. if err != nil {
  455. t.Errorf("Unexpected error getting key for %v %v: %v", kind, name, err)
  456. return ""
  457. }
  458. return key
  459. }