controller_test.go 36 KB

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