provider_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. package aws
  2. import (
  3. "encoding/json"
  4. "io"
  5. "net/http"
  6. "net/url"
  7. "os"
  8. "reflect"
  9. "testing"
  10. "github.com/opencost/opencost/core/pkg/clustercache"
  11. "github.com/opencost/opencost/pkg/cloud/models"
  12. v1 "k8s.io/api/core/v1"
  13. )
  14. func Test_awsKey_getUsageType(t *testing.T) {
  15. type fields struct {
  16. Labels map[string]string
  17. ProviderID string
  18. }
  19. type args struct {
  20. labels map[string]string
  21. }
  22. tests := []struct {
  23. name string
  24. fields fields
  25. args args
  26. want string
  27. }{
  28. {
  29. // test with no labels should return false
  30. name: "Label does not have the capacityType label associated with it",
  31. args: args{
  32. labels: map[string]string{},
  33. },
  34. want: "",
  35. },
  36. {
  37. name: "EKS label with a capacityType set to empty string should return empty string",
  38. args: args{
  39. labels: map[string]string{
  40. EKSCapacityTypeLabel: "",
  41. },
  42. },
  43. want: "",
  44. },
  45. {
  46. name: "EKS label with capacityType set to a random value should return empty string",
  47. args: args{
  48. labels: map[string]string{
  49. EKSCapacityTypeLabel: "TEST_ME",
  50. },
  51. },
  52. want: "",
  53. },
  54. {
  55. name: "EKS label with capacityType set to spot should return spot",
  56. args: args{
  57. labels: map[string]string{
  58. EKSCapacityTypeLabel: EKSCapacitySpotTypeValue,
  59. },
  60. },
  61. want: PreemptibleType,
  62. },
  63. {
  64. name: "Karpenter label with a capacityType set to empty string should return empty string",
  65. args: args{
  66. labels: map[string]string{
  67. models.KarpenterCapacityTypeLabel: "",
  68. },
  69. },
  70. want: "",
  71. },
  72. {
  73. name: "Karpenter label with capacityType set to a random value should return empty string",
  74. args: args{
  75. labels: map[string]string{
  76. models.KarpenterCapacityTypeLabel: "TEST_ME",
  77. },
  78. },
  79. want: "",
  80. },
  81. {
  82. name: "Karpenter label with capacityType set to spot should return spot",
  83. args: args{
  84. labels: map[string]string{
  85. models.KarpenterCapacityTypeLabel: models.KarpenterCapacitySpotTypeValue,
  86. },
  87. },
  88. want: PreemptibleType,
  89. },
  90. }
  91. for _, tt := range tests {
  92. t.Run(tt.name, func(t *testing.T) {
  93. k := &awsKey{
  94. Labels: tt.fields.Labels,
  95. ProviderID: tt.fields.ProviderID,
  96. }
  97. if got := k.getUsageType(tt.args.labels); got != tt.want {
  98. t.Errorf("getUsageType() = %v, want %v", got, tt.want)
  99. }
  100. })
  101. }
  102. }
  103. // Test_PricingData_Regression
  104. //
  105. // Objective: To test the pricing data download and validate the schema is still
  106. // as expected
  107. //
  108. // These tests may take a long time to complete. It is downloading AWS Pricing
  109. // data files (~500MB) for each region.
  110. func Test_PricingData_Regression(t *testing.T) {
  111. if os.Getenv("INTEGRATION") == "" {
  112. t.Skip("skipping integration tests, set environment variable INTEGRATION")
  113. }
  114. awsRegions := []string{"us-east-1", "eu-west-1"}
  115. // Check pricing data produced for each region
  116. for _, region := range awsRegions {
  117. awsTest := AWS{}
  118. res, _, err := awsTest.getRegionPricing([]*clustercache.Node{
  119. {
  120. Labels: map[string]string{"topology.kubernetes.io/region": region},
  121. }})
  122. if err != nil {
  123. t.Errorf("Failed to download pricing data for region %s: %v", region, err)
  124. }
  125. // Unmarshal pricing data into AWSPricing
  126. var pricingData AWSPricing
  127. body, err := io.ReadAll(res.Body)
  128. if err != nil {
  129. t.Errorf("Failed to read pricing data for region %s: %v", region, err)
  130. }
  131. err = json.Unmarshal(body, &pricingData)
  132. if err != nil {
  133. t.Errorf("Failed to unmarshal pricing data for region %s: %v", region, err)
  134. }
  135. // ASSERTION. We only anticipate "OnDemand" or "CapacityBlock" in the
  136. // pricing data.
  137. //
  138. // Failing this test does not necessarily mean we have regressed. Just
  139. // that we need to revisit this code to ensure OnDemand pricing is still
  140. // functioning as expected.
  141. for _, product := range pricingData.Products {
  142. if product.Attributes.MarketOption != "OnDemand" && product.Attributes.MarketOption != "CapacityBlock" && product.Attributes.MarketOption != "" {
  143. t.Errorf("Invalid marketOption for product %s: %s", product.Sku, product.Attributes.MarketOption)
  144. }
  145. }
  146. }
  147. }
  148. // Test_populate_pricing
  149. //
  150. // Objective: To test core pricing population logic for AWS
  151. //
  152. // Case 0: US endpoints
  153. // Take a portion of json returned from ondemand terms in us endpoints load the
  154. // request into the http response and give it to the function inspect the
  155. // resulting aws object after the function returns and validate fields
  156. //
  157. // Case 1: Ensure marketOption=OnDemand
  158. // AWS introduced the field marketOption. We need to further filter for
  159. // marketOption=OnDemand to ensure we are not getting pricing from a line item
  160. // such as marketOption=CapacityBlock
  161. //
  162. // Case 2: Chinese endpoints
  163. // Same as above US test case, except using CN PV offer codes. Validate
  164. // populated fields in AWS object
  165. func Test_populate_pricing(t *testing.T) {
  166. awsTest := AWS{
  167. ValidPricingKeys: map[string]bool{},
  168. ClusterRegion: "us-east-2",
  169. }
  170. inputkeys := map[string]bool{
  171. "us-east-2,m5.large,linux": true,
  172. }
  173. fixture, err := os.Open("testdata/pricing-us-east-2.json")
  174. if err != nil {
  175. t.Fatalf("failed to load pricing fixture: %s", err)
  176. }
  177. testResponse := http.Response{
  178. Body: io.NopCloser(fixture),
  179. Request: &http.Request{
  180. URL: &url.URL{
  181. Scheme: "https",
  182. Host: "test-aws-http-endpoint:443",
  183. },
  184. },
  185. }
  186. awsTest.populatePricing(&testResponse, inputkeys)
  187. expectedProdTermsDisk := &AWSProductTerms{
  188. Sku: "M6UGCCQ3CDJQAA37",
  189. Memory: "",
  190. Storage: "",
  191. VCpu: "",
  192. GPU: "",
  193. OnDemand: &AWSOfferTerm{
  194. Sku: "M6UGCCQ3CDJQAA37",
  195. OfferTermCode: "JRTCKXETXF",
  196. PriceDimensions: map[string]*AWSRateCode{
  197. "M6UGCCQ3CDJQAA37.JRTCKXETXF.6YS6EN2CT7": {
  198. Unit: "GB-Mo",
  199. PricePerUnit: AWSCurrencyCode{
  200. USD: "0.0800000000",
  201. CNY: "",
  202. },
  203. },
  204. },
  205. },
  206. PV: &models.PV{
  207. Cost: "0.00010958904109589041",
  208. CostPerIO: "",
  209. Class: "gp3",
  210. Size: "",
  211. Region: "us-east-2",
  212. ProviderID: "",
  213. },
  214. }
  215. expectedProdTermsInstanceOndemand := &AWSProductTerms{
  216. Sku: "8D49XP354UEYTHGM",
  217. Memory: "8 GiB",
  218. Storage: "EBS only",
  219. VCpu: "2",
  220. GPU: "",
  221. OnDemand: &AWSOfferTerm{
  222. Sku: "8D49XP354UEYTHGM",
  223. OfferTermCode: "MZU6U2429S",
  224. PriceDimensions: map[string]*AWSRateCode{
  225. "8D49XP354UEYTHGM.MZU6U2429S.2TG2D8R56U": {
  226. Unit: "Quantity",
  227. PricePerUnit: AWSCurrencyCode{
  228. USD: "1161",
  229. CNY: "",
  230. },
  231. },
  232. },
  233. },
  234. }
  235. expectedProdTermsInstanceSpot := &AWSProductTerms{
  236. Sku: "8D49XP354UEYTHGM",
  237. Memory: "8 GiB",
  238. Storage: "EBS only",
  239. VCpu: "2",
  240. GPU: "",
  241. OnDemand: &AWSOfferTerm{
  242. Sku: "8D49XP354UEYTHGM",
  243. OfferTermCode: "MZU6U2429S",
  244. PriceDimensions: map[string]*AWSRateCode{
  245. "8D49XP354UEYTHGM.MZU6U2429S.2TG2D8R56U": {
  246. Unit: "Quantity",
  247. PricePerUnit: AWSCurrencyCode{
  248. USD: "1161",
  249. CNY: "",
  250. },
  251. },
  252. },
  253. },
  254. }
  255. expectedProdTermsLoadbalancer := &AWSProductTerms{
  256. Sku: "Y9RYMSE644KDSV4S",
  257. OnDemand: &AWSOfferTerm{
  258. Sku: "Y9RYMSE644KDSV4S",
  259. OfferTermCode: "JRTCKXETXF",
  260. PriceDimensions: map[string]*AWSRateCode{
  261. "Y9RYMSE644KDSV4S.JRTCKXETXF.6YS6EN2CT7": {
  262. Unit: "Hrs",
  263. PricePerUnit: AWSCurrencyCode{
  264. USD: "0.0225000000",
  265. CNY: "",
  266. },
  267. },
  268. },
  269. },
  270. LoadBalancer: &models.LoadBalancer{
  271. Cost: 0.0225,
  272. },
  273. }
  274. expectedPricing := map[string]*AWSProductTerms{
  275. "us-east-2,EBS:VolumeUsage.gp3": expectedProdTermsDisk,
  276. "us-east-2,EBS:VolumeUsage.gp3,preemptible": expectedProdTermsDisk,
  277. "us-east-2,m5.large,linux": expectedProdTermsInstanceOndemand,
  278. "us-east-2,m5.large,linux,preemptible": expectedProdTermsInstanceSpot,
  279. "us-east-2,LoadBalancerUsage": expectedProdTermsLoadbalancer,
  280. }
  281. if !reflect.DeepEqual(expectedPricing, awsTest.Pricing) {
  282. t.Fatalf("expected parsed pricing did not match actual parsed result (us-east-2)")
  283. }
  284. lbPricing, _ := awsTest.LoadBalancerPricing()
  285. if lbPricing.Cost != 0.0225 {
  286. t.Fatalf("expected loadbalancer pricing of 0.0225 but got %f (us-east-2)", lbPricing.Cost)
  287. }
  288. // Case 1 - Only accept `"marketoption":"OnDemand"`
  289. inputkeysCase1 := map[string]bool{
  290. "us-east-1,p4d.24xlarge,linux": true,
  291. }
  292. fixture, err = os.Open("testdata/pricing-us-east-1.json")
  293. if err != nil {
  294. t.Fatalf("failed to load pricing fixture: %s", err)
  295. }
  296. testResponseCase1 := http.Response{
  297. Body: io.NopCloser(fixture),
  298. Request: &http.Request{
  299. URL: &url.URL{
  300. Scheme: "https",
  301. Host: "test-aws-http-endpoint:443",
  302. },
  303. },
  304. }
  305. awsTest.populatePricing(&testResponseCase1, inputkeysCase1)
  306. expectedProdTermsInstanceOndemandCase1 := &AWSProductTerms{
  307. Sku: "H7NGEAC6UEHNTKSJ",
  308. Memory: "1152 GiB",
  309. Storage: "8 x 1000 SSD",
  310. VCpu: "96",
  311. GPU: "8",
  312. OnDemand: &AWSOfferTerm{
  313. Sku: "H7NGEAC6UEHNTKSJ",
  314. OfferTermCode: "JRTCKXETXF",
  315. PriceDimensions: map[string]*AWSRateCode{
  316. "H7NGEAC6UEHNTKSJ.JRTCKXETXF.6YS6EN2CT7": {
  317. Unit: "Hrs",
  318. PricePerUnit: AWSCurrencyCode{
  319. USD: "32.7726000000",
  320. },
  321. },
  322. },
  323. },
  324. }
  325. expectedPricingCase1 := map[string]*AWSProductTerms{
  326. "us-east-1,p4d.24xlarge,linux": expectedProdTermsInstanceOndemandCase1,
  327. "us-east-1,p4d.24xlarge,linux,preemptible": expectedProdTermsInstanceOndemandCase1,
  328. }
  329. if !reflect.DeepEqual(expectedPricingCase1, awsTest.Pricing) {
  330. expectedJsonString, _ := json.MarshalIndent(expectedPricingCase1, "", " ")
  331. resultJsonString, _ := json.MarshalIndent(awsTest.Pricing, "", " ")
  332. t.Logf("Expected: %s", string(expectedJsonString))
  333. t.Logf("Result: %s", string(resultJsonString))
  334. t.Fatalf("expected parsed pricing did not match actual parsed result (us-east-1)")
  335. }
  336. // Case 2
  337. awsTest = AWS{
  338. ValidPricingKeys: map[string]bool{},
  339. }
  340. fixture, err = os.Open("testdata/pricing-cn-northwest-1.json")
  341. if err != nil {
  342. t.Fatalf("failed to load pricing fixture: %s", err)
  343. }
  344. testResponse = http.Response{
  345. Body: io.NopCloser(fixture),
  346. Request: &http.Request{
  347. URL: &url.URL{
  348. Scheme: "https",
  349. Host: "test-aws-http-endpoint:443",
  350. },
  351. },
  352. }
  353. awsTest.populatePricing(&testResponse, inputkeys)
  354. expectedProdTermsDisk = &AWSProductTerms{
  355. Sku: "R83VXG9NAPDASEGN",
  356. Memory: "",
  357. Storage: "",
  358. VCpu: "",
  359. GPU: "",
  360. OnDemand: &AWSOfferTerm{
  361. Sku: "R83VXG9NAPDASEGN",
  362. OfferTermCode: "5Y9WH78GDR",
  363. PriceDimensions: map[string]*AWSRateCode{
  364. "R83VXG9NAPDASEGN.5Y9WH78GDR.Q7UJUT2CE6": {
  365. Unit: "GB-Mo",
  366. PricePerUnit: AWSCurrencyCode{
  367. USD: "",
  368. CNY: "0.5312000000",
  369. },
  370. },
  371. },
  372. },
  373. PV: &models.PV{
  374. Cost: "0.0007276712328767123",
  375. CostPerIO: "",
  376. Class: "gp3",
  377. Size: "",
  378. Region: "cn-northwest-1",
  379. ProviderID: "",
  380. },
  381. }
  382. expectedPricing = map[string]*AWSProductTerms{
  383. "cn-northwest-1,EBS:VolumeUsage.gp3": expectedProdTermsDisk,
  384. "cn-northwest-1,EBS:VolumeUsage.gp3,preemptible": expectedProdTermsDisk,
  385. }
  386. if !reflect.DeepEqual(expectedPricing, awsTest.Pricing) {
  387. t.Fatalf("expected parsed pricing did not match actual parsed result (cn)")
  388. }
  389. }
  390. func TestFeatures(t *testing.T) {
  391. testCases := map[string]struct {
  392. aws awsKey
  393. expected string
  394. }{
  395. "Spot from custom labels": {
  396. aws: awsKey{
  397. SpotLabelName: "node-type",
  398. SpotLabelValue: "node-spot",
  399. Labels: map[string]string{
  400. "node-type": "node-spot",
  401. v1.LabelOSStable: "linux",
  402. v1.LabelHostname: "my-hostname",
  403. v1.LabelTopologyRegion: "us-west-2",
  404. v1.LabelTopologyZone: "us-west-2b",
  405. v1.LabelInstanceTypeStable: "m5.large",
  406. },
  407. },
  408. expected: "us-west-2,m5.large,linux,preemptible",
  409. },
  410. }
  411. for name, tc := range testCases {
  412. t.Run(name, func(t *testing.T) {
  413. features := tc.aws.Features()
  414. if features != tc.expected {
  415. t.Errorf("expected %s, got %s", tc.expected, features)
  416. }
  417. })
  418. }
  419. }
  420. func Test_getStorageClassTypeFrom(t *testing.T) {
  421. tests := []struct {
  422. name string
  423. provisioner string
  424. want string
  425. }{
  426. {
  427. name: "empty-provisioner",
  428. provisioner: "",
  429. want: "",
  430. },
  431. {
  432. name: "ebs-default-provisioner",
  433. provisioner: "kubernetes.io/aws-ebs",
  434. want: "gp2",
  435. },
  436. {
  437. name: "ebs-csi-provisioner",
  438. provisioner: "ebs.csi.aws.com",
  439. want: "gp3",
  440. },
  441. {
  442. name: "unknown-provisioner",
  443. provisioner: "unknown",
  444. want: "",
  445. },
  446. }
  447. for _, tt := range tests {
  448. t.Run(tt.name, func(t *testing.T) {
  449. if got := getStorageClassTypeFrom(tt.provisioner); got != tt.want {
  450. t.Errorf("getStorageClassTypeFrom() = %v, want %v", got, tt.want)
  451. }
  452. })
  453. }
  454. }
  455. func Test_awsKey_isFargateNode(t *testing.T) {
  456. tests := []struct {
  457. name string
  458. labels map[string]string
  459. want bool
  460. }{
  461. {
  462. name: "fargate node with correct label",
  463. labels: map[string]string{
  464. eksComputeTypeLabel: "fargate",
  465. },
  466. want: true,
  467. },
  468. {
  469. name: "ec2 node with different compute type",
  470. labels: map[string]string{
  471. eksComputeTypeLabel: "ec2",
  472. },
  473. want: false,
  474. },
  475. {
  476. name: "node without compute type label",
  477. labels: map[string]string{
  478. "some.other.label": "value",
  479. },
  480. want: false,
  481. },
  482. {
  483. name: "node with empty labels",
  484. labels: map[string]string{},
  485. want: false,
  486. },
  487. {
  488. name: "node with nil labels",
  489. labels: nil,
  490. want: false,
  491. },
  492. }
  493. for _, tt := range tests {
  494. t.Run(tt.name, func(t *testing.T) {
  495. k := &awsKey{
  496. Labels: tt.labels,
  497. }
  498. if got := k.isFargateNode(); got != tt.want {
  499. t.Errorf("awsKey.isFargateNode() = %v, want %v", got, tt.want)
  500. }
  501. })
  502. }
  503. }
  504. func TestGetPricingListURL(t *testing.T) {
  505. tests := []struct {
  506. name string
  507. serviceCode string
  508. nodeList []*clustercache.Node
  509. expected string
  510. }{
  511. {
  512. name: "AmazonEC2 service with us-east-1 region",
  513. serviceCode: "AmazonEC2",
  514. nodeList: []*clustercache.Node{
  515. {
  516. Name: "test-node",
  517. Labels: map[string]string{
  518. "topology.kubernetes.io/region": "us-east-1",
  519. },
  520. },
  521. },
  522. expected: "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/us-east-1/index.json",
  523. },
  524. {
  525. name: "AmazonECS service with us-west-2 region",
  526. serviceCode: "AmazonECS",
  527. nodeList: []*clustercache.Node{
  528. {
  529. Name: "test-node",
  530. Labels: map[string]string{
  531. "topology.kubernetes.io/region": "us-west-2",
  532. },
  533. },
  534. },
  535. expected: "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonECS/current/us-west-2/index.json",
  536. },
  537. {
  538. name: "Chinese region cn-north-1",
  539. serviceCode: "AmazonEC2",
  540. nodeList: []*clustercache.Node{
  541. {
  542. Name: "test-node",
  543. Labels: map[string]string{
  544. "topology.kubernetes.io/region": "cn-north-1",
  545. },
  546. },
  547. },
  548. expected: "https://pricing.cn-north-1.amazonaws.com.cn/offers/v1.0/cn/AmazonEC2/current/cn-north-1/index.json",
  549. },
  550. {
  551. name: "Chinese region cn-northwest-1",
  552. serviceCode: "AmazonECS",
  553. nodeList: []*clustercache.Node{
  554. {
  555. Name: "test-node",
  556. Labels: map[string]string{
  557. "topology.kubernetes.io/region": "cn-northwest-1",
  558. },
  559. },
  560. },
  561. expected: "https://pricing.cn-north-1.amazonaws.com.cn/offers/v1.0/cn/AmazonECS/current/cn-northwest-1/index.json",
  562. },
  563. {
  564. name: "empty node list - multiregion",
  565. serviceCode: "AmazonEC2",
  566. nodeList: []*clustercache.Node{},
  567. expected: "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/index.json",
  568. },
  569. {
  570. name: "multiple regions - multiregion",
  571. serviceCode: "AmazonECS",
  572. nodeList: []*clustercache.Node{
  573. {
  574. Name: "test-node-1",
  575. Labels: map[string]string{
  576. "topology.kubernetes.io/region": "us-east-1",
  577. },
  578. },
  579. {
  580. Name: "test-node-2",
  581. Labels: map[string]string{
  582. "topology.kubernetes.io/region": "us-west-2",
  583. },
  584. },
  585. },
  586. expected: "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonECS/current/index.json",
  587. },
  588. {
  589. name: "node without region label",
  590. serviceCode: "AmazonEC2",
  591. nodeList: []*clustercache.Node{
  592. {
  593. Name: "test-node",
  594. Labels: map[string]string{
  595. "some.other.label": "value",
  596. },
  597. },
  598. },
  599. expected: "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/index.json",
  600. },
  601. }
  602. for _, tt := range tests {
  603. t.Run(tt.name, func(t *testing.T) {
  604. result := getPricingListURL(tt.serviceCode, tt.nodeList)
  605. if result != tt.expected {
  606. t.Errorf("getPricingListURL() = %v, expected %v", result, tt.expected)
  607. }
  608. })
  609. }
  610. }
  611. // Mock cluster cache for testing
  612. type mockClusterCache struct {
  613. pods []*clustercache.Pod
  614. }
  615. func (m *mockClusterCache) Run() {}
  616. func (m *mockClusterCache) Stop() {}
  617. func (m *mockClusterCache) GetAllPods() []*clustercache.Pod {
  618. return m.pods
  619. }
  620. func (m *mockClusterCache) GetAllNodes() []*clustercache.Node {
  621. return nil
  622. }
  623. func (m *mockClusterCache) GetAllPersistentVolumes() []*clustercache.PersistentVolume {
  624. return nil
  625. }
  626. func (m *mockClusterCache) GetAllPersistentVolumeClaims() []*clustercache.PersistentVolumeClaim {
  627. return nil
  628. }
  629. func (m *mockClusterCache) GetAllStorageClasses() []*clustercache.StorageClass {
  630. return nil
  631. }
  632. func (m *mockClusterCache) GetAllServices() []*clustercache.Service {
  633. return nil
  634. }
  635. func (m *mockClusterCache) GetAllDeployments() []*clustercache.Deployment {
  636. return nil
  637. }
  638. func (m *mockClusterCache) GetAllDaemonSets() []*clustercache.DaemonSet {
  639. return nil
  640. }
  641. func (m *mockClusterCache) GetAllStatefulSets() []*clustercache.StatefulSet {
  642. return nil
  643. }
  644. func (m *mockClusterCache) GetAllReplicaSets() []*clustercache.ReplicaSet {
  645. return nil
  646. }
  647. func (m *mockClusterCache) GetAllJobs() []*clustercache.Job {
  648. return nil
  649. }
  650. func (m *mockClusterCache) GetAllNamespaces() []*clustercache.Namespace {
  651. return nil
  652. }
  653. func (m *mockClusterCache) GetAllPodDisruptionBudgets() []*clustercache.PodDisruptionBudget {
  654. return nil
  655. }
  656. func (m *mockClusterCache) GetAllReplicationControllers() []*clustercache.ReplicationController {
  657. return nil
  658. }
  659. func (m *mockClusterCache) GetAllResourceQuotas() []*clustercache.ResourceQuota {
  660. return nil
  661. }
  662. func TestAWS_getFargatePod(t *testing.T) {
  663. tests := []struct {
  664. name string
  665. pods []*clustercache.Pod
  666. awsKey *awsKey
  667. wantPod *clustercache.Pod
  668. wantBool bool
  669. }{
  670. {
  671. name: "pod found for node",
  672. pods: []*clustercache.Pod{
  673. {
  674. Name: "test-pod",
  675. Spec: clustercache.PodSpec{
  676. NodeName: "fargate-node-1",
  677. },
  678. },
  679. },
  680. awsKey: &awsKey{
  681. Name: "fargate-node-1",
  682. },
  683. wantPod: &clustercache.Pod{
  684. Name: "test-pod",
  685. Spec: clustercache.PodSpec{
  686. NodeName: "fargate-node-1",
  687. },
  688. },
  689. wantBool: true,
  690. },
  691. {
  692. name: "pod not found for node",
  693. pods: []*clustercache.Pod{
  694. {
  695. Name: "test-pod",
  696. Spec: clustercache.PodSpec{
  697. NodeName: "different-node",
  698. },
  699. },
  700. },
  701. awsKey: &awsKey{
  702. Name: "fargate-node-1",
  703. },
  704. wantPod: nil,
  705. wantBool: false,
  706. },
  707. {
  708. name: "no pods in cluster",
  709. pods: []*clustercache.Pod{},
  710. awsKey: &awsKey{
  711. Name: "fargate-node-1",
  712. },
  713. wantPod: nil,
  714. wantBool: false,
  715. },
  716. }
  717. for _, tt := range tests {
  718. t.Run(tt.name, func(t *testing.T) {
  719. aws := &AWS{
  720. Clientset: &mockClusterCache{pods: tt.pods},
  721. }
  722. gotPod, gotBool := aws.getFargatePod(tt.awsKey)
  723. if gotBool != tt.wantBool {
  724. t.Errorf("AWS.getFargatePod() gotBool = %v, want %v", gotBool, tt.wantBool)
  725. }
  726. if tt.wantPod == nil && gotPod != nil {
  727. t.Errorf("AWS.getFargatePod() gotPod = %v, want nil", gotPod)
  728. } else if tt.wantPod != nil && gotPod == nil {
  729. t.Errorf("AWS.getFargatePod() gotPod = nil, want %v", tt.wantPod)
  730. } else if tt.wantPod != nil && gotPod != nil {
  731. if gotPod.Name != tt.wantPod.Name || gotPod.Spec.NodeName != tt.wantPod.Spec.NodeName {
  732. t.Errorf("AWS.getFargatePod() gotPod = %v, want %v", gotPod, tt.wantPod)
  733. }
  734. }
  735. })
  736. }
  737. }