controller_test.go 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548
  1. package config
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "testing"
  7. cloudconfig "github.com/opencost/opencost/pkg/cloud"
  8. "github.com/opencost/opencost/pkg/cloud/aws"
  9. "github.com/opencost/opencost/pkg/cloud/gcp"
  10. )
  11. var configFile = "test.json"
  12. // Baseline valid config
  13. var validAthenaConf = &aws.AthenaConfiguration{
  14. Bucket: "bucket",
  15. Region: "region",
  16. Database: "database",
  17. Table: "table",
  18. Workgroup: "workgroup",
  19. Account: "account",
  20. Authorizer: &aws.ServiceAccount{},
  21. }
  22. // Config with the same key as the baseline but is not equal to it because of the change in the non-keyed property Workgroup
  23. var validAthenaConfModifiedProperty = &aws.AthenaConfiguration{
  24. Bucket: "bucket",
  25. Region: "region",
  26. Database: "database",
  27. Table: "table",
  28. Workgroup: "workgroup1",
  29. Account: "account",
  30. Authorizer: &aws.ServiceAccount{},
  31. }
  32. // Config with the same key as baseline but is invalid due to missing Authorizer
  33. var invalidAthenaConf = &aws.AthenaConfiguration{
  34. Bucket: "bucket",
  35. Region: "region",
  36. Database: "database",
  37. Table: "table",
  38. Workgroup: "workgroup",
  39. Account: "account",
  40. Authorizer: nil,
  41. }
  42. // A valid config with a different key from the baseline
  43. var validBigQueryConf = &gcp.BigQueryConfiguration{
  44. ProjectID: "projectID",
  45. Dataset: "dataset",
  46. Table: "table",
  47. Authorizer: &gcp.WorkloadIdentity{},
  48. }
  49. func TestIntegrationController_pullWatchers(t *testing.T) {
  50. testCases := map[string]struct {
  51. initialStatuses []*Status
  52. configWatchers map[ConfigSource]cloudconfig.KeyedConfigWatcher
  53. expectedStatuses []*Status
  54. }{
  55. // Helm Source
  56. "Helm Source init": {
  57. initialStatuses: []*Status{},
  58. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  59. HelmSource: &MockKeyedConfigWatcher{
  60. Integrations: []cloudconfig.KeyedConfig{
  61. validAthenaConf,
  62. },
  63. },
  64. },
  65. expectedStatuses: []*Status{
  66. {
  67. Source: HelmSource,
  68. Key: validAthenaConf.Key(),
  69. Active: true,
  70. Valid: true,
  71. ConfigType: AthenaConfigType,
  72. Config: validAthenaConf,
  73. },
  74. },
  75. },
  76. "Helm Source No Change": {
  77. initialStatuses: []*Status{
  78. {
  79. Source: HelmSource,
  80. Key: validAthenaConf.Key(),
  81. Active: true,
  82. Valid: true,
  83. ConfigType: AthenaConfigType,
  84. Config: validAthenaConf,
  85. },
  86. },
  87. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  88. HelmSource: &MockKeyedConfigWatcher{
  89. Integrations: []cloudconfig.KeyedConfig{
  90. validAthenaConf,
  91. },
  92. },
  93. },
  94. expectedStatuses: []*Status{
  95. {
  96. Source: HelmSource,
  97. Key: validAthenaConf.Key(),
  98. Active: true,
  99. Valid: true,
  100. ConfigType: AthenaConfigType,
  101. Config: validAthenaConf,
  102. },
  103. },
  104. },
  105. "Helm Source Update Config": {
  106. initialStatuses: []*Status{
  107. {
  108. Source: HelmSource,
  109. Key: validAthenaConfModifiedProperty.Key(),
  110. Active: true,
  111. Valid: true,
  112. ConfigType: AthenaConfigType,
  113. Config: validAthenaConfModifiedProperty,
  114. },
  115. },
  116. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  117. HelmSource: &MockKeyedConfigWatcher{
  118. Integrations: []cloudconfig.KeyedConfig{
  119. validAthenaConf,
  120. },
  121. },
  122. },
  123. expectedStatuses: []*Status{
  124. {
  125. Source: HelmSource,
  126. Key: validAthenaConf.Key(),
  127. Active: true,
  128. Valid: true,
  129. ConfigType: AthenaConfigType,
  130. Config: validAthenaConf,
  131. },
  132. },
  133. },
  134. "Helm Source Update Config Invalid": {
  135. initialStatuses: []*Status{
  136. {
  137. Source: HelmSource,
  138. Key: validAthenaConf.Key(),
  139. Active: true,
  140. Valid: true,
  141. ConfigType: AthenaConfigType,
  142. Config: validAthenaConf,
  143. },
  144. },
  145. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  146. HelmSource: &MockKeyedConfigWatcher{
  147. Integrations: []cloudconfig.KeyedConfig{
  148. invalidAthenaConf,
  149. },
  150. },
  151. },
  152. expectedStatuses: []*Status{
  153. {
  154. Source: HelmSource,
  155. Key: invalidAthenaConf.Key(),
  156. Active: false,
  157. Valid: false,
  158. ConfigType: AthenaConfigType,
  159. Config: invalidAthenaConf,
  160. },
  161. },
  162. },
  163. "Helm Source New Config": {
  164. initialStatuses: []*Status{
  165. {
  166. Source: HelmSource,
  167. Key: validAthenaConf.Key(),
  168. Active: true,
  169. Valid: true,
  170. ConfigType: AthenaConfigType,
  171. Config: validAthenaConf,
  172. },
  173. },
  174. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  175. HelmSource: &MockKeyedConfigWatcher{
  176. Integrations: []cloudconfig.KeyedConfig{
  177. validBigQueryConf,
  178. },
  179. },
  180. },
  181. expectedStatuses: []*Status{
  182. {
  183. Source: HelmSource,
  184. Key: validBigQueryConf.Key(),
  185. Active: true,
  186. Valid: true,
  187. ConfigType: AthenaConfigType,
  188. Config: validBigQueryConf,
  189. },
  190. },
  191. },
  192. // Config File
  193. "Config File Source init": {
  194. initialStatuses: []*Status{},
  195. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  196. ConfigFileSource: &MockKeyedConfigWatcher{
  197. Integrations: []cloudconfig.KeyedConfig{
  198. validAthenaConf,
  199. },
  200. },
  201. },
  202. expectedStatuses: []*Status{
  203. {
  204. Source: ConfigFileSource,
  205. Key: validAthenaConf.Key(),
  206. Active: true,
  207. Valid: true,
  208. ConfigType: AthenaConfigType,
  209. Config: validAthenaConf,
  210. },
  211. },
  212. },
  213. "Config File No Change": {
  214. initialStatuses: []*Status{
  215. {
  216. Source: ConfigFileSource,
  217. Key: validAthenaConf.Key(),
  218. Active: true,
  219. Valid: true,
  220. ConfigType: AthenaConfigType,
  221. Config: validAthenaConf,
  222. },
  223. },
  224. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  225. ConfigFileSource: &MockKeyedConfigWatcher{
  226. Integrations: []cloudconfig.KeyedConfig{
  227. validAthenaConf,
  228. },
  229. },
  230. },
  231. expectedStatuses: []*Status{
  232. {
  233. Source: ConfigFileSource,
  234. Key: validAthenaConf.Key(),
  235. Active: true,
  236. Valid: true,
  237. ConfigType: AthenaConfigType,
  238. Config: validAthenaConf,
  239. },
  240. },
  241. },
  242. "Config File Update Config": {
  243. initialStatuses: []*Status{
  244. {
  245. Source: ConfigFileSource,
  246. Key: validAthenaConf.Key(),
  247. Active: true,
  248. Valid: true,
  249. ConfigType: AthenaConfigType,
  250. Config: validAthenaConf,
  251. },
  252. },
  253. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  254. ConfigFileSource: &MockKeyedConfigWatcher{
  255. Integrations: []cloudconfig.KeyedConfig{
  256. validAthenaConf,
  257. },
  258. },
  259. },
  260. expectedStatuses: []*Status{
  261. {
  262. Source: ConfigFileSource,
  263. Key: validAthenaConf.Key(),
  264. Active: true,
  265. Valid: true,
  266. ConfigType: AthenaConfigType,
  267. Config: validAthenaConf,
  268. },
  269. },
  270. },
  271. "Config File Update Config Invalid": {
  272. initialStatuses: []*Status{
  273. {
  274. Source: ConfigFileSource,
  275. Key: validAthenaConf.Key(),
  276. Active: true,
  277. Valid: true,
  278. ConfigType: AthenaConfigType,
  279. Config: validAthenaConf,
  280. },
  281. },
  282. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  283. ConfigFileSource: &MockKeyedConfigWatcher{
  284. Integrations: []cloudconfig.KeyedConfig{
  285. invalidAthenaConf,
  286. },
  287. },
  288. },
  289. expectedStatuses: []*Status{
  290. {
  291. Source: ConfigFileSource,
  292. Key: invalidAthenaConf.Key(),
  293. Active: false,
  294. Valid: false,
  295. ConfigType: AthenaConfigType,
  296. Config: invalidAthenaConf,
  297. },
  298. },
  299. },
  300. "Config File New Config": {
  301. initialStatuses: []*Status{
  302. {
  303. Source: ConfigFileSource,
  304. Key: validAthenaConf.Key(),
  305. Active: true,
  306. Valid: true,
  307. ConfigType: AthenaConfigType,
  308. Config: validAthenaConf,
  309. },
  310. },
  311. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  312. ConfigFileSource: &MockKeyedConfigWatcher{
  313. Integrations: []cloudconfig.KeyedConfig{
  314. validBigQueryConf,
  315. },
  316. },
  317. },
  318. expectedStatuses: []*Status{
  319. {
  320. Source: ConfigFileSource,
  321. Key: validBigQueryConf.Key(),
  322. Active: true,
  323. Valid: true,
  324. ConfigType: BigQueryConfigType,
  325. Config: validBigQueryConf,
  326. },
  327. },
  328. },
  329. // Multi Cloud
  330. "Multi Cloud Source init": {
  331. initialStatuses: []*Status{},
  332. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  333. MultiCloudSource: &MockKeyedConfigWatcher{
  334. Integrations: []cloudconfig.KeyedConfig{
  335. validAthenaConf,
  336. },
  337. },
  338. },
  339. expectedStatuses: []*Status{
  340. {
  341. Source: MultiCloudSource,
  342. Key: validAthenaConf.Key(),
  343. Active: true,
  344. Valid: true,
  345. ConfigType: AthenaConfigType,
  346. Config: validAthenaConf,
  347. },
  348. },
  349. },
  350. "Multi Cloud No Change": {
  351. initialStatuses: []*Status{
  352. {
  353. Source: MultiCloudSource,
  354. Key: validAthenaConf.Key(),
  355. Active: true,
  356. Valid: true,
  357. ConfigType: AthenaConfigType,
  358. Config: validAthenaConf,
  359. },
  360. },
  361. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  362. MultiCloudSource: &MockKeyedConfigWatcher{
  363. Integrations: []cloudconfig.KeyedConfig{
  364. validAthenaConf,
  365. },
  366. },
  367. },
  368. expectedStatuses: []*Status{
  369. {
  370. Source: MultiCloudSource,
  371. Key: validAthenaConf.Key(),
  372. Active: true,
  373. Valid: true,
  374. ConfigType: AthenaConfigType,
  375. Config: validAthenaConf,
  376. },
  377. },
  378. },
  379. "Multi Cloud Update Config": {
  380. initialStatuses: []*Status{
  381. {
  382. Source: MultiCloudSource,
  383. Key: validAthenaConf.Key(),
  384. Active: true,
  385. Valid: true,
  386. ConfigType: AthenaConfigType,
  387. Config: validAthenaConf,
  388. },
  389. },
  390. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  391. MultiCloudSource: &MockKeyedConfigWatcher{
  392. Integrations: []cloudconfig.KeyedConfig{
  393. validAthenaConfModifiedProperty,
  394. },
  395. },
  396. },
  397. expectedStatuses: []*Status{
  398. {
  399. Source: MultiCloudSource,
  400. Key: validAthenaConfModifiedProperty.Key(),
  401. Active: true,
  402. Valid: true,
  403. ConfigType: AthenaConfigType,
  404. Config: validAthenaConfModifiedProperty,
  405. },
  406. },
  407. },
  408. "Multi Cloud Update Config Invalid": {
  409. initialStatuses: []*Status{
  410. {
  411. Source: MultiCloudSource,
  412. Key: validAthenaConf.Key(),
  413. Active: true,
  414. Valid: true,
  415. ConfigType: AthenaConfigType,
  416. Config: validAthenaConf,
  417. },
  418. },
  419. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  420. MultiCloudSource: &MockKeyedConfigWatcher{
  421. Integrations: []cloudconfig.KeyedConfig{
  422. invalidAthenaConf,
  423. },
  424. },
  425. },
  426. expectedStatuses: []*Status{
  427. {
  428. Source: MultiCloudSource,
  429. Key: invalidAthenaConf.Key(),
  430. Active: false,
  431. Valid: false,
  432. ConfigType: AthenaConfigType,
  433. Config: invalidAthenaConf,
  434. },
  435. },
  436. },
  437. "Multi Cloud New Config": {
  438. initialStatuses: []*Status{
  439. {
  440. Source: MultiCloudSource,
  441. Key: validAthenaConf.Key(),
  442. Active: true,
  443. Valid: true,
  444. ConfigType: AthenaConfigType,
  445. Config: validAthenaConf,
  446. },
  447. },
  448. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  449. MultiCloudSource: &MockKeyedConfigWatcher{
  450. Integrations: []cloudconfig.KeyedConfig{
  451. validBigQueryConf,
  452. },
  453. },
  454. },
  455. expectedStatuses: []*Status{
  456. {
  457. Source: MultiCloudSource,
  458. Key: validBigQueryConf.Key(),
  459. Active: true,
  460. Valid: true,
  461. ConfigType: BigQueryConfigType,
  462. Config: validBigQueryConf,
  463. },
  464. },
  465. },
  466. "Multi Cloud Delete All": {
  467. initialStatuses: []*Status{
  468. {
  469. Source: MultiCloudSource,
  470. Key: validAthenaConf.Key(),
  471. Active: true,
  472. Valid: true,
  473. ConfigType: AthenaConfigType,
  474. Config: validAthenaConf,
  475. },
  476. },
  477. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  478. MultiCloudSource: &MockKeyedConfigWatcher{},
  479. },
  480. expectedStatuses: []*Status{},
  481. },
  482. // Watch Interaction
  483. "New Helm, Existing Config File": {
  484. initialStatuses: []*Status{
  485. {
  486. Source: ConfigFileSource,
  487. Key: validAthenaConf.Key(),
  488. Active: true,
  489. Valid: true,
  490. ConfigType: AthenaConfigType,
  491. Config: validAthenaConf,
  492. },
  493. },
  494. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  495. ConfigFileSource: &MockKeyedConfigWatcher{
  496. Integrations: []cloudconfig.KeyedConfig{
  497. validAthenaConf,
  498. },
  499. },
  500. HelmSource: &MockKeyedConfigWatcher{
  501. Integrations: []cloudconfig.KeyedConfig{
  502. validBigQueryConf,
  503. },
  504. },
  505. },
  506. expectedStatuses: []*Status{
  507. {
  508. Source: ConfigFileSource,
  509. Key: validAthenaConf.Key(),
  510. Active: false,
  511. Valid: true,
  512. ConfigType: AthenaConfigType,
  513. Config: validAthenaConf,
  514. },
  515. {
  516. Source: HelmSource,
  517. Key: validBigQueryConf.Key(),
  518. Active: true,
  519. Valid: true,
  520. ConfigType: BigQueryConfigType,
  521. Config: validBigQueryConf,
  522. },
  523. },
  524. },
  525. "Update Helm, Existing Config File": {
  526. initialStatuses: []*Status{
  527. {
  528. Source: HelmSource,
  529. Key: validAthenaConf.Key(),
  530. Active: false,
  531. Valid: true,
  532. ConfigType: AthenaConfigType,
  533. Config: validAthenaConf,
  534. },
  535. {
  536. Source: ConfigFileSource,
  537. Key: validBigQueryConf.Key(),
  538. Active: true,
  539. Valid: true,
  540. ConfigType: BigQueryConfigType,
  541. Config: validBigQueryConf,
  542. },
  543. },
  544. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  545. ConfigFileSource: &MockKeyedConfigWatcher{
  546. Integrations: []cloudconfig.KeyedConfig{
  547. validBigQueryConf,
  548. },
  549. },
  550. HelmSource: &MockKeyedConfigWatcher{
  551. Integrations: []cloudconfig.KeyedConfig{
  552. validAthenaConfModifiedProperty,
  553. },
  554. },
  555. },
  556. expectedStatuses: []*Status{
  557. {
  558. Source: HelmSource,
  559. Key: validAthenaConfModifiedProperty.Key(),
  560. Active: true,
  561. Valid: true,
  562. ConfigType: AthenaConfigType,
  563. Config: validAthenaConfModifiedProperty,
  564. },
  565. {
  566. Source: ConfigFileSource,
  567. Key: validBigQueryConf.Key(),
  568. Active: false,
  569. Valid: true,
  570. ConfigType: BigQueryConfigType,
  571. Config: validBigQueryConf,
  572. },
  573. },
  574. },
  575. "New Helm Invalid, Existing Config File": {
  576. initialStatuses: []*Status{
  577. {
  578. Source: ConfigFileSource,
  579. Key: validBigQueryConf.Key(),
  580. Active: true,
  581. Valid: true,
  582. ConfigType: BigQueryConfigType,
  583. Config: validBigQueryConf,
  584. },
  585. },
  586. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  587. ConfigFileSource: &MockKeyedConfigWatcher{
  588. Integrations: []cloudconfig.KeyedConfig{
  589. validBigQueryConf,
  590. },
  591. },
  592. HelmSource: &MockKeyedConfigWatcher{
  593. Integrations: []cloudconfig.KeyedConfig{
  594. invalidAthenaConf,
  595. },
  596. },
  597. },
  598. expectedStatuses: []*Status{
  599. {
  600. Source: ConfigFileSource,
  601. Key: validBigQueryConf.Key(),
  602. Active: true,
  603. Valid: true,
  604. ConfigType: BigQueryConfigType,
  605. Config: validBigQueryConf,
  606. },
  607. {
  608. Source: HelmSource,
  609. Key: invalidAthenaConf.Key(),
  610. Active: false,
  611. Valid: false,
  612. ConfigType: AthenaConfigType,
  613. Config: invalidAthenaConf,
  614. },
  615. },
  616. },
  617. "Update Helm Invalid, Existing Config File": {
  618. initialStatuses: []*Status{
  619. {
  620. Source: ConfigFileSource,
  621. Key: validBigQueryConf.Key(),
  622. Active: true,
  623. Valid: true,
  624. ConfigType: BigQueryConfigType,
  625. Config: validBigQueryConf,
  626. },
  627. {
  628. Source: HelmSource,
  629. Key: validAthenaConf.Key(),
  630. Active: false,
  631. Valid: true,
  632. ConfigType: AthenaConfigType,
  633. Config: validAthenaConf,
  634. },
  635. },
  636. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  637. ConfigFileSource: &MockKeyedConfigWatcher{
  638. Integrations: []cloudconfig.KeyedConfig{
  639. validBigQueryConf,
  640. },
  641. },
  642. HelmSource: &MockKeyedConfigWatcher{
  643. Integrations: []cloudconfig.KeyedConfig{
  644. invalidAthenaConf,
  645. },
  646. },
  647. },
  648. expectedStatuses: []*Status{
  649. {
  650. Source: ConfigFileSource,
  651. Key: validBigQueryConf.Key(),
  652. Active: true,
  653. Valid: true,
  654. ConfigType: BigQueryConfigType,
  655. Config: validBigQueryConf,
  656. },
  657. {
  658. Source: HelmSource,
  659. Key: invalidAthenaConf.Key(),
  660. Active: false,
  661. Valid: false,
  662. ConfigType: AthenaConfigType,
  663. Config: invalidAthenaConf,
  664. },
  665. },
  666. },
  667. "New Config File, Existing Helm": {
  668. initialStatuses: []*Status{
  669. {
  670. Source: HelmSource,
  671. Key: validAthenaConf.Key(),
  672. Active: true,
  673. Valid: true,
  674. ConfigType: AthenaConfigType,
  675. Config: validAthenaConf,
  676. },
  677. },
  678. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  679. HelmSource: &MockKeyedConfigWatcher{
  680. Integrations: []cloudconfig.KeyedConfig{
  681. validAthenaConf,
  682. },
  683. },
  684. ConfigFileSource: &MockKeyedConfigWatcher{
  685. Integrations: []cloudconfig.KeyedConfig{
  686. validBigQueryConf,
  687. },
  688. },
  689. },
  690. expectedStatuses: []*Status{
  691. {
  692. Source: HelmSource,
  693. Key: validAthenaConf.Key(),
  694. Active: false,
  695. Valid: true,
  696. ConfigType: AthenaConfigType,
  697. Config: validAthenaConf,
  698. },
  699. {
  700. Source: ConfigFileSource,
  701. Key: validBigQueryConf.Key(),
  702. Active: true,
  703. Valid: true,
  704. ConfigType: BigQueryConfigType,
  705. Config: validBigQueryConf,
  706. },
  707. },
  708. },
  709. "Update Config File, Existing Helm": {
  710. initialStatuses: []*Status{
  711. {
  712. Source: HelmSource,
  713. Key: validBigQueryConf.Key(),
  714. Active: true,
  715. Valid: true,
  716. ConfigType: BigQueryConfigType,
  717. Config: validBigQueryConf,
  718. },
  719. },
  720. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  721. HelmSource: &MockKeyedConfigWatcher{
  722. Integrations: []cloudconfig.KeyedConfig{},
  723. },
  724. ConfigFileSource: &MockKeyedConfigWatcher{
  725. Integrations: []cloudconfig.KeyedConfig{
  726. validAthenaConfModifiedProperty,
  727. },
  728. },
  729. },
  730. expectedStatuses: []*Status{
  731. {
  732. Source: ConfigFileSource,
  733. Key: validAthenaConfModifiedProperty.Key(),
  734. Active: true,
  735. Valid: true,
  736. ConfigType: AthenaConfigType,
  737. Config: validAthenaConfModifiedProperty,
  738. },
  739. },
  740. },
  741. "New Config File Invalid, Existing Helm": {
  742. initialStatuses: []*Status{
  743. {
  744. Source: HelmSource,
  745. Key: validBigQueryConf.Key(),
  746. Active: true,
  747. Valid: true,
  748. ConfigType: BigQueryConfigType,
  749. Config: validBigQueryConf,
  750. },
  751. },
  752. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  753. HelmSource: &MockKeyedConfigWatcher{
  754. Integrations: []cloudconfig.KeyedConfig{
  755. validBigQueryConf,
  756. },
  757. },
  758. ConfigFileSource: &MockKeyedConfigWatcher{
  759. Integrations: []cloudconfig.KeyedConfig{
  760. invalidAthenaConf,
  761. },
  762. },
  763. },
  764. expectedStatuses: []*Status{
  765. {
  766. Source: HelmSource,
  767. Key: validBigQueryConf.Key(),
  768. Active: true,
  769. Valid: true,
  770. ConfigType: BigQueryConfigType,
  771. Config: validBigQueryConf,
  772. },
  773. {
  774. Source: ConfigFileSource,
  775. Key: invalidAthenaConf.Key(),
  776. Active: false,
  777. Valid: false,
  778. ConfigType: AthenaConfigType,
  779. Config: invalidAthenaConf,
  780. },
  781. },
  782. },
  783. "Update Config File Invalid, Existing Helm": {
  784. initialStatuses: []*Status{
  785. {
  786. Source: HelmSource,
  787. Key: validBigQueryConf.Key(),
  788. Active: true,
  789. Valid: true,
  790. ConfigType: BigQueryConfigType,
  791. Config: validBigQueryConf,
  792. },
  793. {
  794. Source: ConfigFileSource,
  795. Key: validAthenaConf.Key(),
  796. Active: false,
  797. Valid: true,
  798. ConfigType: AthenaConfigType,
  799. Config: validAthenaConf,
  800. },
  801. },
  802. configWatchers: map[ConfigSource]cloudconfig.KeyedConfigWatcher{
  803. HelmSource: &MockKeyedConfigWatcher{
  804. Integrations: []cloudconfig.KeyedConfig{
  805. validBigQueryConf,
  806. },
  807. },
  808. ConfigFileSource: &MockKeyedConfigWatcher{
  809. Integrations: []cloudconfig.KeyedConfig{
  810. invalidAthenaConf,
  811. },
  812. },
  813. },
  814. expectedStatuses: []*Status{
  815. {
  816. Source: HelmSource,
  817. Key: validBigQueryConf.Key(),
  818. Active: true,
  819. Valid: true,
  820. ConfigType: BigQueryConfigType,
  821. Config: validBigQueryConf,
  822. },
  823. {
  824. Source: ConfigFileSource,
  825. Key: invalidAthenaConf.Key(),
  826. Active: false,
  827. Valid: false,
  828. ConfigType: AthenaConfigType,
  829. Config: invalidAthenaConf,
  830. },
  831. },
  832. },
  833. }
  834. for name, tc := range testCases {
  835. t.Run(name, func(t *testing.T) {
  836. // Test set up and validation
  837. initialStatuses, err := buildStatuses(tc.initialStatuses)
  838. if err != nil {
  839. t.Errorf("initial statuses: %s", err.Error())
  840. }
  841. expectedStatuses, err := buildStatuses(tc.expectedStatuses)
  842. if err != nil {
  843. t.Errorf("initial statuses: %s", err.Error())
  844. }
  845. tempDir := os.TempDir()
  846. path := filepath.Join(tempDir, configFile)
  847. defer os.Remove(path)
  848. storage := &FileControllerStorage{
  849. path: path,
  850. }
  851. // Initialize controller
  852. icd := &Controller{
  853. storage: storage,
  854. watchers: tc.configWatchers,
  855. }
  856. err = icd.storage.save(initialStatuses)
  857. if err != nil {
  858. t.Errorf("failed to save initial statuses: %s", err.Error())
  859. }
  860. // Functionality being tested
  861. icd.pullWatchers()
  862. // Test Result
  863. status, err := icd.storage.load()
  864. if err != nil {
  865. t.Errorf("failed to load status file: %s", err.Error())
  866. }
  867. err = checkStatuses(status, expectedStatuses)
  868. if err != nil {
  869. t.Errorf("statuses equality check failed: %s", err.Error())
  870. }
  871. })
  872. }
  873. }
  874. func TestIntegrationController_CreateConfig(t *testing.T) {
  875. testCases := map[string]struct {
  876. initial []*Status
  877. expected []*Status
  878. input cloudconfig.KeyedConfig
  879. expectErr bool
  880. }{
  881. "Invalid Config": {
  882. initial: nil,
  883. expected: nil,
  884. input: invalidAthenaConf,
  885. expectErr: true,
  886. },
  887. "config exists from this source": {
  888. initial: []*Status{
  889. makeStatus(validAthenaConf, true, ConfigControllerSource),
  890. },
  891. expected: []*Status{
  892. makeStatus(validAthenaConf, true, ConfigControllerSource),
  893. },
  894. input: validAthenaConf,
  895. expectErr: true,
  896. },
  897. "config exists from this source altered": {
  898. initial: []*Status{
  899. makeStatus(validAthenaConf, true, ConfigControllerSource),
  900. },
  901. expected: []*Status{
  902. makeStatus(validAthenaConf, true, ConfigControllerSource),
  903. },
  904. input: validAthenaConfModifiedProperty,
  905. expectErr: true,
  906. },
  907. "config exists from other source enabled": {
  908. initial: []*Status{
  909. makeStatus(validAthenaConf, true, MultiCloudSource),
  910. },
  911. expected: []*Status{
  912. makeStatus(validAthenaConf, false, MultiCloudSource),
  913. makeStatus(validAthenaConf, true, ConfigControllerSource),
  914. },
  915. input: validAthenaConf,
  916. expectErr: false,
  917. },
  918. "config exists from other source disabled": {
  919. initial: []*Status{
  920. makeStatus(validAthenaConf, false, MultiCloudSource),
  921. },
  922. expected: []*Status{
  923. makeStatus(validAthenaConf, false, MultiCloudSource),
  924. makeStatus(validAthenaConf, true, ConfigControllerSource),
  925. },
  926. input: validAthenaConf,
  927. expectErr: false,
  928. },
  929. "config into empty": {
  930. initial: []*Status{},
  931. expected: []*Status{
  932. makeStatus(validAthenaConf, true, ConfigControllerSource),
  933. },
  934. input: validAthenaConf,
  935. expectErr: false,
  936. },
  937. }
  938. for name, tc := range testCases {
  939. t.Run(name, func(t *testing.T) {
  940. // Test set up and validation
  941. initialStatuses, err := buildStatuses(tc.initial)
  942. if err != nil {
  943. t.Errorf("initial statuses: %s", err.Error())
  944. }
  945. expectedStatuses, err := buildStatuses(tc.expected)
  946. if err != nil {
  947. t.Errorf("initial statuses: %s", err.Error())
  948. }
  949. tempDir := os.TempDir()
  950. path := filepath.Join(tempDir, configFile)
  951. defer os.Remove(path)
  952. storage := &FileControllerStorage{
  953. path: path,
  954. }
  955. // Initialize controller
  956. icd := &Controller{
  957. storage: storage,
  958. }
  959. err = icd.storage.save(initialStatuses)
  960. if err != nil {
  961. t.Errorf("failed to save initial statuses: %s", err.Error())
  962. }
  963. // Functionality being tested
  964. err = icd.CreateConfig(tc.input)
  965. // Test Result
  966. if err != nil && !tc.expectErr {
  967. t.Errorf("unexpected error when creating config: %s", err.Error())
  968. }
  969. if err == nil && tc.expectErr {
  970. t.Errorf("no error where expect")
  971. }
  972. status, err := icd.storage.load()
  973. if err != nil {
  974. t.Errorf("failed to load status file: %s", err.Error())
  975. }
  976. err = checkStatuses(status, expectedStatuses)
  977. if err != nil {
  978. t.Errorf("statuses equality check failed: %s", err.Error())
  979. }
  980. })
  981. }
  982. }
  983. func TestIntegrationController_UpdateConfig(t *testing.T) {
  984. testCases := map[string]struct {
  985. initial []*Status
  986. expected []*Status
  987. input cloudconfig.KeyedConfig
  988. expectErr bool
  989. }{
  990. "invalid config": {
  991. initial: []*Status{
  992. makeStatus(validAthenaConf, true, ConfigControllerSource),
  993. },
  994. expected: []*Status{
  995. makeStatus(validAthenaConf, true, ConfigControllerSource),
  996. },
  997. input: invalidAthenaConf,
  998. expectErr: true,
  999. },
  1000. "config is not from ConfigControllerSource": {
  1001. initial: []*Status{
  1002. makeStatus(validAthenaConf, true, MultiCloudSource),
  1003. },
  1004. expected: []*Status{
  1005. makeStatus(validAthenaConf, true, MultiCloudSource),
  1006. },
  1007. input: validAthenaConf,
  1008. expectErr: true,
  1009. },
  1010. "config does not exist": {
  1011. initial: []*Status{},
  1012. expected: []*Status{},
  1013. input: validAthenaConf,
  1014. expectErr: true,
  1015. },
  1016. "update existing config with modified properties": {
  1017. initial: []*Status{
  1018. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1019. },
  1020. expected: []*Status{
  1021. makeStatus(validAthenaConfModifiedProperty, true, ConfigControllerSource),
  1022. },
  1023. input: validAthenaConfModifiedProperty,
  1024. expectErr: false,
  1025. },
  1026. "update existing config with same properties": {
  1027. initial: []*Status{
  1028. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1029. },
  1030. expected: []*Status{
  1031. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1032. },
  1033. input: validAthenaConf,
  1034. expectErr: false,
  1035. },
  1036. "update existing config when other source has same key": {
  1037. initial: []*Status{
  1038. makeStatus(validAthenaConf, false, MultiCloudSource),
  1039. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1040. },
  1041. expected: []*Status{
  1042. makeStatus(validAthenaConf, false, MultiCloudSource),
  1043. makeStatus(validAthenaConfModifiedProperty, true, ConfigControllerSource),
  1044. },
  1045. input: validAthenaConfModifiedProperty,
  1046. expectErr: false,
  1047. },
  1048. "update existing config when multiple other configs exist": {
  1049. initial: []*Status{
  1050. makeStatus(validBigQueryConf, true, MultiCloudSource),
  1051. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1052. },
  1053. expected: []*Status{
  1054. makeStatus(validBigQueryConf, true, MultiCloudSource),
  1055. makeStatus(validAthenaConfModifiedProperty, true, ConfigControllerSource),
  1056. },
  1057. input: validAthenaConfModifiedProperty,
  1058. expectErr: false,
  1059. },
  1060. }
  1061. for name, tc := range testCases {
  1062. t.Run(name, func(t *testing.T) {
  1063. // Test set up and validation
  1064. initialStatuses, err := buildStatuses(tc.initial)
  1065. if err != nil {
  1066. t.Errorf("initial statuses: %s", err.Error())
  1067. }
  1068. expectedStatuses, err := buildStatuses(tc.expected)
  1069. if err != nil {
  1070. t.Errorf("expected statuses: %s", err.Error())
  1071. }
  1072. tempDir := os.TempDir()
  1073. path := filepath.Join(tempDir, configFile)
  1074. defer os.Remove(path)
  1075. storage := &FileControllerStorage{
  1076. path: path,
  1077. }
  1078. // Initialize controller
  1079. icd := &Controller{
  1080. storage: storage,
  1081. }
  1082. err = icd.storage.save(initialStatuses)
  1083. if err != nil {
  1084. t.Errorf("failed to save initial statuses: %s", err.Error())
  1085. }
  1086. // Functionality being tested
  1087. err = icd.UpdateConfig(tc.input)
  1088. // Test Result
  1089. if err != nil && !tc.expectErr {
  1090. t.Errorf("unexpected error when updating config: %s", err.Error())
  1091. }
  1092. if err == nil && tc.expectErr {
  1093. t.Errorf("no error where expected")
  1094. }
  1095. status, err := icd.storage.load()
  1096. if err != nil {
  1097. t.Errorf("failed to load status file: %s", err.Error())
  1098. }
  1099. err = checkStatuses(status, expectedStatuses)
  1100. if err != nil {
  1101. t.Errorf("statuses equality check failed: %s", err.Error())
  1102. }
  1103. })
  1104. }
  1105. }
  1106. func TestIntegrationController_EnableConfig(t *testing.T) {
  1107. testCases := map[string]struct {
  1108. initial []*Status
  1109. expected []*Status
  1110. inputKey string
  1111. inputSource string
  1112. expectErr bool
  1113. }{
  1114. "config doesn't exist": {
  1115. initial: []*Status{},
  1116. expected: []*Status{},
  1117. inputKey: validAthenaConf.Key(),
  1118. inputSource: ConfigControllerSource.String(),
  1119. expectErr: true,
  1120. },
  1121. "config is already enabled": {
  1122. initial: []*Status{
  1123. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1124. },
  1125. expected: []*Status{
  1126. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1127. },
  1128. inputKey: validAthenaConf.Key(),
  1129. inputSource: ConfigControllerSource.String(),
  1130. expectErr: true,
  1131. },
  1132. "alternate source": {
  1133. initial: []*Status{
  1134. makeStatus(validAthenaConf, false, MultiCloudSource),
  1135. },
  1136. expected: []*Status{
  1137. makeStatus(validAthenaConf, true, MultiCloudSource),
  1138. },
  1139. inputKey: validAthenaConf.Key(),
  1140. inputSource: MultiCloudSource.String(),
  1141. expectErr: false,
  1142. },
  1143. "enabled disabled single config": {
  1144. initial: []*Status{
  1145. makeStatus(validAthenaConf, false, ConfigControllerSource),
  1146. },
  1147. expected: []*Status{
  1148. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1149. },
  1150. inputKey: validAthenaConf.Key(),
  1151. inputSource: ConfigControllerSource.String(),
  1152. expectErr: false,
  1153. },
  1154. "enable config which is enabled by another source": {
  1155. initial: []*Status{
  1156. makeStatus(validAthenaConf, false, ConfigControllerSource),
  1157. makeStatus(validAthenaConf, true, MultiCloudSource),
  1158. },
  1159. expected: []*Status{
  1160. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1161. makeStatus(validAthenaConf, false, MultiCloudSource),
  1162. },
  1163. inputKey: validAthenaConf.Key(),
  1164. inputSource: ConfigControllerSource.String(),
  1165. expectErr: false,
  1166. },
  1167. }
  1168. for name, tc := range testCases {
  1169. t.Run(name, func(t *testing.T) {
  1170. // Test set up and validation
  1171. initialStatuses, err := buildStatuses(tc.initial)
  1172. if err != nil {
  1173. t.Errorf("initial statuses: %s", err.Error())
  1174. }
  1175. expectedStatuses, err := buildStatuses(tc.expected)
  1176. if err != nil {
  1177. t.Errorf("initial statuses: %s", err.Error())
  1178. }
  1179. tempDir := os.TempDir()
  1180. path := filepath.Join(tempDir, configFile)
  1181. defer os.Remove(path)
  1182. storage := &FileControllerStorage{
  1183. path: path,
  1184. }
  1185. // Initialize controller
  1186. icd := &Controller{
  1187. storage: storage,
  1188. }
  1189. err = icd.storage.save(initialStatuses)
  1190. if err != nil {
  1191. t.Errorf("failed to save initial statuses: %s", err.Error())
  1192. }
  1193. // Functionality being tested
  1194. err = icd.EnableConfig(tc.inputKey, tc.inputSource)
  1195. // Test Result
  1196. if err != nil && !tc.expectErr {
  1197. t.Errorf("unexpected error when enabling config: %s", err.Error())
  1198. }
  1199. if err == nil && tc.expectErr {
  1200. t.Errorf("no error where expect")
  1201. }
  1202. status, err := icd.storage.load()
  1203. if err != nil {
  1204. t.Errorf("failed to load status file: %s", err.Error())
  1205. }
  1206. err = checkStatuses(status, expectedStatuses)
  1207. if err != nil {
  1208. t.Errorf("statuses equality check failed: %s", err.Error())
  1209. }
  1210. })
  1211. }
  1212. }
  1213. func TestIntegrationController_DisableConfig(t *testing.T) {
  1214. testCases := map[string]struct {
  1215. initial []*Status
  1216. expected []*Status
  1217. inputKey string
  1218. inputSource string
  1219. expectErr bool
  1220. }{
  1221. "config doesn't exist": {
  1222. initial: []*Status{},
  1223. expected: []*Status{},
  1224. inputKey: validAthenaConf.Key(),
  1225. inputSource: ConfigControllerSource.String(),
  1226. expectErr: true,
  1227. },
  1228. "config is already disabled": {
  1229. initial: []*Status{
  1230. makeStatus(validAthenaConf, false, ConfigControllerSource),
  1231. makeStatus(validAthenaConf, true, MultiCloudSource),
  1232. },
  1233. expected: []*Status{
  1234. makeStatus(validAthenaConf, false, ConfigControllerSource),
  1235. makeStatus(validAthenaConf, true, MultiCloudSource),
  1236. },
  1237. inputKey: validAthenaConf.Key(),
  1238. inputSource: ConfigControllerSource.String(),
  1239. expectErr: true,
  1240. },
  1241. "disable single config": {
  1242. initial: []*Status{
  1243. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1244. },
  1245. expected: []*Status{
  1246. makeStatus(validAthenaConf, false, ConfigControllerSource),
  1247. },
  1248. inputKey: validAthenaConf.Key(),
  1249. inputSource: ConfigControllerSource.String(),
  1250. expectErr: false,
  1251. },
  1252. "alternate source": {
  1253. initial: []*Status{
  1254. makeStatus(validAthenaConf, true, MultiCloudSource),
  1255. },
  1256. expected: []*Status{
  1257. makeStatus(validAthenaConf, false, MultiCloudSource),
  1258. },
  1259. inputKey: validAthenaConf.Key(),
  1260. inputSource: MultiCloudSource.String(),
  1261. expectErr: false,
  1262. },
  1263. "disable config, matching config from separate source": {
  1264. initial: []*Status{
  1265. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1266. makeStatus(validAthenaConf, false, MultiCloudSource),
  1267. },
  1268. expected: []*Status{
  1269. makeStatus(validAthenaConf, false, ConfigControllerSource),
  1270. makeStatus(validAthenaConf, false, MultiCloudSource),
  1271. },
  1272. inputKey: validAthenaConf.Key(),
  1273. inputSource: ConfigControllerSource.String(),
  1274. expectErr: false,
  1275. },
  1276. }
  1277. for name, tc := range testCases {
  1278. t.Run(name, func(t *testing.T) {
  1279. // Test set up and validation
  1280. initialStatuses, err := buildStatuses(tc.initial)
  1281. if err != nil {
  1282. t.Errorf("initial statuses: %s", err.Error())
  1283. }
  1284. expectedStatuses, err := buildStatuses(tc.expected)
  1285. if err != nil {
  1286. t.Errorf("initial statuses: %s", err.Error())
  1287. }
  1288. tempDir := os.TempDir()
  1289. path := filepath.Join(tempDir, configFile)
  1290. defer os.Remove(path)
  1291. storage := &FileControllerStorage{
  1292. path: path,
  1293. }
  1294. // Initialize controller
  1295. icd := &Controller{
  1296. storage: storage,
  1297. }
  1298. err = icd.storage.save(initialStatuses)
  1299. if err != nil {
  1300. t.Errorf("failed to save initial statuses: %s", err.Error())
  1301. }
  1302. // Functionality being tested
  1303. err = icd.DisableConfig(tc.inputKey, tc.inputSource)
  1304. // Test Result
  1305. if err != nil && !tc.expectErr {
  1306. t.Errorf("unexpected error when disabling config: %s", err.Error())
  1307. }
  1308. if err == nil && tc.expectErr {
  1309. t.Errorf("no error where expect")
  1310. }
  1311. status, err := icd.storage.load()
  1312. if err != nil {
  1313. t.Errorf("failed to load status file: %s", err.Error())
  1314. }
  1315. err = checkStatuses(status, expectedStatuses)
  1316. if err != nil {
  1317. t.Errorf("statuses equality check failed: %s", err.Error())
  1318. }
  1319. })
  1320. }
  1321. }
  1322. func TestIntegrationController_DeleteConfig(t *testing.T) {
  1323. testCases := map[string]struct {
  1324. initial []*Status
  1325. expected []*Status
  1326. inputKey string
  1327. inputSource string
  1328. expectErr bool
  1329. }{
  1330. "config doesn't exist": {
  1331. initial: []*Status{},
  1332. expected: []*Status{},
  1333. inputKey: validAthenaConf.Key(),
  1334. inputSource: ConfigControllerSource.String(),
  1335. expectErr: true,
  1336. },
  1337. "invalid source": {
  1338. initial: []*Status{},
  1339. expected: []*Status{},
  1340. inputKey: validAthenaConf.Key(),
  1341. inputSource: MultiCloudSource.String(),
  1342. expectErr: true,
  1343. },
  1344. "delete single config": {
  1345. initial: []*Status{
  1346. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1347. },
  1348. expected: []*Status{},
  1349. inputKey: validAthenaConf.Key(),
  1350. inputSource: ConfigControllerSource.String(),
  1351. expectErr: false,
  1352. },
  1353. "disable config, matching config from separate source": {
  1354. initial: []*Status{
  1355. makeStatus(validAthenaConf, true, ConfigControllerSource),
  1356. makeStatus(validAthenaConf, false, MultiCloudSource),
  1357. },
  1358. expected: []*Status{
  1359. makeStatus(validAthenaConf, false, MultiCloudSource),
  1360. },
  1361. inputKey: validAthenaConf.Key(),
  1362. inputSource: ConfigControllerSource.String(),
  1363. expectErr: false,
  1364. },
  1365. }
  1366. for name, tc := range testCases {
  1367. t.Run(name, func(t *testing.T) {
  1368. // Test set up and validation
  1369. initialStatuses, err := buildStatuses(tc.initial)
  1370. if err != nil {
  1371. t.Errorf("initial statuses: %s", err.Error())
  1372. }
  1373. expectedStatuses, err := buildStatuses(tc.expected)
  1374. if err != nil {
  1375. t.Errorf("initial statuses: %s", err.Error())
  1376. }
  1377. tempDir := os.TempDir()
  1378. path := filepath.Join(tempDir, configFile)
  1379. defer os.Remove(path)
  1380. storage := &FileControllerStorage{
  1381. path: path,
  1382. }
  1383. // Initialize controller
  1384. icd := &Controller{
  1385. storage: storage,
  1386. }
  1387. err = icd.storage.save(initialStatuses)
  1388. if err != nil {
  1389. t.Errorf("failed to save initial statuses: %s", err.Error())
  1390. }
  1391. // Functionality being tested
  1392. err = icd.DeleteConfig(tc.inputKey, tc.inputSource)
  1393. // Test Result
  1394. if err != nil && !tc.expectErr {
  1395. t.Errorf("unexpected error when deleting config: %s", err.Error())
  1396. }
  1397. if err == nil && tc.expectErr {
  1398. t.Errorf("no error where expect")
  1399. }
  1400. status, err := icd.storage.load()
  1401. if err != nil {
  1402. t.Errorf("failed to load status file: %s", err.Error())
  1403. }
  1404. err = checkStatuses(status, expectedStatuses)
  1405. if err != nil {
  1406. t.Errorf("statuses equality check failed: %s", err.Error())
  1407. }
  1408. })
  1409. }
  1410. }
  1411. func makeStatus(config cloudconfig.KeyedConfig, active bool, source ConfigSource) *Status {
  1412. err := config.Validate()
  1413. valid := err == nil
  1414. configType, err := ConfigTypeFromConfig(config)
  1415. if err != nil {
  1416. panic(fmt.Errorf("config type not recognised: %w", err))
  1417. }
  1418. return &Status{
  1419. Source: source,
  1420. Key: config.Key(),
  1421. Active: active,
  1422. Valid: valid,
  1423. ConfigType: configType,
  1424. Config: config,
  1425. }
  1426. }
  1427. func buildStatuses(statusList []*Status) (Statuses, error) {
  1428. statuses := Statuses{}
  1429. for _, status := range statusList {
  1430. if _, ok := statuses.Get(status.Key, status.Source); ok {
  1431. return nil, fmt.Errorf("invalid test, duplicate status with key: %s source: %s", status.Key, status.Source.String())
  1432. }
  1433. statuses.Insert(status)
  1434. }
  1435. return statuses, nil
  1436. }
  1437. func checkStatuses(actual, expected Statuses) error {
  1438. if len(actual.List()) != len(expected.List()) {
  1439. return fmt.Errorf("integration statueses did not have the correct length actaul: %d, expected: %d", len(actual.List()), len(expected.List()))
  1440. }
  1441. for _, actualStatus := range actual.List() {
  1442. expectedStatus, ok := expected.Get(actualStatus.Key, actualStatus.Source)
  1443. if !ok {
  1444. return fmt.Errorf("expected integration statuses is missing with integration key: %s, source: %s", actualStatus.Key, actualStatus.Source.String())
  1445. }
  1446. // failure here indicates an issue with the configID
  1447. if actualStatus.Key != expectedStatus.Key {
  1448. return fmt.Errorf("integration status does not have the correct Key values actual: %s, expected: %s", actualStatus.Key, expectedStatus.Key)
  1449. }
  1450. // failure here indicates an issue with the configID
  1451. if actualStatus.Key != expectedStatus.Key {
  1452. return fmt.Errorf("integration status does not have the correct Source values actual: %s, expected: %s", actualStatus.Source, expectedStatus.Source)
  1453. }
  1454. if actualStatus.Active != expectedStatus.Active {
  1455. return fmt.Errorf("integration status does not have the correct Active values actual: %v, expected: %v", actualStatus.Active, expectedStatus.Active)
  1456. }
  1457. if actualStatus.Valid != expectedStatus.Valid {
  1458. return fmt.Errorf("integration status does not have the correct Valid values actual: %v, expected: %v", actualStatus.Valid, expectedStatus.Valid)
  1459. }
  1460. if !actualStatus.Config.Equals(expectedStatus.Config) {
  1461. return fmt.Errorf("integration status does not have the correct config values actual: %v, expected: %v", actualStatus.Config, expectedStatus.Config)
  1462. }
  1463. }
  1464. return nil
  1465. }