aliyunprovider_test.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. package cloud
  2. import (
  3. "fmt"
  4. "testing"
  5. "github.com/aliyun/alibaba-cloud-sdk-go/sdk"
  6. "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
  7. "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/signers"
  8. v1 "k8s.io/api/core/v1"
  9. resource "k8s.io/apimachinery/pkg/api/resource"
  10. )
  11. func TestCreateDescribePriceACSRequest(t *testing.T) {
  12. node := &SlimK8sNode{
  13. InstanceType: "ecs.g6.large",
  14. RegionID: "cn-hangzhou",
  15. PriceUnit: "Hour",
  16. MemorySizeInKiB: "16KiB",
  17. IsIoOptimized: true,
  18. OSType: "Linux",
  19. ProviderID: "Ali-XXX-node-01",
  20. InstanceTypeFamily: "g6",
  21. }
  22. disk := &SlimK8sDisk{
  23. DiskType: "data",
  24. RegionID: "cn-hangzhou",
  25. PriceUnit: "Hour",
  26. SizeInGiB: "20",
  27. DiskCategory: "diskCategory",
  28. PerformanceLevel: "cloud_essd",
  29. ProviderID: "d-Ali-XXX-01",
  30. StorageClass: "testStorageClass",
  31. }
  32. cases := []struct {
  33. name string
  34. testStruct interface{}
  35. expectedError error
  36. }{
  37. {
  38. name: "test CreateDescribePriceACSRequest with SlimK8sNode struct Object",
  39. testStruct: node,
  40. expectedError: nil,
  41. },
  42. {
  43. name: "test CreateDescribePriceACSRequest with SlimK8sDisk struct Object",
  44. testStruct: disk,
  45. expectedError: nil,
  46. },
  47. }
  48. for _, c := range cases {
  49. t.Run(c.name, func(t *testing.T) {
  50. _, err := createDescribePriceACSRequest(c.testStruct)
  51. if err != nil && c.expectedError == nil {
  52. t.Fatalf("Case name %s: Error converting to Alibaba cloud request", c.name)
  53. }
  54. })
  55. }
  56. }
  57. func TestProcessDescribePriceAndCreateAlibabaPricing(t *testing.T) {
  58. // Skipping this test case since it exposes secret but a good test case to verify when
  59. // supporting a new family of instances, steps to perform are
  60. // STEP 1: Comment the t.Skip() line and then replace XXX_KEY_ID with the alibaba key id of your account and XXX_SECRET_ID with alibaba cloud secret of your account.
  61. // STEP 2: Once you verify describePrice is working and no change needed in processDescribePriceAndCreateAlibabaPricing, you can go ahead and revert the step 1 changes.
  62. // This test case was use to test all general puprose instances
  63. t.Skip()
  64. client, err := sdk.NewClientWithAccessKey("cn-hangzhou", "XXX_KEY_ID", "XXX_SECRET_ID")
  65. if err != nil {
  66. t.Errorf("Error connecting to the Alibaba cloud")
  67. }
  68. aak := credentials.NewAccessKeyCredential("XXX_KEY_ID", "XXX_SECRET_ID")
  69. signer := signers.NewAccessKeySigner(aak)
  70. cases := []struct {
  71. name string
  72. teststruct interface{}
  73. expectedError error
  74. }{
  75. {
  76. name: "test General Purpose Type g7 instance family",
  77. teststruct: &SlimK8sNode{
  78. InstanceType: "ecs.g7.4xlarge",
  79. RegionID: "cn-hangzhou",
  80. PriceUnit: "Hour",
  81. MemorySizeInKiB: "16777216KiB",
  82. IsIoOptimized: true,
  83. OSType: "Linux",
  84. ProviderID: "cn-hangzhou.i-test-01a",
  85. InstanceTypeFamily: "g7",
  86. },
  87. expectedError: nil,
  88. },
  89. {
  90. name: "test General Purpose Type g7a instance family",
  91. teststruct: &SlimK8sNode{
  92. InstanceType: "ecs.g7a.8xlarge",
  93. RegionID: "cn-hangzhou",
  94. PriceUnit: "Hour",
  95. MemorySizeInKiB: "33554432KiB",
  96. IsIoOptimized: true,
  97. OSType: "Linux",
  98. ProviderID: "cn-hangzhou.i-test-01b",
  99. InstanceTypeFamily: "g7a",
  100. },
  101. expectedError: nil,
  102. },
  103. {
  104. name: "test Enhanced General Purpose Type g6e instance family",
  105. teststruct: &SlimK8sNode{
  106. InstanceType: "ecs.g6e.xlarge",
  107. RegionID: "cn-hangzhou",
  108. PriceUnit: "Hour",
  109. MemorySizeInKiB: "16777216KiB",
  110. IsIoOptimized: true,
  111. OSType: "Linux",
  112. ProviderID: "cn-hangzhou.i-test-01",
  113. InstanceTypeFamily: "g6e",
  114. },
  115. expectedError: nil,
  116. },
  117. {
  118. name: "test General Purpose Type g6 instance family",
  119. teststruct: &SlimK8sNode{
  120. InstanceType: "ecs.g6.3xlarge",
  121. RegionID: "cn-hangzhou",
  122. PriceUnit: "Hour",
  123. MemorySizeInKiB: "50331648KiB",
  124. IsIoOptimized: true,
  125. OSType: "Linux",
  126. ProviderID: "cn-hangzhou.i-test-02",
  127. InstanceTypeFamily: "g6",
  128. },
  129. expectedError: nil,
  130. },
  131. {
  132. name: "test General Purpose Type g5 instance family",
  133. teststruct: &SlimK8sNode{
  134. InstanceType: "ecs.g5.2xlarge",
  135. RegionID: "cn-hangzhou",
  136. PriceUnit: "Hour",
  137. MemorySizeInKiB: "33554432KiB",
  138. IsIoOptimized: true,
  139. OSType: "Linux",
  140. ProviderID: "cn-hangzhou.i-test-03",
  141. InstanceTypeFamily: "g5",
  142. },
  143. expectedError: nil,
  144. },
  145. {
  146. name: "test General Purpose Type sn2 instance family",
  147. teststruct: &SlimK8sNode{
  148. InstanceType: "ecs.sn2.large",
  149. RegionID: "cn-hangzhou",
  150. PriceUnit: "Hour",
  151. MemorySizeInKiB: "16777216KiB",
  152. IsIoOptimized: true,
  153. OSType: "Linux",
  154. ProviderID: "cn-hangzhou.i-test-04",
  155. InstanceTypeFamily: "sn2",
  156. },
  157. expectedError: nil,
  158. },
  159. {
  160. name: "test General Purpose Type with Enhanced Network Performance sn2ne instance family",
  161. teststruct: &SlimK8sNode{
  162. InstanceType: "ecs.sn2ne.2xlarge",
  163. RegionID: "cn-hangzhou",
  164. PriceUnit: "Hour",
  165. MemorySizeInKiB: "33554432KiB",
  166. IsIoOptimized: true,
  167. OSType: "Linux",
  168. ProviderID: "cn-hangzhou.i-test-05",
  169. InstanceTypeFamily: "sn2ne",
  170. },
  171. expectedError: nil,
  172. },
  173. {
  174. name: "test Memory Optmized instance type r7 instance family",
  175. teststruct: &SlimK8sNode{
  176. InstanceType: "ecs.r7.6xlarge",
  177. RegionID: "cn-hangzhou",
  178. PriceUnit: "Hour",
  179. MemorySizeInKiB: "2013265592KiB",
  180. IsIoOptimized: true,
  181. OSType: "Linux",
  182. ProviderID: "cn-hangzhou.i-test-06",
  183. InstanceTypeFamily: "r7",
  184. },
  185. expectedError: nil,
  186. },
  187. {
  188. name: "test Memory Optmized instance type r7a instance family",
  189. teststruct: &SlimK8sNode{
  190. InstanceType: "ecs.r7a.8xlarge",
  191. RegionID: "cn-hangzhou",
  192. PriceUnit: "Hour",
  193. MemorySizeInKiB: "33554432KiB",
  194. IsIoOptimized: true,
  195. OSType: "Linux",
  196. ProviderID: "cn-hangzhou.i-test-06a",
  197. InstanceTypeFamily: "r7a",
  198. },
  199. expectedError: nil,
  200. },
  201. {
  202. name: "test Enhanced Memory Optmized instance type r6e instance family",
  203. teststruct: &SlimK8sNode{
  204. InstanceType: "ecs.r6e.4xlarge",
  205. RegionID: "cn-hangzhou",
  206. PriceUnit: "Hour",
  207. MemorySizeInKiB: "2013265592KiB",
  208. IsIoOptimized: true,
  209. OSType: "Linux",
  210. ProviderID: "cn-hangzhou.i-test-07",
  211. InstanceTypeFamily: "r6e",
  212. },
  213. expectedError: nil,
  214. },
  215. {
  216. name: "test Memory Optmized instance type r6a instance family",
  217. teststruct: &SlimK8sNode{
  218. InstanceType: "ecs.r6a.8xlarge",
  219. RegionID: "cn-hangzhou",
  220. PriceUnit: "Hour",
  221. MemorySizeInKiB: "33554432KiB",
  222. IsIoOptimized: true,
  223. OSType: "Linux",
  224. ProviderID: "cn-hangzhou.i-test-07a",
  225. InstanceTypeFamily: "r6a",
  226. },
  227. expectedError: nil,
  228. },
  229. {
  230. name: "test Memory Optmized instance type r6 instance family",
  231. teststruct: &SlimK8sNode{
  232. InstanceType: "ecs.r6.8xlarge",
  233. RegionID: "cn-hangzhou",
  234. PriceUnit: "Hour",
  235. MemorySizeInKiB: "33554432KiB",
  236. IsIoOptimized: true,
  237. OSType: "Linux",
  238. ProviderID: "cn-hangzhou.i-test-08",
  239. InstanceTypeFamily: "r6",
  240. },
  241. expectedError: nil,
  242. },
  243. {
  244. name: "test Memory type instance and r5 instance family",
  245. teststruct: &SlimK8sNode{
  246. InstanceType: "ecs.r5.xlarge",
  247. RegionID: "cn-hangzhou",
  248. PriceUnit: "Hour",
  249. MemorySizeInKiB: "33554432KiB",
  250. IsIoOptimized: true,
  251. OSType: "Linux",
  252. ProviderID: "cn-hangzhou.i-test-09",
  253. InstanceTypeFamily: "r5",
  254. },
  255. expectedError: nil,
  256. },
  257. {
  258. name: "test Memory Optmized instance type with se1 instance family",
  259. teststruct: &SlimK8sNode{
  260. InstanceType: "ecs.se1.4xlarge",
  261. RegionID: "cn-hangzhou",
  262. PriceUnit: "Hour",
  263. MemorySizeInKiB: "16777216KiB",
  264. IsIoOptimized: true,
  265. OSType: "Linux",
  266. ProviderID: "cn-hangzhou.i-test-10",
  267. InstanceTypeFamily: "se1",
  268. },
  269. expectedError: nil,
  270. },
  271. {
  272. name: "test Memory Optmized instance type with Enhanced Network Performance se1ne instance family",
  273. teststruct: &SlimK8sNode{
  274. InstanceType: "ecs.se1ne.3xlarge",
  275. RegionID: "cn-hangzhou",
  276. PriceUnit: "Hour",
  277. MemorySizeInKiB: "100663296KiB",
  278. IsIoOptimized: true,
  279. OSType: "Linux",
  280. ProviderID: "cn-hangzhou.i-test-11",
  281. InstanceTypeFamily: "se1ne",
  282. },
  283. expectedError: nil,
  284. },
  285. {
  286. name: "test High Memory type with re6 instance family",
  287. teststruct: &SlimK8sNode{
  288. InstanceType: "ecs.re6.8xlarge",
  289. RegionID: "cn-hangzhou",
  290. PriceUnit: "Hour",
  291. MemorySizeInKiB: "33554432KiB",
  292. IsIoOptimized: true,
  293. OSType: "Linux",
  294. ProviderID: "cn-hangzhou.i-test-12",
  295. InstanceTypeFamily: "re6",
  296. },
  297. expectedError: nil,
  298. },
  299. {
  300. name: "test Persistent Memory Optimized type with re6p instance family",
  301. teststruct: &SlimK8sNode{
  302. InstanceType: "ecs.re6p.4xlarge",
  303. RegionID: "cn-hangzhou",
  304. PriceUnit: "Hour",
  305. MemorySizeInKiB: "33554432KiB",
  306. IsIoOptimized: true,
  307. OSType: "Linux",
  308. ProviderID: "cn-hangzhou.i-test-13",
  309. InstanceTypeFamily: "re6p",
  310. },
  311. expectedError: nil,
  312. },
  313. {
  314. name: "test Memory type with re4 instance family",
  315. teststruct: &SlimK8sNode{
  316. InstanceType: "ecs.re4.10xlarge",
  317. RegionID: "cn-hangzhou",
  318. PriceUnit: "Hour",
  319. MemorySizeInKiB: "41943040KiB",
  320. IsIoOptimized: true,
  321. OSType: "Linux",
  322. ProviderID: "cn-hangzhou.i-test-14",
  323. InstanceTypeFamily: "re4",
  324. },
  325. expectedError: nil,
  326. },
  327. {
  328. name: "test Memory optimized type with se1 instance family",
  329. teststruct: &SlimK8sNode{
  330. InstanceType: "ecs.se1.8xlarge",
  331. RegionID: "cn-hangzhou",
  332. PriceUnit: "Hour",
  333. MemorySizeInKiB: "33554432KiB",
  334. IsIoOptimized: true,
  335. OSType: "Linux",
  336. ProviderID: "cn-hangzhou.i-test-15",
  337. InstanceTypeFamily: "se1",
  338. },
  339. expectedError: nil,
  340. },
  341. {
  342. name: "test for a nil information",
  343. teststruct: nil,
  344. expectedError: fmt.Errorf("unsupported ECS pricing component at this time"),
  345. },
  346. {
  347. name: "test Cloud Disk with Category cloud representing basic disk",
  348. teststruct: &SlimK8sDisk{
  349. DiskType: "data",
  350. RegionID: "cn-hangzhou",
  351. PriceUnit: "Hour",
  352. SizeInGiB: "20",
  353. DiskCategory: "cloud",
  354. ProviderID: "d-Ali-cloud-XXX-01",
  355. StorageClass: "temp",
  356. },
  357. expectedError: nil,
  358. },
  359. {
  360. name: "test Cloud Disk with Category cloud_efficiency representing ultra disk",
  361. teststruct: &SlimK8sDisk{
  362. DiskType: "data",
  363. RegionID: "cn-hangzhou",
  364. PriceUnit: "Hour",
  365. SizeInGiB: "40",
  366. DiskCategory: "cloud_efficiency",
  367. ProviderID: "d-Ali-cloud-XXX-02",
  368. StorageClass: "temp",
  369. },
  370. expectedError: nil,
  371. },
  372. {
  373. name: "test Cloud Disk with Category cloud_ssd representing standard SSD",
  374. teststruct: &SlimK8sDisk{
  375. DiskType: "data",
  376. RegionID: "cn-hangzhou",
  377. PriceUnit: "Hour",
  378. SizeInGiB: "40",
  379. DiskCategory: "cloud_efficiency",
  380. ProviderID: "d-Ali-cloud-XXX-02",
  381. StorageClass: "temp",
  382. },
  383. expectedError: nil,
  384. },
  385. {
  386. name: "test Cloud Disk with Category cloud_essd representing Enhanced SSD with PL2 performance level",
  387. teststruct: &SlimK8sDisk{
  388. DiskType: "data",
  389. RegionID: "cn-hangzhou",
  390. PriceUnit: "Hour",
  391. SizeInGiB: "80",
  392. DiskCategory: "cloud_ssd",
  393. PerformanceLevel: "PL2",
  394. ProviderID: "d-Ali-cloud-XXX-04",
  395. StorageClass: "temp",
  396. },
  397. expectedError: nil,
  398. },
  399. }
  400. custom := &CustomPricing{}
  401. for _, c := range cases {
  402. t.Run(c.name, func(t *testing.T) {
  403. pricingObj, err := processDescribePriceAndCreateAlibabaPricing(client, c.teststruct, signer, custom)
  404. if err != nil && c.expectedError == nil {
  405. t.Fatalf("Case name %s: got an error %s", c.name, err)
  406. }
  407. if c.teststruct != nil {
  408. if pricingObj == nil {
  409. t.Fatalf("Case name %s: got a nil pricing object", c.name)
  410. }
  411. t.Logf("Case name %s: Pricing Information gathered for instanceType is %v", c.name, pricingObj.PricingTerms.PricingDetails.TradePrice)
  412. }
  413. })
  414. }
  415. }
  416. func TestGetInstanceFamilyFromType(t *testing.T) {
  417. cases := []struct {
  418. name string
  419. instanceType string
  420. expectedInstanceFamily string
  421. }{
  422. {
  423. name: "test if ecs.[instance-family].[different-type] work",
  424. instanceType: "ecs.sn2ne.2xlarge",
  425. expectedInstanceFamily: "sn2ne",
  426. },
  427. {
  428. name: "test if random word gives you ALIBABA_UNKNOWN_INSTANCE_FAMILY_TYPE value ",
  429. instanceType: "random.value",
  430. expectedInstanceFamily: ALIBABA_UNKNOWN_INSTANCE_FAMILY_TYPE,
  431. },
  432. {
  433. name: "test if random instance family gives you ALIBABA_NOT_SUPPORTED_INSTANCE_FAMILY_TYPE value ",
  434. instanceType: "ecs.g7e.2xlarge",
  435. expectedInstanceFamily: ALIBABA_NOT_SUPPORTED_INSTANCE_FAMILY_TYPE,
  436. },
  437. }
  438. for _, c := range cases {
  439. t.Run(c.name, func(t *testing.T) {
  440. returnValue := getInstanceFamilyFromType(c.instanceType)
  441. if returnValue != c.expectedInstanceFamily {
  442. t.Fatalf("Case name %s: expected instance family of type %s but got %s", c.name, c.expectedInstanceFamily, returnValue)
  443. }
  444. })
  445. }
  446. }
  447. func TestDetermineKeyForPricing(t *testing.T) {
  448. type randomK8sStruct struct {
  449. name string
  450. }
  451. cases := []struct {
  452. name string
  453. testVar interface{}
  454. expectedKey string
  455. expectedError error
  456. }{
  457. {
  458. name: "test when all RegionID, InstanceType, OSType & ALIBABA_OPTIMIZE_KEYWORD words are used in Node key",
  459. testVar: &SlimK8sNode{
  460. InstanceType: "ecs.sn2.large",
  461. RegionID: "cn-hangzhou",
  462. PriceUnit: "Hour",
  463. MemorySizeInKiB: "16777216KiB",
  464. IsIoOptimized: true,
  465. OSType: "linux",
  466. ProviderID: "cn-hangzhou.i-test-04",
  467. InstanceTypeFamily: "sn2",
  468. },
  469. expectedKey: "cn-hangzhou::ecs.sn2.large::linux::optimize",
  470. expectedError: nil,
  471. },
  472. {
  473. name: "test missing InstanceType to create Node key",
  474. testVar: &SlimK8sNode{
  475. RegionID: "cn-hangzhou",
  476. PriceUnit: "Hour",
  477. MemorySizeInKiB: "16777216KiB",
  478. IsIoOptimized: true,
  479. OSType: "linux",
  480. ProviderID: "cn-hangzhou.i-test-04",
  481. },
  482. expectedKey: "cn-hangzhou::linux::optimize",
  483. expectedError: nil,
  484. },
  485. {
  486. name: "test when node has a systemDisk Information with missing Performance level",
  487. testVar: &SlimK8sNode{
  488. InstanceType: "ecs.sn2.large",
  489. RegionID: "cn-hangzhou",
  490. PriceUnit: "Hour",
  491. MemorySizeInKiB: "16777216KiB",
  492. IsIoOptimized: true,
  493. OSType: "linux",
  494. ProviderID: "cn-hangzhou.i-test-04",
  495. InstanceTypeFamily: "sn2",
  496. SystemDisk: &SlimK8sDisk{
  497. DiskType: "system",
  498. RegionID: "cn-hangzhou",
  499. PriceUnit: "Hour",
  500. SizeInGiB: "40",
  501. DiskCategory: "cloud_efficiency",
  502. ProviderID: "d-Ali-cloud-XXX-i1",
  503. StorageClass: "",
  504. },
  505. },
  506. expectedKey: "cn-hangzhou::ecs.sn2.large::linux::optimize::cloud_efficiency::40",
  507. expectedError: nil,
  508. },
  509. {
  510. name: "test when node has a systemDisk Information with all information",
  511. testVar: &SlimK8sNode{
  512. InstanceType: "ecs.sn2.large",
  513. RegionID: "cn-hangzhou",
  514. PriceUnit: "Hour",
  515. MemorySizeInKiB: "16777216KiB",
  516. IsIoOptimized: true,
  517. OSType: "linux",
  518. ProviderID: "cn-hangzhou.i-test-04",
  519. InstanceTypeFamily: "sn2",
  520. SystemDisk: &SlimK8sDisk{
  521. DiskType: "data",
  522. RegionID: "cn-hangzhou",
  523. PriceUnit: "Hour",
  524. SizeInGiB: "80",
  525. DiskCategory: "cloud_ssd",
  526. PerformanceLevel: "PL2",
  527. ProviderID: "d-Ali-cloud-XXX-04",
  528. StorageClass: "",
  529. },
  530. },
  531. expectedKey: "cn-hangzhou::ecs.sn2.large::linux::optimize::cloud_ssd::80::PL2",
  532. expectedError: nil,
  533. },
  534. {
  535. name: "test random k8s struct should return unsupported error",
  536. testVar: &randomK8sStruct{
  537. name: "test struct",
  538. },
  539. expectedKey: "",
  540. expectedError: fmt.Errorf("unsupported ECS type randomK8sStruct for DescribePrice at this time"),
  541. },
  542. {
  543. name: "test for nil check",
  544. testVar: nil,
  545. expectedKey: "",
  546. expectedError: fmt.Errorf("unsupported ECS type randomK8sStruct for DescribePrice at this time"),
  547. },
  548. {
  549. name: "test when all RegionID, InstanceType, OSType & ALIBABA_OPTIMIZE_KEYWORD words are used to key",
  550. testVar: &SlimK8sDisk{
  551. DiskType: "data",
  552. RegionID: "cn-hangzhou",
  553. PriceUnit: "Hour",
  554. SizeInGiB: "40",
  555. DiskCategory: "cloud_efficiency",
  556. ProviderID: "d-Ali-cloud-XXX-02",
  557. StorageClass: "temp",
  558. },
  559. expectedKey: "cn-hangzhou::data::cloud_efficiency::40",
  560. expectedError: nil,
  561. },
  562. {
  563. name: "test missing InstanceType to create key",
  564. testVar: &SlimK8sDisk{
  565. DiskType: "data",
  566. RegionID: "cn-hangzhou",
  567. PriceUnit: "Hour",
  568. SizeInGiB: "80",
  569. DiskCategory: "cloud_ssd",
  570. PerformanceLevel: "PL2",
  571. ProviderID: "d-Ali-cloud-XXX-04",
  572. StorageClass: "temp",
  573. },
  574. expectedKey: "cn-hangzhou::data::cloud_ssd::PL2::80",
  575. expectedError: nil,
  576. },
  577. }
  578. for _, c := range cases {
  579. t.Run(c.name, func(t *testing.T) {
  580. returnString, returnErr := determineKeyForPricing(c.testVar)
  581. if c.expectedError == nil && returnErr != nil {
  582. t.Fatalf("Case name %s: expected error was nil but recieved error %v", c.name, returnErr)
  583. }
  584. if returnString != c.expectedKey {
  585. t.Fatalf("Case name %s: determineKeyForPricing recieved %s but expected %s", c.name, returnString, c.expectedKey)
  586. }
  587. })
  588. }
  589. }
  590. func TestGenerateSlimK8sNodeFromV1Node(t *testing.T) {
  591. testv1Node := &v1.Node{}
  592. testv1Node.Labels = make(map[string]string)
  593. testv1Node.Labels["topology.kubernetes.io/region"] = "us-east-1"
  594. testv1Node.Labels["beta.kubernetes.io/os"] = "linux"
  595. testv1Node.Labels["node.kubernetes.io/instance-type"] = "ecs.sn2ne.2xlarge"
  596. testv1Node.Status.Capacity = v1.ResourceList{
  597. v1.ResourceMemory: *resource.NewQuantity(16, resource.BinarySI),
  598. }
  599. cases := []struct {
  600. name string
  601. testNode *v1.Node
  602. expectedSlimNode *SlimK8sNode
  603. }{
  604. {
  605. name: "test a generic *v1.Node to *SlimK8sNode Conversion",
  606. testNode: testv1Node,
  607. expectedSlimNode: &SlimK8sNode{
  608. InstanceType: "ecs.sn2ne.2xlarge",
  609. RegionID: "us-east-1",
  610. PriceUnit: ALIBABA_HOUR_PRICE_UNIT,
  611. MemorySizeInKiB: "16",
  612. IsIoOptimized: true,
  613. OSType: "linux",
  614. InstanceTypeFamily: "sn2ne",
  615. },
  616. },
  617. }
  618. for _, c := range cases {
  619. t.Run(c.name, func(t *testing.T) {
  620. returnSlimK8sNode := generateSlimK8sNodeFromV1Node(c.testNode)
  621. if returnSlimK8sNode.InstanceType != c.expectedSlimNode.InstanceType {
  622. t.Fatalf("unexpected conversion in function generateSlimK8sNodeFromV1Node expected InstanceType: %s , recieved InstanceType: %s", c.expectedSlimNode.InstanceType, returnSlimK8sNode.InstanceType)
  623. }
  624. if returnSlimK8sNode.RegionID != c.expectedSlimNode.RegionID {
  625. t.Fatalf("unexpected conversion in function generateSlimK8sNodeFromV1Node expected RegionID: %s , recieved RegionID: %s", c.expectedSlimNode.RegionID, returnSlimK8sNode.RegionID)
  626. }
  627. if returnSlimK8sNode.PriceUnit != c.expectedSlimNode.PriceUnit {
  628. t.Fatalf("unexpected conversion in function generateSlimK8sNodeFromV1Node expected PriceUnit: %s , recieved PriceUnit: %s", c.expectedSlimNode.PriceUnit, returnSlimK8sNode.PriceUnit)
  629. }
  630. if returnSlimK8sNode.MemorySizeInKiB != c.expectedSlimNode.MemorySizeInKiB {
  631. t.Fatalf("unexpected conversion in function generateSlimK8sNodeFromV1Node expected MemorySizeInKiB: %s , recieved MemorySizeInKiB: %s", c.expectedSlimNode.MemorySizeInKiB, returnSlimK8sNode.MemorySizeInKiB)
  632. }
  633. if returnSlimK8sNode.OSType != c.expectedSlimNode.OSType {
  634. t.Fatalf("unexpected conversion in function generateSlimK8sNodeFromV1Node expected OSType: %s , recieved OSType: %s", c.expectedSlimNode.OSType, returnSlimK8sNode.OSType)
  635. }
  636. if returnSlimK8sNode.InstanceTypeFamily != c.expectedSlimNode.InstanceTypeFamily {
  637. t.Fatalf("unexpected conversion in function generateSlimK8sNodeFromV1Node expected InstanceTypeFamily: %s , recieved InstanceTypeFamily: %s", c.expectedSlimNode.InstanceTypeFamily, returnSlimK8sNode.InstanceTypeFamily)
  638. }
  639. })
  640. }
  641. }
  642. func TestGenerateSlimK8sDiskFromV1PV(t *testing.T) {
  643. testv1PV := &v1.PersistentVolume{}
  644. testv1PV.Spec.Capacity = v1.ResourceList{
  645. v1.ResourceStorage: *resource.NewQuantity(16*1024*1024*1024, resource.BinarySI),
  646. }
  647. testv1PV.Spec.CSI = &v1.CSIPersistentVolumeSource{}
  648. testv1PV.Spec.CSI.VolumeHandle = "testPV"
  649. testv1PV.Spec.CSI.VolumeAttributes = map[string]string{
  650. "performanceLevel": "PL2",
  651. "type": "cloud_essd",
  652. }
  653. testv1PV.Spec.CSI.VolumeHandle = "testPV"
  654. testv1PV.Spec.StorageClassName = "testStorageClass"
  655. cases := []struct {
  656. name string
  657. testPV *v1.PersistentVolume
  658. expectedSlimDisk *SlimK8sDisk
  659. inpRegionID string
  660. }{
  661. {
  662. name: "test a generic *v1.Node to *SlimK8sNode Conversion",
  663. testPV: testv1PV,
  664. expectedSlimDisk: &SlimK8sDisk{
  665. DiskType: ALIBABA_DATA_DISK_CATEGORY,
  666. RegionID: "us-east-1",
  667. PriceUnit: ALIBABA_HOUR_PRICE_UNIT,
  668. SizeInGiB: "16",
  669. DiskCategory: "cloud_essd",
  670. PerformanceLevel: "PL2",
  671. ProviderID: "testPV",
  672. StorageClass: "testStorageClass",
  673. },
  674. inpRegionID: "us-east-1",
  675. },
  676. }
  677. for _, c := range cases {
  678. t.Run(c.name, func(t *testing.T) {
  679. returnSlimK8sDisk := generateSlimK8sDiskFromV1PV(c.testPV, c.inpRegionID)
  680. if returnSlimK8sDisk.DiskType != c.expectedSlimDisk.DiskType {
  681. t.Fatalf("unexpected conversion in function generateSlimK8sDiskFromV1PV expected DiskType: %s , recieved DiskType: %s", c.expectedSlimDisk.DiskType, returnSlimK8sDisk.DiskType)
  682. }
  683. if returnSlimK8sDisk.RegionID != c.expectedSlimDisk.RegionID {
  684. t.Fatalf("unexpected conversion in function generateSlimK8sDiskFromV1PV expected RegionID: %s , recieved RegionID Type: %s", c.expectedSlimDisk.RegionID, returnSlimK8sDisk.RegionID)
  685. }
  686. if returnSlimK8sDisk.PriceUnit != c.expectedSlimDisk.PriceUnit {
  687. t.Fatalf("unexpected conversion in function generateSlimK8sDiskFromV1PV expected PriceUnit: %s , recieved PriceUnit Type: %s", c.expectedSlimDisk.PriceUnit, returnSlimK8sDisk.PriceUnit)
  688. }
  689. if returnSlimK8sDisk.SizeInGiB != c.expectedSlimDisk.SizeInGiB {
  690. t.Fatalf("unexpected conversion in function generateSlimK8sDiskFromV1PV expected SizeInGiB: %s , recieved SizeInGiB Type: %s", c.expectedSlimDisk.SizeInGiB, returnSlimK8sDisk.SizeInGiB)
  691. }
  692. if returnSlimK8sDisk.DiskCategory != c.expectedSlimDisk.DiskCategory {
  693. t.Fatalf("unexpected conversion in function generateSlimK8sDiskFromV1PV expected DiskCategory: %s , recieved DiskCategory Type: %s", c.expectedSlimDisk.DiskCategory, returnSlimK8sDisk.DiskCategory)
  694. }
  695. if returnSlimK8sDisk.PerformanceLevel != c.expectedSlimDisk.PerformanceLevel {
  696. t.Fatalf("unexpected conversion in function generateSlimK8sDiskFromV1PV expected PerformanceLevel: %s , recieved PerformanceLevel Type: %s", c.expectedSlimDisk.PerformanceLevel, returnSlimK8sDisk.PerformanceLevel)
  697. }
  698. if returnSlimK8sDisk.ProviderID != c.expectedSlimDisk.ProviderID {
  699. t.Fatalf("unexpected conversion in function generateSlimK8sDiskFromV1PV expected ProviderID: %s , recieved ProviderID Type: %s", c.expectedSlimDisk.ProviderID, returnSlimK8sDisk.ProviderID)
  700. }
  701. if returnSlimK8sDisk.StorageClass != c.expectedSlimDisk.StorageClass {
  702. t.Fatalf("unexpected conversion in function generateSlimK8sDiskFromV1PV expected StorageClass: %s , recieved StorageClass Type: %s", c.expectedSlimDisk.StorageClass, returnSlimK8sDisk.StorageClass)
  703. }
  704. })
  705. }
  706. }
  707. func TestGetNumericalValueFromResourceQuantity(t *testing.T) {
  708. cases := []struct {
  709. name string
  710. inputResourceQuanity string
  711. expectedValue string
  712. }{
  713. {
  714. name: "positive scenario: when inputResourceQuantity is 10Gi",
  715. inputResourceQuanity: "10Gi",
  716. expectedValue: "10",
  717. },
  718. {
  719. name: "negative scenario: when inputResourceQuantity is Gi",
  720. inputResourceQuanity: "Gi",
  721. expectedValue: ALIBABA_DEFAULT_DATADISK_SIZE,
  722. },
  723. {
  724. name: "negative scenario: when inputResourceQuantity is 10",
  725. inputResourceQuanity: "10",
  726. expectedValue: ALIBABA_DEFAULT_DATADISK_SIZE,
  727. },
  728. {
  729. name: "negative scenario: when inputResourceQuantity is empty string",
  730. inputResourceQuanity: "",
  731. expectedValue: ALIBABA_DEFAULT_DATADISK_SIZE,
  732. },
  733. }
  734. for _, c := range cases {
  735. t.Run(c.name, func(t *testing.T) {
  736. returnValue := getNumericalValueFromResourceQuantity(c.inputResourceQuanity)
  737. if c.expectedValue != returnValue {
  738. t.Fatalf("Case name %s: getNumericalValueFromResourceQuantity recieved %s but expected %s", c.name, returnValue, c.expectedValue)
  739. }
  740. })
  741. }
  742. }
  743. func TestDeterminePVRegion(t *testing.T) {
  744. genericNodeAffinityTestStruct := v1.NodeSelectorTerm{
  745. MatchExpressions: []v1.NodeSelectorRequirement{
  746. {
  747. Key: "topology.diskplugin.csi.alibabacloud.com/zone",
  748. Operator: v1.NodeSelectorOpIn,
  749. Values: []string{"us-east-1a"},
  750. },
  751. },
  752. MatchFields: []v1.NodeSelectorRequirement{},
  753. }
  754. // testPV1 contains the Label with region information as well as node affinity in spec
  755. testPV1 := &v1.PersistentVolume{}
  756. testPV1.Name = "testPV1"
  757. testPV1.Labels = make(map[string]string)
  758. testPV1.Labels[ALIBABA_DISK_TOPOLOGY_REGION_LABEL] = "us-east-1"
  759. testPV1.Spec.NodeAffinity = &v1.VolumeNodeAffinity{
  760. Required: &v1.NodeSelector{
  761. NodeSelectorTerms: []v1.NodeSelectorTerm{genericNodeAffinityTestStruct},
  762. },
  763. }
  764. // testPV2 contains the only zone label
  765. testPV2 := &v1.PersistentVolume{}
  766. testPV2.Name = "testPV2"
  767. testPV2.Labels = make(map[string]string)
  768. testPV2.Labels[ALIBABA_DISK_TOPOLOGY_ZONE_LABEL] = "us-east-1a"
  769. // testPV3 contains only node affinity in spec
  770. testPV3 := &v1.PersistentVolume{}
  771. testPV3.Name = "testPV3"
  772. testPV3.Spec.NodeAffinity = &v1.VolumeNodeAffinity{
  773. Required: &v1.NodeSelector{
  774. NodeSelectorTerms: []v1.NodeSelectorTerm{genericNodeAffinityTestStruct},
  775. },
  776. }
  777. // testPV4 contains no label/annotation or any node affinity
  778. testPV4 := &v1.PersistentVolume{}
  779. testPV4.Name = "testPV4"
  780. cases := []struct {
  781. name string
  782. inputPV *v1.PersistentVolume
  783. expectedRegion string
  784. }{
  785. {
  786. name: "When Region label topology.diskplugin.csi.alibabacloud.com/region is present along with node affinity details",
  787. inputPV: testPV1,
  788. expectedRegion: "us-east-1",
  789. },
  790. {
  791. name: "When zone label topology.diskplugin.csi.alibabacloud.com/zone is present function has to determine region",
  792. inputPV: testPV2,
  793. expectedRegion: "us-east-1",
  794. },
  795. {
  796. name: "When only node affinity detail is present function has to determine the region",
  797. inputPV: testPV3,
  798. expectedRegion: "us-east-1",
  799. },
  800. {
  801. name: "When no region/zone information is present function returns empty to default to cluster region",
  802. inputPV: testPV4,
  803. expectedRegion: "",
  804. },
  805. }
  806. for _, c := range cases {
  807. t.Run(c.name, func(t *testing.T) {
  808. returnRegion := determinePVRegion(c.inputPV)
  809. if c.expectedRegion != returnRegion {
  810. t.Fatalf("Case name %s: determinePVRegion recieved region :%s but expected region: %s", c.name, returnRegion, c.expectedRegion)
  811. }
  812. })
  813. }
  814. }