|
| 1 | +# How to write tests with Couchbase |
| 2 | + |
| 3 | +When you write tests interacting with Couchbase, it's easy to get fooled by its asynchronicity. |
| 4 | +Buckets, scopes, collections, query indexes and search indexes are built asynchronously. |
| 5 | + |
| 6 | +This means a numbers of things to avoid the flakiness of our tests. |
| 7 | + |
| 8 | +## TL;DR - Cheat sheet |
| 9 | + |
| 10 | +| | Check / Solution | Cbjs helper | |
| 11 | +|--------------------------------------|---------------------------------------------------------------------------------------|---------------------------------------| |
| 12 | +| Write a keyspace inside a bucket | GET `/pools/default/<bucket>` is a `200` | `waitForBucket` | |
| 13 | +| Write a keyspace inside a scope | Response of `/pools/default/<bucket>/scopes` includes the scope | `waitForScope` | |
| 14 | +| Write a keyspace inside a collection | Response of `/pools/default/<bucket>/scopes` includes the collection | `waitForCollection` | |
| 15 | +| Write a document in the bucket | The bucket stats (ram, vBuckets) are not empty | `waitForBucket` | |
| 16 | +| Write a document in the scope | Bucket is writable and scope is included in `/pools/default/<bucket>/scopes` | `waitForScope` | |
| 17 | +| Write a document in the collection | Bucket is writable and collection is included in `/pools/default/<bucket>/scopes` | `waitForCollection` | |
| 18 | +| Create a query index using a bucket | `SELECT RAW name FROM system:keyspaces` | `getQueryBuckets` | |
| 19 | +| Query fresh documents | Query with `REQUEST_PLUS` consistency on the indexes involved before our actual query | Too business specific to get a helper | |
| 20 | +| Full Text Search fresh documents | Query for docIds and wait for the result to include our documents | `waitForDocumentsInSearchIndex` | |
| 21 | + |
| 22 | + |
| 23 | +## Keyspaces (buckets, scopes and collections) |
| 24 | + |
| 25 | +When we create a keyspace object, the API will return immediately, but the creation is not instantaneous. |
| 26 | +Each service of each node will be notified asynchronously about the new keyspace. |
| 27 | + |
| 28 | +We will need to wait for the keyspace to be known and ready in order to : |
| 29 | + |
| 30 | +1. Create a keyspace object within it |
| 31 | +2. Write a document within it |
| 32 | +3. Create an index that references it |
| 33 | + |
| 34 | +The check must be performed on each node involved ; so if you want to write a document in a fresh keyspace, you need to |
| 35 | +check every node with the `kv` service before writing the document. |
| 36 | +For indexes, unless the index is configured to be on specific nodes, you will need to check every node with the `query` service. |
| 37 | + |
| 38 | +To make sure a keyspace is visible by the query service, you need to execute the following statement and verify our keyspace is |
| 39 | +included in the result set : |
| 40 | + |
| 41 | +```sql |
| 42 | +SELECT RAW name FROM system:keyspaces |
| 43 | +``` |
| 44 | + |
| 45 | +## Query fresh documents |
| 46 | + |
| 47 | +Since the indexes are built asynchronously, if we execute a query just after writing a document, the query result |
| 48 | +is not guaranteed to include the latest changes. |
| 49 | +If we want to have the latest updates, we can execute our query with the `REQUEST_PLUS` consistency. |
| 50 | +But it is likely that our actual business query does not require this level of consistency, so the trick here will be to execute a _consistency query_ |
| 51 | +prior to our actual query. |
| 52 | + |
| 53 | +Let's say we are testing a query that retrieves the blog posts authored by a user : |
| 54 | + |
| 55 | +Given we have the following index: `CREATE INDEX posts_listing ON posts (authorId, categoryId, createdAt)`, we will proceed as follow : |
| 56 | + |
| 57 | +1. We insert our test blog posts |
| 58 | +2. We execute `SELECT META().id FROM posts WHERE authorId IS NOT MISSING` with `REQUEST_PLUS` consistency - that's our _consistency query_ |
| 59 | +3. We call `getUserPosts(userId)` which executes `SELECT META().id, title FROM posts WHERE authorId = $1 ORDER BY createdAt DESC` |
| 60 | + |
| 61 | +The `WHERE` clause in our _consistency query_ is very important because it targets the index we are using in our business query. |
| 62 | +We only need to specify the first field of the index for it to be used by the query, |
| 63 | +so one _consistency query_ can be reused for every query that use the same index. |
| 64 | + |
| 65 | +So now we will create a helper function `waitForBlogPosts` that executes the query. |
| 66 | +If we create a new index on the `posts` collection, we can add another _consistency query_ with an **index hint** in our helper function, so |
| 67 | +we only have to know about this helper. |
0 commit comments