Skip to content

Commit

Permalink
Implements Query() and changes how PutItem() works
Browse files Browse the repository at this point in the history
  • Loading branch information
ebh committed Feb 14, 2021
1 parent 6154915 commit d6a570e
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 69 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.0.1] - 2021-02-14
### Added
- Query() implemented

### Changed
- How inputs and outputs for PutItem() work

## [0.0.0] - 2021-02-04
### Added
- PutItem() implemented
25 changes: 0 additions & 25 deletions all.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,31 +361,6 @@ func (db *DynamoDb) ListTagsOfResourceRequest(*dynamodb.ListTagsOfResourceInput)
panic("ListTagsOfResourceRequest is not implemented")
}

// Query is not implemented. It will panic in all cases.
func (db *DynamoDb) Query(*dynamodb.QueryInput) (*dynamodb.QueryOutput, error) {
panic("Query is not implemented")
}

// QueryWithContext is not implemented. It will panic in all cases.
func (db *DynamoDb) QueryWithContext(aws.Context, *dynamodb.QueryInput, ...request.Option) (*dynamodb.QueryOutput, error) {
panic("QueryWithContext is not implemented")
}

// QueryRequest is not implemented. It will panic in all cases.
func (db *DynamoDb) QueryRequest(*dynamodb.QueryInput) (*request.Request, *dynamodb.QueryOutput) {
panic("QueryRequest is not implemented")
}

// QueryPages is not implemented. It will panic in all cases.
func (db *DynamoDb) QueryPages(*dynamodb.QueryInput, func(*dynamodb.QueryOutput, bool) bool) error {
panic("QueryPages is not implemented")
}

// QueryPagesWithContext is not implemented. It will panic in all cases.
func (db *DynamoDb) QueryPagesWithContext(aws.Context, *dynamodb.QueryInput, func(*dynamodb.QueryOutput, bool) bool, ...request.Option) error {
panic("QueryPagesWithContext is not implemented")
}

// RestoreTableFromBackup is not implemented. It will panic in all cases.
func (db *DynamoDb) RestoreTableFromBackup(*dynamodb.RestoreTableFromBackupInput) (*dynamodb.RestoreTableFromBackupOutput, error) {
panic("RestoreTableFromBackup is not implemented")
Expand Down
34 changes: 0 additions & 34 deletions all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,40 +486,6 @@ func TestDynamoDb_ListTagsOfResourceRequest(t *testing.T) {
})
}

func TestDynamoDb_Query(t *testing.T) {
assert.PanicsWithValue(t, "Query is not implemented", func() {
_, err := mockdynamodb.New().Query(nil)
require.NoError(t, err)
})
}

func TestDynamoDb_QueryWithContext(t *testing.T) {
assert.PanicsWithValue(t, "QueryWithContext is not implemented", func() {
_, err := mockdynamodb.New().QueryWithContext(context.TODO(), nil)
require.NoError(t, err)
})
}

func TestDynamoDb_QueryRequest(t *testing.T) {
assert.PanicsWithValue(t, "QueryRequest is not implemented", func() {
mockdynamodb.New().QueryRequest(nil)
})
}

func TestDynamoDb_QueryPages(t *testing.T) {
assert.PanicsWithValue(t, "QueryPages is not implemented", func() {
err := mockdynamodb.New().QueryPages(nil, nil)
require.NoError(t, err)
})
}

func TestDynamoDb_QueryPagesWithContext(t *testing.T) {
assert.PanicsWithValue(t, "QueryPagesWithContext is not implemented", func() {
err := mockdynamodb.New().QueryPagesWithContext(context.TODO(), nil, nil)
require.NoError(t, err)
})
}

func TestDynamoDb_RestoreTableFromBackup(t *testing.T) {
assert.PanicsWithValue(t, "RestoreTableFromBackup is not implemented", func() {
_, err := mockdynamodb.New().RestoreTableFromBackup(nil)
Expand Down
18 changes: 16 additions & 2 deletions put.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package mockdynamodb

import (
"errors"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/service/dynamodb"
)

// PutItem is implemented.
// Use AddReturnPutItemOutput() set PutItemOutput for PutItem() to return.
// PutItem() will return PutItemOutputs in the same order in which AddReturnPutItemOutput() is called.
// If a nil value is given to AddReturnPutItemOutput() then PutItem() will return an error.
// Use ReceivedPutItemInputs() retrieve the inputs given to PutItem(), use for asserting.
func (db *DynamoDb) PutItem(input *dynamodb.PutItemInput) (*dynamodb.PutItemOutput, error) {
db.Lock()
defer db.Unlock()
Expand All @@ -33,8 +39,16 @@ func (db *DynamoDb) putItem(input *dynamodb.PutItemInput) (*dynamodb.PutItemOutp
}

if table := db.GetTable(*input.TableName); table != nil {
table.items = append(table.items, *input)
return &dynamodb.PutItemOutput{}, nil
table.receivedPutItemInputs = append(table.receivedPutItemInputs, *input)
if len(table.returnPutItemOutputs) > 0 {
o := table.popReturnPutItemOutput()
if o != nil {
return o, nil
}
return nil, errors.New("nil PutItemOutput")
}

return nil, errors.New("no PutItemOutputs to return")
}

return &dynamodb.PutItemOutput{}, errorNonExistentTable()
Expand Down
52 changes: 50 additions & 2 deletions put_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,63 @@ func TestDynamoDb_PutItem(t *testing.T) {
})

t.Run("PutItemInputRecorded", func(t *testing.T) {
tableName := "mockTable"
putItemInput := dynamodb.PutItemInput{TableName: &tableName}
putItemOutput := dynamodb.PutItemOutput{}

db := mockdynamodb.NewWithTables([]string{tableName})
db.GetTable(tableName).AddReturnPutItemOutput(&putItemOutput)

output, err := db.PutItem(&putItemInput)

assert.NoError(t, err)
assert.Equal(t, &[]dynamodb.PutItemInput{putItemInput}, db.GetTable(tableName).ReceivedPutItemInputs())
assert.Equal(t, &putItemOutput, output)
})

t.Run("PutItemOutputReturnedInOrder", func(t *testing.T) {
tableName := "mockTable"
putItemInput := dynamodb.PutItemInput{TableName: &tableName}

putItemOutput1 := dynamodb.PutItemOutput{}
putItemOutput2 := dynamodb.PutItemOutput{}

db := mockdynamodb.NewWithTables([]string{tableName})
db.GetTable(tableName).AddReturnPutItemOutput(&putItemOutput1)
db.GetTable(tableName).AddReturnPutItemOutput(&putItemOutput2)

output1, err1 := db.PutItem(&putItemInput)
output2, err2 := db.PutItem(&putItemInput)

assert.NoError(t, err1)
assert.NoError(t, err2)
assert.Same(t, &putItemOutput1, output1)
assert.Same(t, &putItemOutput2, output2)
})

t.Run("PutItemOutputIsNull", func(t *testing.T) {
tableName := "mockTable"
putItem := dynamodb.PutItemInput{TableName: &tableName}

db := mockdynamodb.NewWithTables([]string{tableName})
db.GetTable(tableName).AddReturnPutItemOutput(nil)

_, err := db.PutItem(&putItem)

require.NoError(t, err)
assert.Equal(t, &[]dynamodb.PutItemInput{putItem}, db.GetTable(tableName).Items())
assert.Error(t, err)
assert.Equal(t, &[]dynamodb.PutItemInput{putItem}, db.GetTable(tableName).ReceivedPutItemInputs())
})

t.Run("PutItemOutputEmpty", func(t *testing.T) {
tableName := "mockTable"
putItem := dynamodb.PutItemInput{TableName: &tableName}

db := mockdynamodb.NewWithTables([]string{tableName})

_, err := db.PutItem(&putItem)

assert.Error(t, err)
assert.Equal(t, &[]dynamodb.PutItemInput{putItem}, db.GetTable(tableName).ReceivedPutItemInputs())
})
}

Expand Down
65 changes: 65 additions & 0 deletions query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package mockdynamodb

import (
"errors"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/service/dynamodb"
)

// Query is implemented.
// Use AddReturnQueryOutput() set QueryOutput for Query() to return.
// Query() will return QueryOutputs in the same order in which AddReturnQueryOutput() is called.
// If a nil value is given to AddReturnQueryOutput() then Query() will return an error.
// Use ReceivedQueryInputs() retrieve the inputs given to Query(), use for asserting.
func (db *DynamoDb) Query(input *dynamodb.QueryInput) (*dynamodb.QueryOutput, error) {
db.Lock()
defer db.Unlock()

return db.query(input)
}

// QueryWithContext is not implemented. It will panic in all cases.
func (db *DynamoDb) QueryWithContext(aws.Context, *dynamodb.QueryInput, ...request.Option) (*dynamodb.QueryOutput, error) {
panic("QueryWithContext is not implemented")
}

// QueryRequest is not implemented. It will panic in all cases.
func (db *DynamoDb) QueryRequest(*dynamodb.QueryInput) (*request.Request, *dynamodb.QueryOutput) {
panic("QueryRequest is not implemented")
}

// QueryPages is not implemented. It will panic in all cases.
func (db *DynamoDb) QueryPages(*dynamodb.QueryInput, func(*dynamodb.QueryOutput, bool) bool) error {
panic("QueryPages is not implemented")
}

// QueryPagesWithContext is not implemented. It will panic in all cases.
func (db *DynamoDb) QueryPagesWithContext(aws.Context, *dynamodb.QueryInput, func(*dynamodb.QueryOutput, bool) bool, ...request.Option) error {
panic("QueryPagesWithContext is not implemented")
}

func (db *DynamoDb) query(input *dynamodb.QueryInput) (*dynamodb.QueryOutput, error) {
err := checkRequiredFields(map[string]interface{}{
"QueryInput.TableName": input.TableName,
})
if err != nil {
return &dynamodb.QueryOutput{}, err
}

if table := db.GetTable(*input.TableName); table != nil {
table.receivedQueryInputs = append(table.receivedQueryInputs, *input)
if len(table.returnQueryOutputs) > 0 {
o := table.popReturnQueryOutput()
if o != nil {
return o, nil
}
return nil, errors.New("nil QueryOutput")
}

return nil, errors.New("no QueryOutputs to return")
}

return &dynamodb.QueryOutput{}, errorNonExistentTable()
}
99 changes: 99 additions & 0 deletions query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package mockdynamodb_test

import (
"context"
"testing"

"github.com/aws/aws-sdk-go/service/dynamodb"

"github.com/ebh/mockdynamodb"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestDynamoDb_Query(t *testing.T) {
t.Run("TableNameNotSet", func(t *testing.T) {
tableName := "mockTable"
db := mockdynamodb.NewWithTables([]string{tableName})

_, err := db.Query(&dynamodb.QueryInput{})

assert.EqualError(t, err, "InvalidParameter: 1 validation error(s) found.\n- missing required field, QueryInput.TableName.\n")
})

t.Run("NonExistentTable", func(t *testing.T) {
tableName := "mockTable"
db := mockdynamodb.NewWithTables([]string{"anotherMockTable"})

_, err := db.Query(&dynamodb.QueryInput{TableName: &tableName})

assertRegexpError(t, err, "AWS.DynamoDB.NonExistentTable: The specified table does not exist for this wsdl version.\\n\\tstatus code: 400, request id: "+uuidRegexp+"$")
})

t.Run("QueryInputRecorded", func(t *testing.T) {
tableName := "mockTable"
QueryInput := dynamodb.QueryInput{TableName: &tableName}
QueryOutput := dynamodb.QueryOutput{}

db := mockdynamodb.NewWithTables([]string{tableName})
db.GetTable(tableName).AddReturnQueryOutput(&QueryOutput)

output, err := db.Query(&QueryInput)

assert.NoError(t, err)
assert.Equal(t, &[]dynamodb.QueryInput{QueryInput}, db.GetTable(tableName).ReceivedQueryInputs())
assert.Equal(t, &QueryOutput, output)
})

t.Run("QueryOutputIsNull", func(t *testing.T) {
tableName := "mockTable"
Query := dynamodb.QueryInput{TableName: &tableName}

db := mockdynamodb.NewWithTables([]string{tableName})
db.GetTable(tableName).AddReturnQueryOutput(nil)

_, err := db.Query(&Query)

assert.Error(t, err)
assert.Equal(t, &[]dynamodb.QueryInput{Query}, db.GetTable(tableName).ReceivedQueryInputs())
})

t.Run("QueryOutputEmpty", func(t *testing.T) {
tableName := "mockTable"
Query := dynamodb.QueryInput{TableName: &tableName}

db := mockdynamodb.NewWithTables([]string{tableName})

_, err := db.Query(&Query)

assert.Error(t, err)
assert.Equal(t, &[]dynamodb.QueryInput{Query}, db.GetTable(tableName).ReceivedQueryInputs())
})
}

func TestDynamoDb_QueryWithContext(t *testing.T) {
assert.PanicsWithValue(t, "QueryWithContext is not implemented", func() {
_, err := mockdynamodb.New().QueryWithContext(context.TODO(), nil)
require.NoError(t, err)
})
}

func TestDynamoDb_QueryRequest(t *testing.T) {
assert.PanicsWithValue(t, "QueryRequest is not implemented", func() {
mockdynamodb.New().QueryRequest(nil)
})
}

func TestDynamoDb_QueryPages(t *testing.T) {
assert.PanicsWithValue(t, "QueryPages is not implemented", func() {
err := mockdynamodb.New().QueryPages(nil, nil)
require.NoError(t, err)
})
}

func TestDynamoDb_QueryPagesWithContext(t *testing.T) {
assert.PanicsWithValue(t, "QueryPagesWithContext is not implemented", func() {
err := mockdynamodb.New().QueryPagesWithContext(context.TODO(), nil, nil)
require.NoError(t, err)
})
}
Loading

0 comments on commit d6a570e

Please sign in to comment.