clustercache_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. package scrape
  2. import (
  3. "reflect"
  4. "testing"
  5. "time"
  6. "github.com/opencost/opencost/core/pkg/clustercache"
  7. "github.com/opencost/opencost/core/pkg/source"
  8. "github.com/opencost/opencost/modules/collector-source/pkg/metric"
  9. "github.com/opencost/opencost/modules/collector-source/pkg/util"
  10. v1 "k8s.io/api/core/v1"
  11. "k8s.io/apimachinery/pkg/api/resource"
  12. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  13. )
  14. var Start1Str = "2025-01-01T00:00:00Z00:00"
  15. func Test_kubernetesScraper_scrapeNodes(t *testing.T) {
  16. start1, _ := time.Parse(time.RFC3339, Start1Str)
  17. type scrape struct {
  18. Nodes []*clustercache.Node
  19. Timestamp time.Time
  20. }
  21. tests := []struct {
  22. name string
  23. scrapes []scrape
  24. expected []metric.Update
  25. }{
  26. {
  27. name: "simple",
  28. scrapes: []scrape{
  29. {
  30. Nodes: []*clustercache.Node{
  31. {
  32. Name: "node1",
  33. SpecProviderID: "i-1",
  34. Status: v1.NodeStatus{
  35. Capacity: v1.ResourceList{
  36. v1.ResourceCPU: resource.MustParse("2"),
  37. v1.ResourceMemory: resource.MustParse("2048"),
  38. },
  39. Allocatable: v1.ResourceList{
  40. v1.ResourceCPU: resource.MustParse("1"),
  41. v1.ResourceMemory: resource.MustParse("1024"),
  42. },
  43. },
  44. Labels: map[string]string{
  45. "test1": "blah",
  46. "test2": "blah2",
  47. },
  48. },
  49. },
  50. Timestamp: start1,
  51. },
  52. },
  53. expected: []metric.Update{
  54. {
  55. Name: KubeNodeStatusCapacityCPUCores,
  56. Labels: map[string]string{
  57. source.NodeLabel: "node1",
  58. source.ProviderIDLabel: "i-1",
  59. },
  60. Value: 2.0,
  61. AdditionalInfo: nil,
  62. },
  63. {
  64. Name: KubeNodeStatusCapacityMemoryBytes,
  65. Labels: map[string]string{
  66. source.NodeLabel: "node1",
  67. source.ProviderIDLabel: "i-1",
  68. },
  69. Value: 2048.0,
  70. AdditionalInfo: nil,
  71. },
  72. {
  73. Name: KubeNodeStatusAllocatableCPUCores,
  74. Labels: map[string]string{
  75. source.NodeLabel: "node1",
  76. source.ProviderIDLabel: "i-1",
  77. },
  78. Value: 1.0,
  79. AdditionalInfo: nil,
  80. },
  81. {
  82. Name: KubeNodeStatusAllocatableMemoryBytes,
  83. Labels: map[string]string{
  84. source.NodeLabel: "node1",
  85. source.ProviderIDLabel: "i-1",
  86. },
  87. Value: 1024.0,
  88. AdditionalInfo: nil,
  89. },
  90. {
  91. Name: KubeNodeLabels,
  92. Labels: map[string]string{
  93. source.NodeLabel: "node1",
  94. source.ProviderIDLabel: "i-1",
  95. },
  96. Value: 0,
  97. AdditionalInfo: map[string]string{
  98. "label_test1": "blah",
  99. "label_test2": "blah2",
  100. },
  101. },
  102. },
  103. },
  104. }
  105. for _, tt := range tests {
  106. t.Run(tt.name, func(t *testing.T) {
  107. ks := &ClusterCacheScraper{}
  108. var scrapeResults []metric.Update
  109. for _, s := range tt.scrapes {
  110. res := ks.scrapeNodes(s.Nodes)
  111. scrapeResults = append(scrapeResults, res...)
  112. }
  113. if len(scrapeResults) != len(tt.expected) {
  114. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  115. }
  116. for i, expected := range tt.expected {
  117. got := scrapeResults[i]
  118. if !reflect.DeepEqual(expected, got) {
  119. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  120. }
  121. }
  122. })
  123. }
  124. }
  125. func Test_kubernetesScraper_scrapeDeployments(t *testing.T) {
  126. start1, _ := time.Parse(time.RFC3339, Start1Str)
  127. type scrape struct {
  128. Deployments []*clustercache.Deployment
  129. Timestamp time.Time
  130. }
  131. tests := []struct {
  132. name string
  133. scrapes []scrape
  134. expected []metric.Update
  135. }{
  136. {
  137. name: "simple",
  138. scrapes: []scrape{
  139. {
  140. Deployments: []*clustercache.Deployment{
  141. {
  142. Name: "deployment1",
  143. Namespace: "namespace1",
  144. MatchLabels: map[string]string{
  145. "test1": "blah",
  146. "test2": "blah2",
  147. },
  148. },
  149. },
  150. Timestamp: start1,
  151. },
  152. },
  153. expected: []metric.Update{
  154. {
  155. Name: DeploymentMatchLabels,
  156. Labels: map[string]string{
  157. source.DeploymentLabel: "deployment1",
  158. source.NamespaceLabel: "namespace1",
  159. },
  160. Value: 0,
  161. AdditionalInfo: map[string]string{
  162. "label_test1": "blah",
  163. "label_test2": "blah2",
  164. },
  165. },
  166. },
  167. },
  168. }
  169. for _, tt := range tests {
  170. t.Run(tt.name, func(t *testing.T) {
  171. ks := &ClusterCacheScraper{}
  172. var scrapeResults []metric.Update
  173. for _, s := range tt.scrapes {
  174. res := ks.scrapeDeployments(s.Deployments)
  175. scrapeResults = append(scrapeResults, res...)
  176. }
  177. if len(scrapeResults) != len(tt.expected) {
  178. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  179. }
  180. for i, expected := range tt.expected {
  181. got := scrapeResults[i]
  182. if !reflect.DeepEqual(expected, got) {
  183. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  184. }
  185. }
  186. })
  187. }
  188. }
  189. func Test_kubernetesScraper_scrapeNamespaces(t *testing.T) {
  190. start1, _ := time.Parse(time.RFC3339, Start1Str)
  191. type scrape struct {
  192. Namespaces []*clustercache.Namespace
  193. Timestamp time.Time
  194. }
  195. tests := []struct {
  196. name string
  197. scrapes []scrape
  198. expected []metric.Update
  199. }{
  200. {
  201. name: "simple",
  202. scrapes: []scrape{
  203. {
  204. Namespaces: []*clustercache.Namespace{
  205. {
  206. Name: "namespace1",
  207. Labels: map[string]string{
  208. "test1": "blah",
  209. "test2": "blah2",
  210. },
  211. Annotations: map[string]string{
  212. "test3": "blah3",
  213. "test4": "blah4",
  214. },
  215. },
  216. },
  217. Timestamp: start1,
  218. },
  219. },
  220. expected: []metric.Update{
  221. {
  222. Name: KubeNamespaceLabels,
  223. Labels: map[string]string{
  224. source.NamespaceLabel: "namespace1",
  225. },
  226. Value: 0,
  227. AdditionalInfo: map[string]string{
  228. "label_test1": "blah",
  229. "label_test2": "blah2",
  230. },
  231. },
  232. {
  233. Name: KubeNamespaceAnnotations,
  234. Labels: map[string]string{
  235. source.NamespaceLabel: "namespace1",
  236. },
  237. Value: 0,
  238. AdditionalInfo: map[string]string{
  239. "annotation_test3": "blah3",
  240. "annotation_test4": "blah4",
  241. },
  242. },
  243. },
  244. },
  245. }
  246. for _, tt := range tests {
  247. t.Run(tt.name, func(t *testing.T) {
  248. ks := &ClusterCacheScraper{}
  249. var scrapeResults []metric.Update
  250. for _, s := range tt.scrapes {
  251. res := ks.scrapeNamespaces(s.Namespaces)
  252. scrapeResults = append(scrapeResults, res...)
  253. }
  254. if len(scrapeResults) != len(tt.expected) {
  255. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  256. }
  257. for i, expected := range tt.expected {
  258. got := scrapeResults[i]
  259. if !reflect.DeepEqual(expected, got) {
  260. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  261. }
  262. }
  263. })
  264. }
  265. }
  266. func Test_kubernetesScraper_scrapePods(t *testing.T) {
  267. start1, _ := time.Parse(time.RFC3339, Start1Str)
  268. type scrape struct {
  269. Pods []*clustercache.Pod
  270. Timestamp time.Time
  271. }
  272. tests := []struct {
  273. name string
  274. scrapes []scrape
  275. expected []metric.Update
  276. }{
  277. {
  278. name: "simple",
  279. scrapes: []scrape{
  280. {
  281. Pods: []*clustercache.Pod{
  282. {
  283. Name: "pod1",
  284. Namespace: "namespace1",
  285. UID: "uuid1",
  286. Spec: clustercache.PodSpec{
  287. NodeName: "node1",
  288. Containers: []clustercache.Container{
  289. {
  290. Name: "container1",
  291. Resources: v1.ResourceRequirements{
  292. Requests: map[v1.ResourceName]resource.Quantity{
  293. v1.ResourceCPU: resource.MustParse("500m"),
  294. v1.ResourceMemory: resource.MustParse("512"),
  295. },
  296. },
  297. },
  298. },
  299. },
  300. Labels: map[string]string{
  301. "test1": "blah",
  302. "test2": "blah2",
  303. },
  304. Annotations: map[string]string{
  305. "test3": "blah3",
  306. "test4": "blah4",
  307. },
  308. OwnerReferences: []metav1.OwnerReference{
  309. {
  310. Kind: source.DeploymentLabel,
  311. Name: "deployment1",
  312. Controller: nil,
  313. },
  314. },
  315. Status: clustercache.PodStatus{
  316. ContainerStatuses: []v1.ContainerStatus{
  317. {
  318. Name: "container1",
  319. State: v1.ContainerState{
  320. Running: &v1.ContainerStateRunning{},
  321. },
  322. },
  323. },
  324. },
  325. },
  326. },
  327. Timestamp: start1,
  328. },
  329. },
  330. expected: []metric.Update{
  331. {
  332. Name: KubePodLabels,
  333. Labels: map[string]string{
  334. source.PodLabel: "pod1",
  335. source.NamespaceLabel: "namespace1",
  336. source.UIDLabel: "uuid1",
  337. source.NodeLabel: "node1",
  338. source.InstanceLabel: "node1",
  339. },
  340. Value: 0,
  341. AdditionalInfo: map[string]string{
  342. "label_test1": "blah",
  343. "label_test2": "blah2",
  344. },
  345. },
  346. {
  347. Name: KubePodAnnotations,
  348. Labels: map[string]string{
  349. source.PodLabel: "pod1",
  350. source.NamespaceLabel: "namespace1",
  351. source.UIDLabel: "uuid1",
  352. source.NodeLabel: "node1",
  353. source.InstanceLabel: "node1",
  354. },
  355. Value: 0,
  356. AdditionalInfo: map[string]string{
  357. "annotation_test3": "blah3",
  358. "annotation_test4": "blah4",
  359. },
  360. },
  361. {
  362. Name: KubePodOwner,
  363. Labels: map[string]string{
  364. source.PodLabel: "pod1",
  365. source.NamespaceLabel: "namespace1",
  366. source.UIDLabel: "uuid1",
  367. source.NodeLabel: "node1",
  368. source.InstanceLabel: "node1",
  369. source.OwnerKindLabel: "deployment",
  370. source.OwnerNameLabel: "deployment1",
  371. },
  372. Value: 0,
  373. AdditionalInfo: nil,
  374. },
  375. {
  376. Name: KubePodContainerStatusRunning,
  377. Labels: map[string]string{
  378. source.PodLabel: "pod1",
  379. source.NamespaceLabel: "namespace1",
  380. source.UIDLabel: "uuid1",
  381. source.NodeLabel: "node1",
  382. source.InstanceLabel: "node1",
  383. source.ContainerLabel: "container1",
  384. },
  385. Value: 0,
  386. AdditionalInfo: nil,
  387. },
  388. {
  389. Name: KubePodContainerResourceRequests,
  390. Labels: map[string]string{
  391. source.PodLabel: "pod1",
  392. source.NamespaceLabel: "namespace1",
  393. source.UIDLabel: "uuid1",
  394. source.NodeLabel: "node1",
  395. source.InstanceLabel: "node1",
  396. source.ContainerLabel: "container1",
  397. source.ResourceLabel: "cpu",
  398. source.UnitLabel: "core",
  399. },
  400. Value: 0.5,
  401. AdditionalInfo: nil,
  402. },
  403. {
  404. Name: KubePodContainerResourceRequests,
  405. Labels: map[string]string{
  406. source.PodLabel: "pod1",
  407. source.NamespaceLabel: "namespace1",
  408. source.UIDLabel: "uuid1",
  409. source.NodeLabel: "node1",
  410. source.InstanceLabel: "node1",
  411. source.ContainerLabel: "container1",
  412. source.ResourceLabel: "memory",
  413. source.UnitLabel: "byte",
  414. },
  415. Value: 512,
  416. AdditionalInfo: nil,
  417. },
  418. },
  419. },
  420. }
  421. for _, tt := range tests {
  422. t.Run(tt.name, func(t *testing.T) {
  423. ks := &ClusterCacheScraper{}
  424. var scrapeResults []metric.Update
  425. for _, s := range tt.scrapes {
  426. res := ks.scrapePods(s.Pods)
  427. scrapeResults = append(scrapeResults, res...)
  428. }
  429. if len(scrapeResults) != len(tt.expected) {
  430. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  431. }
  432. for i, expected := range tt.expected {
  433. got := scrapeResults[i]
  434. if !reflect.DeepEqual(expected, got) {
  435. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  436. }
  437. }
  438. })
  439. }
  440. }
  441. func Test_kubernetesScraper_scrapePVCs(t *testing.T) {
  442. start1, _ := time.Parse(time.RFC3339, Start1Str)
  443. type scrape struct {
  444. PVCs []*clustercache.PersistentVolumeClaim
  445. Timestamp time.Time
  446. }
  447. tests := []struct {
  448. name string
  449. scrapes []scrape
  450. expected []metric.Update
  451. }{
  452. {
  453. name: "simple",
  454. scrapes: []scrape{
  455. {
  456. PVCs: []*clustercache.PersistentVolumeClaim{
  457. {
  458. Name: "pvc1",
  459. Namespace: "namespace1",
  460. Spec: v1.PersistentVolumeClaimSpec{
  461. VolumeName: "vol1",
  462. StorageClassName: util.Ptr("storageClass1"),
  463. Resources: v1.VolumeResourceRequirements{
  464. Requests: v1.ResourceList{
  465. v1.ResourceStorage: resource.MustParse("4096"),
  466. },
  467. },
  468. },
  469. },
  470. },
  471. Timestamp: start1,
  472. },
  473. },
  474. expected: []metric.Update{
  475. {
  476. Name: KubePersistentVolumeClaimInfo,
  477. Labels: map[string]string{
  478. source.PVCLabel: "pvc1",
  479. source.NamespaceLabel: "namespace1",
  480. source.VolumeNameLabel: "vol1",
  481. source.StorageClassLabel: "storageClass1",
  482. },
  483. Value: 0,
  484. AdditionalInfo: nil,
  485. },
  486. {
  487. Name: KubePersistentVolumeClaimResourceRequestsStorageBytes,
  488. Labels: map[string]string{
  489. source.PVCLabel: "pvc1",
  490. source.NamespaceLabel: "namespace1",
  491. source.VolumeNameLabel: "vol1",
  492. source.StorageClassLabel: "storageClass1",
  493. },
  494. Value: 4096,
  495. AdditionalInfo: nil,
  496. },
  497. },
  498. },
  499. }
  500. for _, tt := range tests {
  501. t.Run(tt.name, func(t *testing.T) {
  502. ks := &ClusterCacheScraper{}
  503. var scrapeResults []metric.Update
  504. for _, s := range tt.scrapes {
  505. res := ks.scrapePVCs(s.PVCs)
  506. scrapeResults = append(scrapeResults, res...)
  507. }
  508. if len(scrapeResults) != len(tt.expected) {
  509. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  510. }
  511. for i, expected := range tt.expected {
  512. got := scrapeResults[i]
  513. if !reflect.DeepEqual(expected, got) {
  514. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  515. }
  516. }
  517. })
  518. }
  519. }
  520. func Test_kubernetesScraper_scrapePVs(t *testing.T) {
  521. start1, _ := time.Parse(time.RFC3339, Start1Str)
  522. type scrape struct {
  523. PVs []*clustercache.PersistentVolume
  524. Timestamp time.Time
  525. }
  526. tests := []struct {
  527. name string
  528. scrapes []scrape
  529. expected []metric.Update
  530. }{
  531. {
  532. name: "simple",
  533. scrapes: []scrape{
  534. {
  535. PVs: []*clustercache.PersistentVolume{
  536. {
  537. Name: "pv1",
  538. Spec: v1.PersistentVolumeSpec{
  539. StorageClassName: "storageClass1",
  540. PersistentVolumeSource: v1.PersistentVolumeSource{
  541. CSI: &v1.CSIPersistentVolumeSource{
  542. VolumeHandle: "vol-1",
  543. },
  544. },
  545. Capacity: v1.ResourceList{
  546. v1.ResourceStorage: resource.MustParse("4096"),
  547. },
  548. },
  549. },
  550. },
  551. Timestamp: start1,
  552. },
  553. },
  554. expected: []metric.Update{
  555. {
  556. Name: KubecostPVInfo,
  557. Labels: map[string]string{
  558. source.PVLabel: "pv1",
  559. source.ProviderIDLabel: "vol-1",
  560. source.StorageClassLabel: "storageClass1",
  561. },
  562. Value: 0,
  563. AdditionalInfo: nil,
  564. },
  565. {
  566. Name: KubePersistentVolumeCapacityBytes,
  567. Labels: map[string]string{
  568. source.PVLabel: "pv1",
  569. source.ProviderIDLabel: "vol-1",
  570. source.StorageClassLabel: "storageClass1",
  571. },
  572. Value: 4096,
  573. AdditionalInfo: nil,
  574. },
  575. },
  576. },
  577. }
  578. for _, tt := range tests {
  579. t.Run(tt.name, func(t *testing.T) {
  580. ks := &ClusterCacheScraper{}
  581. var scrapeResults []metric.Update
  582. for _, s := range tt.scrapes {
  583. res := ks.scrapePVs(s.PVs)
  584. scrapeResults = append(scrapeResults, res...)
  585. }
  586. if len(scrapeResults) != len(tt.expected) {
  587. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  588. }
  589. for i, expected := range tt.expected {
  590. got := scrapeResults[i]
  591. if !reflect.DeepEqual(expected, got) {
  592. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  593. }
  594. }
  595. })
  596. }
  597. }
  598. func Test_kubernetesScraper_scrapeServices(t *testing.T) {
  599. start1, _ := time.Parse(time.RFC3339, Start1Str)
  600. type scrape struct {
  601. Services []*clustercache.Service
  602. Timestamp time.Time
  603. }
  604. tests := []struct {
  605. name string
  606. scrapes []scrape
  607. expected []metric.Update
  608. }{
  609. {
  610. name: "simple",
  611. scrapes: []scrape{
  612. {
  613. Services: []*clustercache.Service{
  614. {
  615. Name: "service1",
  616. Namespace: "namespace1",
  617. SpecSelector: map[string]string{
  618. "test1": "blah",
  619. "test2": "blah2",
  620. },
  621. },
  622. },
  623. Timestamp: start1,
  624. },
  625. },
  626. expected: []metric.Update{
  627. {
  628. Name: ServiceSelectorLabels,
  629. Labels: map[string]string{
  630. "service": "service1",
  631. source.NamespaceLabel: "namespace1",
  632. },
  633. Value: 0,
  634. AdditionalInfo: map[string]string{
  635. "label_test1": "blah",
  636. "label_test2": "blah2",
  637. },
  638. },
  639. },
  640. },
  641. }
  642. for _, tt := range tests {
  643. t.Run(tt.name, func(t *testing.T) {
  644. ks := &ClusterCacheScraper{}
  645. var scrapeResults []metric.Update
  646. for _, s := range tt.scrapes {
  647. res := ks.scrapeServices(s.Services)
  648. scrapeResults = append(scrapeResults, res...)
  649. }
  650. if len(scrapeResults) != len(tt.expected) {
  651. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  652. }
  653. for i, expected := range tt.expected {
  654. got := scrapeResults[i]
  655. if !reflect.DeepEqual(expected, got) {
  656. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  657. }
  658. }
  659. })
  660. }
  661. }
  662. func Test_kubernetesScraper_scrapeStatefulSets(t *testing.T) {
  663. start1, _ := time.Parse(time.RFC3339, Start1Str)
  664. type scrape struct {
  665. StatefulSets []*clustercache.StatefulSet
  666. Timestamp time.Time
  667. }
  668. tests := []struct {
  669. name string
  670. scrapes []scrape
  671. expected []metric.Update
  672. }{
  673. {
  674. name: "simple",
  675. scrapes: []scrape{
  676. {
  677. StatefulSets: []*clustercache.StatefulSet{
  678. {
  679. Name: "statefulSet1",
  680. Namespace: "namespace1",
  681. SpecSelector: &metav1.LabelSelector{
  682. MatchLabels: map[string]string{
  683. "test1": "blah",
  684. "test2": "blah2",
  685. },
  686. },
  687. },
  688. },
  689. Timestamp: start1,
  690. },
  691. },
  692. expected: []metric.Update{
  693. {
  694. Name: StatefulSetMatchLabels,
  695. Labels: map[string]string{
  696. source.StatefulSetLabel: "statefulSet1",
  697. source.NamespaceLabel: "namespace1",
  698. },
  699. Value: 0,
  700. AdditionalInfo: map[string]string{
  701. "label_test1": "blah",
  702. "label_test2": "blah2",
  703. },
  704. },
  705. },
  706. },
  707. }
  708. for _, tt := range tests {
  709. t.Run(tt.name, func(t *testing.T) {
  710. ks := &ClusterCacheScraper{}
  711. var scrapeResults []metric.Update
  712. for _, s := range tt.scrapes {
  713. res := ks.scrapeStatefulSets(s.StatefulSets)
  714. scrapeResults = append(scrapeResults, res...)
  715. }
  716. if len(scrapeResults) != len(tt.expected) {
  717. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  718. }
  719. for i, expected := range tt.expected {
  720. got := scrapeResults[i]
  721. if !reflect.DeepEqual(expected, got) {
  722. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  723. }
  724. }
  725. })
  726. }
  727. }
  728. func Test_kubernetesScraper_scrapeReplicaSets(t *testing.T) {
  729. start1, _ := time.Parse(time.RFC3339, Start1Str)
  730. type scrape struct {
  731. ReplicaSets []*clustercache.ReplicaSet
  732. Timestamp time.Time
  733. }
  734. tests := []struct {
  735. name string
  736. scrapes []scrape
  737. expected []metric.Update
  738. }{
  739. {
  740. name: "simple",
  741. scrapes: []scrape{
  742. {
  743. ReplicaSets: []*clustercache.ReplicaSet{
  744. {
  745. Name: "replicaSet1",
  746. Namespace: "namespace1",
  747. OwnerReferences: []metav1.OwnerReference{
  748. {
  749. Name: "rollout1",
  750. Kind: "Rollout",
  751. },
  752. },
  753. },
  754. },
  755. Timestamp: start1,
  756. },
  757. },
  758. expected: []metric.Update{
  759. {
  760. Name: KubeReplicasetOwner,
  761. Labels: map[string]string{
  762. "replicaset": "replicaSet1",
  763. source.NamespaceLabel: "namespace1",
  764. source.OwnerNameLabel: "rollout1",
  765. source.OwnerKindLabel: "Rollout",
  766. },
  767. Value: 0,
  768. },
  769. },
  770. },
  771. }
  772. for _, tt := range tests {
  773. t.Run(tt.name, func(t *testing.T) {
  774. ks := &ClusterCacheScraper{}
  775. var scrapeResults []metric.Update
  776. for _, s := range tt.scrapes {
  777. res := ks.scrapeReplicaSets(s.ReplicaSets)
  778. scrapeResults = append(scrapeResults, res...)
  779. }
  780. if len(scrapeResults) != len(tt.expected) {
  781. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  782. }
  783. for i, expected := range tt.expected {
  784. got := scrapeResults[i]
  785. if !reflect.DeepEqual(expected, got) {
  786. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  787. }
  788. }
  789. })
  790. }
  791. }