Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(storage-browser): validate schema of data received from read APIs #6213

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

eppjame
Copy link

@eppjame eppjame commented Nov 27, 2024

Description of changes

  • Based on outdated PR from @wuuxigh
  • Add explicit checks for the required data schema we expect from READ APIs. The required data is a subset of the response structure, and focuses on what the storage browser uses.
  • In most cases, without these checks, missing fields will currently result in a type error or caught by stricter value-checks. Adding explicit checks makes for a consistent error mode, and expands coverage to all relevant cases. It would also be possible for implementation refactors to unknowingly remove the code path to the existing errors.
  • checkRequiredKeys is intentionally forwards-compatible so these checks do not have to be updated every time amplify-js adds properties to the response that storage browser doesn't use.

Issue #, if available

Description of how you validated changes

  • Updated unit tests

Checklist

  • Have read the Pull Request Guidelines
  • PR description included
  • yarn test passes and tests are updated/added
  • PR title and commit messages follow conventional commit syntax
  • If this change should result in a version bump, changeset added (This can be done after creating the PR.) This does not apply to changes made to docs, e2e, examples, or other private packages.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@eppjame eppjame requested a review from a team as a code owner November 27, 2024 18:36
Copy link

changeset-bot bot commented Nov 27, 2024

⚠️ No Changeset found

Latest commit: 9b3467b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Member

@calebpollman calebpollman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor feedback around aligning to existing idioms. Somewhat concerned in regards to how the UI will handle exceptions thrown from the new util and what messaging is exposed to end users


describe('checkRequiredKeys', () => {
it('should not throw when all required keys are present', () => {
const object: TestObject = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer declarative naming of variables implying their use case (e.g. input)

Comment on lines +4 to +7
key1?: string | null;
key2?: string | null;
key3?: string | null;
extraKey?: string | null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the values provided are of type number?

@@ -127,4 +128,37 @@ describe('listLocationsHandler', () => {
'Storage Browser: Must provide accountId to `listCallerAccessGrants`.'
);
});

it('should throw if list does not provide locations', async () => {
input.config.accountId = accountId;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See that mutating the test input is an existing pattern but these new tests need to create a new input for each call to avoid non-deterministic behavior between individual tests, example:

await expect(listLocationsHandler({ ...input, config: { ...input.config, accountId }})).rejects.toThrow(
   'Required keys missing for ListLocationsOutput: locations.'
);

@@ -54,7 +55,9 @@ export const downloadHandler: DownloadHandler = ({
expectedBucketOwner: accountId,
},
})
.then(({ url }) => {
.then((result) => {
checkRequiredKeys(result, 'StorageGetUrlOutput', ['url']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the UI handle the error thrown here gracefully?

Comment on lines +11 to +15
throw Error(
`Required keys missing for ${objectName}: ${[...missingValues].join(
', '
)}.\nObject: ${JSON.stringify(objectToCheck)}`
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this intended to be surfaced to an end user and what actions are they expected to take in a missing key scenario?

@@ -150,6 +151,33 @@ describe('listLocationItemsHandler', () => {
})
);
});

it('should throw if list does not provide items', async () => {
mockList.mockResolvedValueOnce({} as any);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer @ts-expect-error with a concise comment explaining the need for the invalid response

);
});

['path', 'lastModified', 'size'].forEach((requiredKey) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer jest.each

});

await expect(listLocationItemsHandler(baseInput)).rejects.toThrow(
`Required keys missing for ListOutputItem #1: ${requiredKey}.`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a single key is missing why pluralize?

Comment on lines +2 to +3
objectToCheck: T,
objectName: string,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please updates these names to align with function parameter naming within the code base, for example:

- objectToCheck: T,
+ input: T,
- objectName: string,
+ displayName: string,

@@ -70,4 +71,15 @@ describe('downloadHandler', () => {
message: errorMessage,
});
});

it('should fail if getUrl does not return a url', async () => {
mockGetUrl.mockResolvedValue({} as any);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer @ts-expect-error with a concise comment explaining the need for the invalid response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants