Patterns for testing web API permissions
I am working on a cookie cutter JSON web API. Think /items/<id>
with your typical CRUD of delete
, patch
, get
, and post
.
Recently, we started rolling out a new permissions model for the API, where certain operations are forbidden based on a combination of user and object properties. For example:
- We have two types of items - normal items and
locked
items, and we have two type of users - regular users and admin users. Users belong to acompany
. - Regular users can mutate any normal item that belongs to their
company
, but notlocked
items - Admin users can mutate any item (normal or locked) in their
company
.
So the matrix for testing looks something like this:
- Test that regular users can do full CRUD on normal items in their company
- Test that regular users can get but not mutate locked items in their company
- Test that regular users can not do any CRUD on items not in their company
- Test that admin users can do full CRUD on normal items in their company
- Test that admin users can do full CRUD on locked items in their company
- Test that admin users can not do any CRUD on items not in their company
If we multiply this out, we get 32 combinations:
4 types of operations (delete|patch|post|get)
multiplied by2 types of users (admin | regular user)
...2 types of company ownership (your company | not your company)
...2 types of item (locked|unlocked)
There is some redundancy there. We don't have to test admin users against normal items, or items outside their company. That reduces number of tests from 32 to 24. It's still a lot of testing.
Setting up individual test methods for this is very labor intensive. Common sense solutions are:
- Make this a table driven test. It will be verbose and messy. The test framework I am using doesn't let you easily parameterize tests. I am using django test suite -- it has a
subTest()
utility method that lets you run tests in a for-loop, but it all happens inside the same setUp/tearDown context (so tests are not isolated). - Don't bother testing permissions as part of the API integration tests. Instead, test the underlying
has_permissions
functions in a lower level test, without setting up the API layer. I am iffy on this. I am a big fan of testing the behavior. CRUD API is the behavior. If you delete all the permissions checks from the API layer, the unit tests of the permissions function won't help you.
How do you approach this problem in a manner that creates maintainable test code?