athenaconfiguration_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. package aws
  2. import (
  3. "fmt"
  4. "testing"
  5. "github.com/opencost/opencost/core/pkg/log"
  6. "github.com/opencost/opencost/core/pkg/util/json"
  7. "github.com/opencost/opencost/pkg/cloud"
  8. )
  9. func TestAthenaConfiguration_Validate(t *testing.T) {
  10. testCases := map[string]struct {
  11. config AthenaConfiguration
  12. expected error
  13. }{
  14. "valid config access key": {
  15. config: AthenaConfiguration{
  16. Bucket: "bucket",
  17. Region: "region",
  18. Database: "database",
  19. Catalog: "catalog",
  20. Table: "table",
  21. Workgroup: "workgroup",
  22. Account: "account",
  23. Authorizer: &AccessKey{
  24. ID: "id",
  25. Secret: "secret",
  26. },
  27. },
  28. expected: nil,
  29. },
  30. "valid config service account": {
  31. config: AthenaConfiguration{
  32. Bucket: "bucket",
  33. Region: "region",
  34. Database: "database",
  35. Catalog: "catalog",
  36. Table: "table",
  37. Workgroup: "workgroup",
  38. Account: "account",
  39. Authorizer: &ServiceAccount{},
  40. },
  41. expected: nil,
  42. },
  43. "valid missing catalog": {
  44. config: AthenaConfiguration{
  45. Bucket: "bucket",
  46. Region: "region",
  47. Database: "database",
  48. Table: "table",
  49. Workgroup: "workgroup",
  50. Account: "account",
  51. Authorizer: &ServiceAccount{},
  52. },
  53. expected: nil,
  54. },
  55. "access key invalid": {
  56. config: AthenaConfiguration{
  57. Bucket: "bucket",
  58. Region: "region",
  59. Database: "database",
  60. Catalog: "catalog",
  61. Table: "table",
  62. Workgroup: "workgroup",
  63. Account: "account",
  64. Authorizer: &AccessKey{
  65. ID: "id",
  66. },
  67. },
  68. expected: fmt.Errorf("AthenaConfiguration: AccessKey: missing Secret"),
  69. },
  70. "missing Authorizer": {
  71. config: AthenaConfiguration{
  72. Bucket: "bucket",
  73. Region: "region",
  74. Database: "database",
  75. Catalog: "catalog",
  76. Table: "table",
  77. Workgroup: "workgroup",
  78. Account: "account",
  79. Authorizer: nil,
  80. },
  81. expected: fmt.Errorf("AthenaConfiguration: missing Authorizer"),
  82. },
  83. "missing bucket": {
  84. config: AthenaConfiguration{
  85. Bucket: "",
  86. Region: "region",
  87. Database: "database",
  88. Catalog: "catalog",
  89. Table: "table",
  90. Workgroup: "workgroup",
  91. Account: "account",
  92. Authorizer: &ServiceAccount{},
  93. },
  94. expected: fmt.Errorf("AthenaConfiguration: missing bucket"),
  95. },
  96. "missing region": {
  97. config: AthenaConfiguration{
  98. Bucket: "bucket",
  99. Region: "",
  100. Database: "database",
  101. Catalog: "catalog",
  102. Table: "table",
  103. Workgroup: "workgroup",
  104. Account: "account",
  105. Authorizer: &ServiceAccount{},
  106. },
  107. expected: fmt.Errorf("AthenaConfiguration: missing region"),
  108. },
  109. "missing database": {
  110. config: AthenaConfiguration{
  111. Bucket: "bucket",
  112. Region: "region",
  113. Database: "",
  114. Catalog: "catalog",
  115. Table: "table",
  116. Workgroup: "workgroup",
  117. Account: "account",
  118. Authorizer: &ServiceAccount{},
  119. },
  120. expected: fmt.Errorf("AthenaConfiguration: missing database"),
  121. },
  122. "missing table": {
  123. config: AthenaConfiguration{
  124. Bucket: "bucket",
  125. Region: "region",
  126. Database: "database",
  127. Table: "",
  128. Catalog: "catalog",
  129. Workgroup: "workgroup",
  130. Account: "account",
  131. Authorizer: &ServiceAccount{},
  132. },
  133. expected: fmt.Errorf("AthenaConfiguration: missing table"),
  134. },
  135. "missing workgroup": {
  136. config: AthenaConfiguration{
  137. Bucket: "bucket",
  138. Region: "region",
  139. Database: "database",
  140. Catalog: "catalog",
  141. Table: "table",
  142. Workgroup: "",
  143. Account: "account",
  144. Authorizer: &ServiceAccount{},
  145. },
  146. expected: nil,
  147. },
  148. "missing account": {
  149. config: AthenaConfiguration{
  150. Bucket: "bucket",
  151. Region: "region",
  152. Database: "database",
  153. Catalog: "catalog",
  154. Table: "table",
  155. Workgroup: "workgroup",
  156. Account: "",
  157. Authorizer: &ServiceAccount{},
  158. },
  159. expected: fmt.Errorf("AthenaConfiguration: missing account"),
  160. },
  161. }
  162. for name, testCase := range testCases {
  163. t.Run(name, func(t *testing.T) {
  164. actual := testCase.config.Validate()
  165. actualString := "nil"
  166. if actual != nil {
  167. actualString = actual.Error()
  168. }
  169. expectedString := "nil"
  170. if testCase.expected != nil {
  171. expectedString = testCase.expected.Error()
  172. }
  173. if actualString != expectedString {
  174. t.Errorf("errors do not match: Actual: '%s', Expected: '%s", actualString, expectedString)
  175. }
  176. })
  177. }
  178. }
  179. func TestAthenaConfiguration_Equals(t *testing.T) {
  180. testCases := map[string]struct {
  181. left AthenaConfiguration
  182. right cloud.Config
  183. expected bool
  184. }{
  185. "matching config": {
  186. left: AthenaConfiguration{
  187. Bucket: "bucket",
  188. Region: "region",
  189. Database: "database",
  190. Catalog: "catalog",
  191. Table: "table",
  192. Workgroup: "workgroup",
  193. Account: "account",
  194. Authorizer: &AccessKey{
  195. ID: "id",
  196. Secret: "secret",
  197. },
  198. },
  199. right: &AthenaConfiguration{
  200. Bucket: "bucket",
  201. Region: "region",
  202. Database: "database",
  203. Catalog: "catalog",
  204. Table: "table",
  205. Workgroup: "workgroup",
  206. Account: "account",
  207. Authorizer: &AccessKey{
  208. ID: "id",
  209. Secret: "secret",
  210. },
  211. },
  212. expected: true,
  213. },
  214. "different Authorizer": {
  215. left: AthenaConfiguration{
  216. Bucket: "bucket",
  217. Region: "region",
  218. Database: "database",
  219. Catalog: "catalog",
  220. Table: "table",
  221. Workgroup: "workgroup",
  222. Account: "account",
  223. Authorizer: &AccessKey{
  224. ID: "id",
  225. Secret: "secret",
  226. },
  227. },
  228. right: &AthenaConfiguration{
  229. Bucket: "bucket",
  230. Region: "region",
  231. Database: "database",
  232. Catalog: "catalog",
  233. Table: "table",
  234. Workgroup: "workgroup",
  235. Account: "account",
  236. Authorizer: &ServiceAccount{},
  237. },
  238. expected: false,
  239. },
  240. "missing both Authorizer": {
  241. left: AthenaConfiguration{
  242. Bucket: "bucket",
  243. Region: "region",
  244. Database: "database",
  245. Catalog: "catalog",
  246. Table: "table",
  247. Workgroup: "workgroup",
  248. Account: "account",
  249. Authorizer: nil,
  250. },
  251. right: &AthenaConfiguration{
  252. Bucket: "bucket",
  253. Region: "region",
  254. Database: "database",
  255. Catalog: "catalog",
  256. Table: "table",
  257. Workgroup: "workgroup",
  258. Account: "account",
  259. Authorizer: nil,
  260. },
  261. expected: true,
  262. },
  263. "missing left Authorizer": {
  264. left: AthenaConfiguration{
  265. Bucket: "bucket",
  266. Region: "region",
  267. Database: "database",
  268. Catalog: "catalog",
  269. Table: "table",
  270. Workgroup: "workgroup",
  271. Account: "account",
  272. Authorizer: nil,
  273. },
  274. right: &AthenaConfiguration{
  275. Bucket: "bucket",
  276. Region: "region",
  277. Database: "database",
  278. Catalog: "catalog",
  279. Table: "table",
  280. Workgroup: "workgroup",
  281. Account: "account",
  282. Authorizer: &ServiceAccount{},
  283. },
  284. expected: false,
  285. },
  286. "missing right Authorizer": {
  287. left: AthenaConfiguration{
  288. Bucket: "bucket",
  289. Region: "region",
  290. Database: "database",
  291. Catalog: "catalog",
  292. Table: "table",
  293. Workgroup: "workgroup",
  294. Account: "account",
  295. Authorizer: &AccessKey{
  296. ID: "id",
  297. Secret: "secret",
  298. },
  299. },
  300. right: &AthenaConfiguration{
  301. Bucket: "bucket",
  302. Region: "region",
  303. Database: "database",
  304. Catalog: "catalog",
  305. Table: "table",
  306. Workgroup: "workgroup",
  307. Account: "account",
  308. Authorizer: nil,
  309. },
  310. expected: false,
  311. },
  312. "different bucket": {
  313. left: AthenaConfiguration{
  314. Bucket: "bucket",
  315. Region: "region",
  316. Database: "database",
  317. Catalog: "catalog",
  318. Table: "table",
  319. Workgroup: "workgroup",
  320. Account: "account",
  321. Authorizer: &AccessKey{
  322. ID: "id",
  323. Secret: "secret",
  324. },
  325. },
  326. right: &AthenaConfiguration{
  327. Bucket: "bucket2",
  328. Region: "region",
  329. Database: "database",
  330. Catalog: "catalog",
  331. Table: "table",
  332. Workgroup: "workgroup",
  333. Account: "account",
  334. Authorizer: &AccessKey{
  335. ID: "id",
  336. Secret: "secret",
  337. },
  338. },
  339. expected: false,
  340. },
  341. "different region": {
  342. left: AthenaConfiguration{
  343. Bucket: "bucket",
  344. Region: "region",
  345. Database: "database",
  346. Catalog: "catalog",
  347. Table: "table",
  348. Workgroup: "workgroup",
  349. Account: "account",
  350. Authorizer: &AccessKey{
  351. ID: "id",
  352. Secret: "secret",
  353. },
  354. },
  355. right: &AthenaConfiguration{
  356. Bucket: "bucket",
  357. Region: "region2",
  358. Database: "database",
  359. Catalog: "catalog",
  360. Table: "table",
  361. Workgroup: "workgroup",
  362. Account: "account",
  363. Authorizer: &AccessKey{
  364. ID: "id",
  365. Secret: "secret",
  366. },
  367. },
  368. expected: false,
  369. },
  370. "different database": {
  371. left: AthenaConfiguration{
  372. Bucket: "bucket",
  373. Region: "region",
  374. Database: "database",
  375. Catalog: "catalog",
  376. Table: "table",
  377. Workgroup: "workgroup",
  378. Account: "account",
  379. Authorizer: &AccessKey{
  380. ID: "id",
  381. Secret: "secret",
  382. },
  383. },
  384. right: &AthenaConfiguration{
  385. Bucket: "bucket",
  386. Region: "region",
  387. Database: "database2",
  388. Catalog: "catalog",
  389. Table: "table",
  390. Workgroup: "workgroup",
  391. Account: "account",
  392. Authorizer: &AccessKey{
  393. ID: "id",
  394. Secret: "secret",
  395. },
  396. },
  397. expected: false,
  398. },
  399. "different table": {
  400. left: AthenaConfiguration{
  401. Bucket: "bucket",
  402. Region: "region",
  403. Database: "database",
  404. Catalog: "catalog",
  405. Table: "table",
  406. Workgroup: "workgroup",
  407. Account: "account",
  408. Authorizer: &AccessKey{
  409. ID: "id",
  410. Secret: "secret",
  411. },
  412. },
  413. right: &AthenaConfiguration{
  414. Bucket: "bucket",
  415. Region: "region",
  416. Database: "database",
  417. Catalog: "catalog",
  418. Table: "table2",
  419. Workgroup: "workgroup",
  420. Account: "account",
  421. Authorizer: &AccessKey{
  422. ID: "id",
  423. Secret: "secret",
  424. },
  425. },
  426. expected: false,
  427. },
  428. "different catalog": {
  429. left: AthenaConfiguration{
  430. Bucket: "bucket",
  431. Region: "region",
  432. Database: "database",
  433. Catalog: "catalog",
  434. Table: "table",
  435. Workgroup: "workgroup",
  436. Account: "account",
  437. Authorizer: &AccessKey{
  438. ID: "id",
  439. Secret: "secret",
  440. },
  441. },
  442. right: &AthenaConfiguration{
  443. Bucket: "bucket",
  444. Region: "region",
  445. Database: "database",
  446. Catalog: "catalog2",
  447. Table: "table",
  448. Workgroup: "workgroup",
  449. Account: "account",
  450. Authorizer: &AccessKey{
  451. ID: "id",
  452. Secret: "secret",
  453. },
  454. },
  455. expected: false,
  456. },
  457. "different workgroup": {
  458. left: AthenaConfiguration{
  459. Bucket: "bucket",
  460. Region: "region",
  461. Database: "database",
  462. Catalog: "catalog",
  463. Table: "table",
  464. Workgroup: "workgroup",
  465. Account: "account",
  466. Authorizer: &AccessKey{
  467. ID: "id",
  468. Secret: "secret",
  469. },
  470. },
  471. right: &AthenaConfiguration{
  472. Bucket: "bucket",
  473. Region: "region",
  474. Database: "database",
  475. Catalog: "catalog",
  476. Table: "table",
  477. Workgroup: "workgroup2",
  478. Account: "account",
  479. Authorizer: &AccessKey{
  480. ID: "id",
  481. Secret: "secret",
  482. },
  483. },
  484. expected: false,
  485. },
  486. "different account": {
  487. left: AthenaConfiguration{
  488. Bucket: "bucket",
  489. Region: "region",
  490. Database: "database",
  491. Table: "table",
  492. Workgroup: "workgroup",
  493. Account: "account",
  494. Authorizer: &AccessKey{
  495. ID: "id",
  496. Secret: "secret",
  497. },
  498. },
  499. right: &AthenaConfiguration{
  500. Bucket: "bucket",
  501. Region: "region",
  502. Database: "database",
  503. Table: "table",
  504. Workgroup: "workgroup",
  505. Account: "account2",
  506. Authorizer: &AccessKey{
  507. ID: "id",
  508. Secret: "secret",
  509. },
  510. },
  511. expected: false,
  512. },
  513. "different resultReuseMaxAgeMinutes": {
  514. left: AthenaConfiguration{
  515. Bucket: "bucket",
  516. Region: "region",
  517. Database: "database",
  518. Catalog: "catalog",
  519. Table: "table",
  520. Workgroup: "workgroup",
  521. Account: "account",
  522. ResultReuseMaxAgeMinutes: 60,
  523. Authorizer: &AccessKey{
  524. ID: "id",
  525. Secret: "secret",
  526. },
  527. },
  528. right: &AthenaConfiguration{
  529. Bucket: "bucket",
  530. Region: "region",
  531. Database: "database",
  532. Catalog: "catalog",
  533. Table: "table",
  534. Workgroup: "workgroup",
  535. Account: "account",
  536. ResultReuseMaxAgeMinutes: 120,
  537. Authorizer: &AccessKey{
  538. ID: "id",
  539. Secret: "secret",
  540. },
  541. },
  542. expected: false,
  543. },
  544. "different config": {
  545. left: AthenaConfiguration{
  546. Bucket: "bucket",
  547. Region: "region",
  548. Database: "database",
  549. Table: "table",
  550. Workgroup: "workgroup",
  551. Account: "account",
  552. Authorizer: &AccessKey{
  553. ID: "id",
  554. Secret: "secret",
  555. },
  556. },
  557. right: &AccessKey{
  558. ID: "id",
  559. Secret: "secret",
  560. },
  561. expected: false,
  562. },
  563. }
  564. for name, testCase := range testCases {
  565. t.Run(name, func(t *testing.T) {
  566. actual := testCase.left.Equals(testCase.right)
  567. if actual != testCase.expected {
  568. t.Errorf("incorrect result: Actual: '%t', Expected: '%t", actual, testCase.expected)
  569. }
  570. })
  571. }
  572. }
  573. func TestAthenaConfiguration_JSON(t *testing.T) {
  574. testCases := map[string]struct {
  575. config AthenaConfiguration
  576. }{
  577. "Empty Config": {
  578. config: AthenaConfiguration{},
  579. },
  580. "AccessKey": {
  581. config: AthenaConfiguration{
  582. Bucket: "bucket",
  583. Region: "region",
  584. Database: "database",
  585. Catalog: "catalog",
  586. Table: "table",
  587. Workgroup: "workgroup",
  588. Account: "account",
  589. Authorizer: &AccessKey{
  590. ID: "id",
  591. Secret: "secret",
  592. },
  593. },
  594. },
  595. "ServiceAccount": {
  596. config: AthenaConfiguration{
  597. Bucket: "bucket",
  598. Region: "region",
  599. Database: "database",
  600. Catalog: "catalog",
  601. Table: "table",
  602. Workgroup: "workgroup",
  603. Account: "account",
  604. Authorizer: &ServiceAccount{},
  605. },
  606. },
  607. "ResultReuseMaxAgeMinutes": {
  608. config: AthenaConfiguration{
  609. Bucket: "bucket",
  610. Region: "region",
  611. Database: "database",
  612. Catalog: "catalog",
  613. Table: "table",
  614. Workgroup: "workgroup",
  615. Account: "account",
  616. ResultReuseMaxAgeMinutes: 60,
  617. Authorizer: &AccessKey{
  618. ID: "id",
  619. Secret: "secret",
  620. },
  621. },
  622. },
  623. "AssumeRole with AccessKey": {
  624. config: AthenaConfiguration{
  625. Bucket: "bucket",
  626. Region: "region",
  627. Database: "database",
  628. Catalog: "catalog",
  629. Table: "table",
  630. Workgroup: "workgroup",
  631. Account: "account",
  632. Authorizer: &AssumeRole{
  633. Authorizer: &AccessKey{
  634. ID: "id",
  635. Secret: "secret",
  636. },
  637. RoleARN: "12345",
  638. },
  639. },
  640. },
  641. "AssumeRole with ServiceAccount": {
  642. config: AthenaConfiguration{
  643. Bucket: "bucket",
  644. Region: "region",
  645. Database: "database",
  646. Catalog: "catalog",
  647. Table: "table",
  648. Workgroup: "workgroup",
  649. Account: "account",
  650. Authorizer: &AssumeRole{
  651. Authorizer: &ServiceAccount{},
  652. RoleARN: "12345",
  653. },
  654. },
  655. },
  656. "RoleArnNil": {
  657. config: AthenaConfiguration{
  658. Bucket: "bucket",
  659. Region: "region",
  660. Database: "database",
  661. Catalog: "catalog",
  662. Table: "table",
  663. Workgroup: "workgroup",
  664. Account: "account",
  665. Authorizer: &AssumeRole{
  666. Authorizer: nil,
  667. RoleARN: "12345",
  668. },
  669. },
  670. },
  671. "AssumeRole with AssumeRole with ServiceAccount": {
  672. config: AthenaConfiguration{
  673. Bucket: "bucket",
  674. Region: "region",
  675. Database: "database",
  676. Catalog: "catalog",
  677. Table: "table",
  678. Workgroup: "workgroup",
  679. Account: "account",
  680. Authorizer: &AssumeRole{
  681. Authorizer: &AssumeRole{
  682. RoleARN: "12345",
  683. Authorizer: &ServiceAccount{},
  684. },
  685. RoleARN: "12345",
  686. },
  687. },
  688. },
  689. }
  690. for name, testCase := range testCases {
  691. t.Run(name, func(t *testing.T) {
  692. // test JSON Marshalling
  693. configJSON, err := json.Marshal(testCase.config)
  694. if err != nil {
  695. t.Errorf("failed to marshal configuration: %s", err.Error())
  696. }
  697. log.Info(string(configJSON))
  698. unmarshalledConfig := &AthenaConfiguration{}
  699. err = json.Unmarshal(configJSON, unmarshalledConfig)
  700. if err != nil {
  701. t.Errorf("failed to unmarshal configuration: %s", err.Error())
  702. }
  703. if !testCase.config.Equals(unmarshalledConfig) {
  704. t.Error("config does not equal unmarshalled config")
  705. }
  706. })
  707. }
  708. }