Have some questions around people's testing approa...
# random
t
Have some questions around people's testing approach with dynamo. I'd like to write tests for my domains where a single test writes some data, reads it out and verifies it looks right. My typical approach is to reset the database between each test so it's fresh. However jest by default runs tests in parallel. Which makes sense for strict unit tests and I know I can force it to run serially but makes me wonder if I'm using the wrong tool for the job.
Almost feel like each test should prefix its data in dynamo so they can run in parallel without conflicting
s
I was generating unique partition/sort keys for the same reason in my integration tests. I couldn’t figure out a better solution. There is also a TTL option for DynamoDb records. Though I never tried how fast the engine cleans up stale records.
o
My app has different tenants so each test creates a new tenant. So its effectively prefixing cos tenant data is always segregated
t
Ah nice. I effectively need to do something like that. Curious how you implemented multi tenant?
o
• Workspaces have exist as two docs, one that’s
{ pk: "workspace/workspace_id", sk: "_self" }
which is high read volume and another that’s
{pk: "workspaces", sk: "workspace_id"}
that’s low read volume (mostly used for enumerating workspaces for ops tasks) • Top level docs exist as
{pk: "workspace_id/entity_type", sk: "entity_id"}
- don’t have many top level docs per workspace (usually 10s, max ~hundreds) • Lower level docs exist as
{pk: "parent_entity_type/parent_entity_id/entity_type", sk: "entity_id"}
, have a GSI that partitions by
workspace_id
and sometimes a GSI that partitions by parent’s parent entity • And as you’d expect there’s plenty of exceptions to the scheme above to optimise for various query patterns
t
Ah nice
And in code do your implement this explicitly (eg functions take a workspace id param) or more automatically through the environment (deployment per tenant that is locked to a workspace)
o
Yeah all explicit - external API calls get tagged by the authorizer (workspace id is in the JWT), otherwise events have the workspace id in there (usually because the entity in the event has workspace_id on there from the gsi described above)
Have a context object that I pass around everywhere, that contains the workspace id, logger instance, data loaders etc. Lambda handler code is exclusively focused on parsing the request and constructing that context. The code that gets called by the handler is typed to require a context object and its parameters. Whenever the context gets passed to something lower level, it constructs a new child context that inherits everything but gets a child logger instance (from bunyan).
t
Ah nice makes sense. Context object is what I was thinking as well