Skip to content

Commit

Permalink
Merge branch 'master' into v2-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
guregu committed May 4, 2024
2 parents 9b9e3cb + aa3c35c commit a749b0c
Show file tree
Hide file tree
Showing 24 changed files with 751 additions and 236 deletions.
8 changes: 8 additions & 0 deletions .github/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: '3'

services:
dynamodb:
image: amazon/dynamodb-local:latest
ports:
- "8880:8000"
command: "-jar DynamoDBLocal.jar -sharedDb -inMemory"
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 'stable'
- name: Start DynamoDB Local
run: docker compose -f '.github/docker-compose.yml' up -d
- name: Test
run: go test -v -race -cover -coverpkg=./... ./...
env:
DYNAMO_TEST_ENDPOINT: 'http://localhost:8880'
DYNAMO_TEST_REGION: local
DYNAMO_TEST_TABLE: 'TestDB-%'
AWS_ACCESS_KEY_ID: dummy
AWS_SECRET_ACCESS_KEY: dummy
AWS_REGION: local
44 changes: 15 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,38 +237,24 @@ err := db.Table("Books").Get("ID", 555).One(dynamo.AWSEncoding(&someBook))

### Integration tests

By default, tests are run in offline mode. Create a table called `TestDB`, with a number partition key called `UserID` and a string sort key called `Time`. It also needs a Global Secondary Index called `Msg-Time-index` with a string partition key called `Msg` and a string sort key called `Time`.
By default, tests are run in offline mode. In order to run the integration tests, some environment variables need to be set.

Change the table name with the environment variable `DYNAMO_TEST_TABLE`. You must specify `DYNAMO_TEST_REGION`, setting it to the AWS region where your test table is.


```bash
DYNAMO_TEST_REGION=us-west-2 go test github.com/guregu/dynamo/... -cover
```

If you want to use [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html) to run local tests, specify `DYNAMO_TEST_ENDPOINT`.

```bash
DYNAMO_TEST_REGION=us-west-2 DYNAMO_TEST_ENDPOINT=http://localhost:8000 go test github.com/guregu/dynamo/... -cover
```

Example of using [aws-cli](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.CLI.html) to create a table for testing.
To run the tests against [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html):

```bash
aws dynamodb create-table \
--table-name TestDB \
--attribute-definitions \
AttributeName=UserID,AttributeType=N \
AttributeName=Time,AttributeType=S \
AttributeName=Msg,AttributeType=S \
--key-schema \
AttributeName=UserID,KeyType=HASH \
AttributeName=Time,KeyType=RANGE \
--global-secondary-indexes \
IndexName=Msg-Time-index,KeySchema=[{'AttributeName=Msg,KeyType=HASH'},{'AttributeName=Time,KeyType=RANGE'}],Projection={'ProjectionType=ALL'} \
--billing-mode PAY_PER_REQUEST \
--region us-west-2 \
--endpoint-url http://localhost:8000 # using DynamoDB local
# Use Docker to run DynamoDB local on port 8880
docker compose -f '.github/docker-compose.yml' up -d

# Run the tests with a fresh table
# The tables will be created automatically
# The '%' in the table name will be replaced the current timestamp
DYNAMO_TEST_ENDPOINT='http://localhost:8880' \
DYNAMO_TEST_REGION='local' \
DYNAMO_TEST_TABLE='TestDB-%' \
AWS_ACCESS_KEY_ID='dummy' \
AWS_SECRET_ACCESS_KEY='dummy' \
AWS_REGION='local' \
go test -v -race ./... -cover -coverpkg=./...
```

### License
Expand Down
80 changes: 51 additions & 29 deletions batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ func TestBatchGetWrite(t *testing.T) {
if testDB == nil {
t.Skip(offlineSkipMsg)
}
table := testDB.Table(testTable)
table1 := testDB.Table(testTableWidgets)
table2 := testDB.Table(testTableSprockets)
tables := []Table{table1, table2}
totalBatchSize := batchSize * len(tables)
ctx := context.TODO()

items := make([]interface{}, batchSize)
Expand All @@ -30,10 +33,17 @@ func TestBatchGetWrite(t *testing.T) {
keys[i] = Keys{i, now}
}

var batches []*BatchWrite
for _, table := range tables {
b := table.Batch().Write().Put(items...)
batches = append(batches, b)
}
batch1 := batches[0]
batch1.Merge(batches[1:]...)
var wcc ConsumedCapacity
wrote, err := table.Batch().Write().Put(items...).ConsumedCapacity(&wcc).Run(ctx)
if wrote != batchSize {
t.Error("unexpected wrote:", wrote, "≠", batchSize)
wrote, err := batch1.ConsumedCapacity(&wcc).Run(ctx)
if wrote != totalBatchSize {
t.Error("unexpected wrote:", wrote, "≠", totalBatchSize)
}
if err != nil {
t.Error("unexpected error:", err)
Expand All @@ -43,20 +53,27 @@ func TestBatchGetWrite(t *testing.T) {
}

// get all
var results []widget
var gets []*BatchGet
for _, table := range tables {
b := table.Batch("UserID", "Time").
Get(keys...).
Project("UserID", "Time").
Consistent(true)
gets = append(gets, b)
}

var cc ConsumedCapacity
err = table.Batch("UserID", "Time").
Get(keys...).
Project("UserID", "Time").
Consistent(true).
ConsumedCapacity(&cc).
All(ctx, &results)
get1 := gets[0].ConsumedCapacity(&cc)
get1.Merge(gets[1:]...)

var results []widget
err = get1.All(ctx, &results)
if err != nil {
t.Error("unexpected error:", err)
}

if len(results) != batchSize {
t.Error("expected", batchSize, "results, got", len(results))
if len(results) != totalBatchSize {
t.Error("expected", totalBatchSize, "results, got", len(results))
}

if cc.Total == 0 {
Expand All @@ -74,34 +91,39 @@ func TestBatchGetWrite(t *testing.T) {
}

// delete both
wrote, err = table.Batch("UserID", "Time").Write().
Delete(keys...).Run(ctx)
if wrote != batchSize {
t.Error("unexpected wrote:", wrote, "≠", batchSize)
wrote, err = table1.Batch("UserID", "Time").Write().
Delete(keys...).
DeleteInRange(table2, "UserID", "Time", keys...).
Run(ctx)
if wrote != totalBatchSize {
t.Error("unexpected wrote:", wrote, "≠", totalBatchSize)
}
if err != nil {
t.Error("unexpected error:", err)
}

// get both again
results = nil
err = table.Batch("UserID", "Time").
Get(keys...).
Consistent(true).
All(ctx, &results)
if err != ErrNotFound {
t.Error("expected ErrNotFound, got", err)
}
if len(results) != 0 {
t.Error("expected 0 results, got", len(results))
{
var results []widget
err = table1.Batch("UserID", "Time").
Get(keys...).
FromRange(table2, "UserID", "Time", keys...).
Consistent(true).
All(ctx, &results)
if err != ErrNotFound {
t.Error("expected ErrNotFound, got", err)
}
if len(results) != 0 {
t.Error("expected 0 results, got", len(results))
}
}
}

func TestBatchGetEmptySets(t *testing.T) {
if testDB == nil {
t.Skip(offlineSkipMsg)
}
table := testDB.Table(testTable)
table := testDB.Table(testTableWidgets)
ctx := context.TODO()

now := time.Now().UnixNano() / 1000000000
Expand Down Expand Up @@ -153,8 +175,8 @@ func TestBatchGetEmptySets(t *testing.T) {
}

func TestBatchEmptyInput(t *testing.T) {
table := testDB.Table(testTableWidgets)
ctx := context.TODO()
table := testDB.Table(testTable)
var out []any
err := table.Batch("UserID", "Time").Get().All(ctx, &out)
if err != ErrNoInput {
Expand Down
Loading

0 comments on commit a749b0c

Please sign in to comment.