Repository navigation
CUMULUS-4954: add AthenaClient - #4567
Conversation
Updated getQueryResults get retrieve all results
for more information, see https://pre-commit.ci
| // TODO: Remove this comment when localstack is replaced: | ||
| // Athena client tests are unable to run using localstack local environment. | ||
| // Once localstack is replaced, these tests will need to be updated to use | ||
| // local AWS instances. This work should be completed in CUMULUS-5307. |
There was a problem hiding this comment.
This is probably my mistake, but I think 'instances' should actually be 'services' here.
| }); | ||
|
|
||
| test.serial('query() initiates a query, waits for it to finish, and returns the mapped response', async (t) => { | ||
| // could not get ministack duckdb to find a table to perform operations on it, |
There was a problem hiding this comment.
I think this comment is OBE
| sinon.stub(t.context.client, 'getQueryExecution') | ||
| .callsFake(() => Promise.resolve(abridgedResponse)); | ||
|
|
||
| const expected = [{ result: 'mock_value' }]; |
There was a problem hiding this comment.
Since that comment is OBE, and we're not using an endpoint that returns this, this expected should probably match what we are inserting into the table.
|
|
||
| const abridgedResponse = { | ||
| QueryExecution: { | ||
| QueryExecutionId: '1234-abcd-5678-efgh', |
There was a problem hiding this comment.
Really minor nit, which is kinda not important since we are mocking everything. But, it would probably be better if these Ids were not all the same. We could maybe randomize them or generate a uuid.
| const abridgedResponse = { | ||
| QueryExecution: { | ||
| QueryExecutionId: '1234-abcd-5678-efgh', | ||
| Query: '', |
There was a problem hiding this comment.
Also, the query should probably actually reflect the query we are sending for this and the other responses.
| t.deepEqual([], mappedResult); | ||
| }); | ||
|
|
||
| test.serial('query() initiates a query, waits for it to finish, and returns the mapped response', async (t) => { |
There was a problem hiding this comment.
getQueryResults is private so we probably can't call that directly to test and may need to use query, but we should probably test that the NextToken 'pagination' actually works.
Added NextToken test
for more information, see https://pre-commit.ci
| let nextToken = response?.NextToken?.toString() || ''; | ||
| data = data.concat(await this.mapData(response.ResultSet)); | ||
|
|
||
| while (response?.NextToken?.toString()) { |
There was a problem hiding this comment.
shouldn't the while loop be checking against nextToken?
|
|
||
| while (response?.NextToken?.toString()) { | ||
| // eslint-disable-next-line no-await-in-loop | ||
| const response = await this.client.send(new GetQueryResultsCommand({ |
There was a problem hiding this comment.
as the lint checker is pointing out, response is declared above, so that should probably use let and the const can be dropped here
| }; | ||
|
|
||
| athenaClientMock.on(GetQueryResultsCommand).resolvesOnce( | ||
| getDataResultsResponse |
There was a problem hiding this comment.
I'm a little confused by the chained and ordered responses here. getDataResultsWithNextToken actually includes a nextToken, but getDataResultsResponse does not. So I would think that getDataResultsWithNextToken should come first and would make the loop want to make another request, and then when getDataResultsResponse is the response that doesn't include a nextToken, then the loop would stop.
Also it looks like there are 5 resolvesOnce and 1 resolves (which would be the default), so I would think there should be 6 rows of data. But the test is expecting 3 rows. Am I missing something?
Fixed next token loop
Using mocked tests because we were unable to find an easy replacement for Localstack was discussed in at least 3 or 4 different Arch meetings. It was determined and stated by Nathan that we would proceed with using mocked tests to get this functionality in, and we would carry some tech debt to replace Localstack and have tests written against that replacement. There were no objections raised. So I wrote some tickets to that effect, which I think you are looking at. |
Added pRetry to athena client Updated athena client format Removed debug logging
for more information, see https://pre-commit.ci
sylvesterkaczmarek
left a comment
There was a problem hiding this comment.
Thanks for the latest cleanup and test updates. Re-reviewed head 88e90d7 and found a new result-mapping regression that needs correcting before merge.
Athena's actual ResultSetMetadata.ColumnInfo is an array of column descriptors, one per selected column, with fields such as Name, Label, and Type. Both getQueryResults() and mapData() now use Object.keys(ColumnInfo[0]). That returns descriptor property names (Name, Type, etc.), not the SQL result column names. For example, with real metadata [{Name: 'bucket', Type: 'varchar'}, {Name: 'key', Type: 'varchar'}], the mapped result is keyed as {Name: ..., Type: ...} rather than {bucket: ..., key: ...}; additional values may be assigned under an undefined key.
The current mocks hide this because they use ColumnInfo: [{bucket: 'string', key: 'string', ...}], which isn't the Athena API's response shape. AWS reference: https://docs.aws.amazon.com/athena/latest/APIReference/API_GetQueryResults.html
Please derive the columns from ColumnInfo.map(column => column.Name) (with appropriate absent-metadata handling), or use the first-page header row as before, and carry those names into continuation pages. A regression with actual descriptor-shaped metadata, a header on page 1, and data-only rows on page 2 should assert the exact object keys and values. The earlier pagination issue remains fixed, but this metadata change reintroduces incorrect mappings, so I'm requesting changes on the current revision.
|
Updated the PR with the requested changes. I believe that this will resolve the issues addressed above. The only outstanding issue is the that the tests are currently being mocked. Changing those to real tests is blocked by another ticket currently in PR and is outside the scope of this ticket. |
|
Thanks for the update, @rswanso5-nasa. I checked head |
Fix format Updated constructor with init values Refactor Athena client
Updated changelog Format change to athena client
|
Thanks @rswanso5-nasa for updating the Athena result mapping and descriptor-shaped fixtures. I rechecked head |
Updated function docs
There was a problem hiding this comment.
Approving the PR with the expectation that the following items will be addressed in follow-up tickets/PRs.
- The current getQueryResults function fetches all results at once. Consider providing a separate asynchronous generator function to retrieve the results in batches.
#4567 (comment) - Add comprehensive unit and/or integration tests to ensure code reliability.
- Currently, getQueryResults returns an array of objects where all field values are stored as strings, regardless of their actual database schema type. Depending on how this function is consumed, we should consider converting these fields into their native types (e.g., numbers, booleans) using the result set metadata.
Updated tests
Summary: Summary of changes
Addresses [CUMULUS-4954: Implement Athena Client](https://bugs.earthdata.nasa.gov/browse/CUMULUS-4954)
Changes
PR Checklist
📝 Note:
For most pull requests, please Squash and merge to maintain a clean and readable commit history.