sqs-browse: started working on tests

This commit is contained in:
Leon Mika 2022-03-23 22:02:46 +11:00
parent 7526c095ee
commit cff059e160
11 changed files with 516 additions and 16 deletions

View file

@ -0,0 +1,43 @@
package models
import (
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"math/big"
)
func compareScalarAttributes(x, y types.AttributeValue) (int, bool) {
switch xVal := x.(type) {
case *types.AttributeValueMemberS:
if yVal, ok := y.(*types.AttributeValueMemberS); ok {
return comparisonValue(xVal.Value == yVal.Value, xVal.Value < yVal.Value), true
}
case *types.AttributeValueMemberN:
if yVal, ok := y.(*types.AttributeValueMemberN); ok {
xNumVal, _, err := big.ParseFloat(xVal.Value, 10, 63, big.ToNearestEven)
if err != nil {
return 0, false
}
yNumVal, _, err := big.ParseFloat(yVal.Value, 10, 63, big.ToNearestEven)
if err != nil {
return 0, false
}
return xNumVal.Cmp(yNumVal), true
}
case *types.AttributeValueMemberBOOL:
if yVal, ok := y.(*types.AttributeValueMemberBOOL); ok {
return comparisonValue(xVal.Value == yVal.Value, !xVal.Value), true
}
}
return 0, false
}
func comparisonValue(isEqual bool, isLess bool) int {
if isEqual {
return 0
} else if isLess {
return -1
}
return 1
}

View file

@ -0,0 +1,55 @@
package models
import "sort"
// sortedItems is a collection of items that is sorted.
// Items are sorted based on the PK, and SK in ascending order
type sortedItems struct {
pk, sk string
items []Item
}
// Sort sorts the items in place
func Sort(items []Item, pk, sk string) {
si := sortedItems{items: items, pk: pk, sk: sk}
sort.Sort(&si)
}
func (si *sortedItems) Len() int {
return len(si.items)
}
func (si *sortedItems) Less(i, j int) bool {
// Compare primary keys
pv1, pv2 := si.items[i][si.pk], si.items[j][si.pk]
pc, ok := compareScalarAttributes(pv1, pv2)
if !ok {
return i < j
}
if pc < 0 {
return true
} else if pc > 0 {
return false
}
// Partition keys are equal, compare sort key
sv1, sv2 := si.items[i][si.sk], si.items[j][si.sk]
sc, ok := compareScalarAttributes(sv1, sv2)
if !ok {
return i < j
}
if sc < 0 {
return true
} else if sc > 0 {
return false
}
// This should never happen, but just in case
return i < j
}
func (si *sortedItems) Swap(i, j int) {
si.items[j], si.items[i] = si.items[i], si.items[j]
}

View file

@ -0,0 +1,103 @@
package models_test
import (
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/lmika/awstools/internal/dynamo-browse/models"
"github.com/stretchr/testify/assert"
"testing"
)
func TestSort(t *testing.T) {
t.Run("pk and sk are both strings", func(t *testing.T) {
items := make([]models.Item, len(testStringData))
copy(items, testStringData)
models.Sort(items, "pk", "sk")
assert.Equal(t, items[0], testStringData[1])
assert.Equal(t, items[1], testStringData[2])
assert.Equal(t, items[2], testStringData[0])
})
t.Run("pk and sk are both numbers", func(t *testing.T) {
items := make([]models.Item, len(testNumberData))
copy(items, testNumberData)
models.Sort(items, "pk", "sk")
assert.Equal(t, items[0], testNumberData[2])
assert.Equal(t, items[1], testNumberData[1])
assert.Equal(t, items[2], testNumberData[0])
})
t.Run("pk and sk are both bools", func(t *testing.T) {
items := make([]models.Item, len(testBoolData))
copy(items, testBoolData)
models.Sort(items, "pk", "sk")
assert.Equal(t, items[0], testBoolData[2])
assert.Equal(t, items[1], testBoolData[1])
assert.Equal(t, items[2], testBoolData[0])
})
}
var testStringData = []models.Item{
{
"pk": &types.AttributeValueMemberS{Value: "bbb"},
"sk": &types.AttributeValueMemberS{Value: "131"},
"beta": &types.AttributeValueMemberN{Value: "2468"},
"gamma": &types.AttributeValueMemberS{Value: "foobar"},
},
{
"pk": &types.AttributeValueMemberS{Value: "abc"},
"sk": &types.AttributeValueMemberS{Value: "111"},
"alpha": &types.AttributeValueMemberS{Value: "This is some value"},
},
{
"pk": &types.AttributeValueMemberS{Value: "abc"},
"sk": &types.AttributeValueMemberS{Value: "222"},
"alpha": &types.AttributeValueMemberS{Value: "This is another some value"},
"beta": &types.AttributeValueMemberN{Value: "2468"},
},
}
var testNumberData = []models.Item{
{
"pk": &types.AttributeValueMemberN{Value: "1141"},
"sk": &types.AttributeValueMemberN{Value: "1111"},
"beta": &types.AttributeValueMemberN{Value: "2468"},
"gamma": &types.AttributeValueMemberS{Value: "foobar"},
},
{
"pk": &types.AttributeValueMemberN{Value: "1141"},
"sk": &types.AttributeValueMemberN{Value: "111.5"},
"alpha": &types.AttributeValueMemberS{Value: "This is some value"},
},
{
"pk": &types.AttributeValueMemberN{Value: "5"},
"sk": &types.AttributeValueMemberN{Value: "222"},
"alpha": &types.AttributeValueMemberS{Value: "This is another some value"},
"beta": &types.AttributeValueMemberN{Value: "2468"},
},
}
var testBoolData = []models.Item{
{
"pk": &types.AttributeValueMemberBOOL{Value: true},
"sk": &types.AttributeValueMemberBOOL{Value: true},
"beta": &types.AttributeValueMemberN{Value: "2468"},
"gamma": &types.AttributeValueMemberS{Value: "foobar"},
},
{
"pk": &types.AttributeValueMemberBOOL{Value: true},
"sk": &types.AttributeValueMemberBOOL{Value: false},
"alpha": &types.AttributeValueMemberS{Value: "This is some value"},
},
{
"pk": &types.AttributeValueMemberBOOL{Value: false},
"sk": &types.AttributeValueMemberBOOL{Value: false},
"alpha": &types.AttributeValueMemberS{Value: "This is another some value"},
"beta": &types.AttributeValueMemberN{Value: "2468"},
},
}

View file

@ -0,0 +1,113 @@
package dynamo_test
import (
"context"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/lmika/awstools/internal/dynamo-browse/providers/dynamo"
"github.com/lmika/awstools/test/testdynamo"
"github.com/stretchr/testify/assert"
"testing"
)
func TestProvider_ScanItems(t *testing.T) {
tableName := "test-table"
client := testdynamo.SetupTestTable(t, tableName, testData)
provider := dynamo.NewProvider(client)
t.Run("should return scanned items from the table", func(t *testing.T) {
ctx := context.Background()
items, err := provider.ScanItems(ctx, tableName)
assert.NoError(t, err)
assert.Len(t, items, 3)
assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0]))
assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[1]))
assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[2]))
})
t.Run("should return error if table name does not exist", func(t *testing.T) {
ctx := context.Background()
items, err := provider.ScanItems(ctx, "does-not-exist")
assert.Error(t, err)
assert.Nil(t, items)
})
}
func TestProvider_DeleteItem(t *testing.T) {
tableName := "test-table"
t.Run("should delete item if exists in table", func(t *testing.T) {
client := testdynamo.SetupTestTable(t, tableName, testData)
provider := dynamo.NewProvider(client)
ctx := context.Background()
err := provider.DeleteItem(ctx, tableName, map[string]types.AttributeValue{
"pk": &types.AttributeValueMemberS{Value: "abc"},
"sk": &types.AttributeValueMemberS{Value: "222"},
})
items, err := provider.ScanItems(ctx, tableName)
assert.NoError(t, err)
assert.Len(t, items, 2)
assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0]))
assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[2]))
assert.NotContains(t, items, testdynamo.TestRecordAsItem(t, testData[1]))
})
t.Run("should do nothing if key does not exist", func(t *testing.T) {
client := testdynamo.SetupTestTable(t, tableName, testData)
provider := dynamo.NewProvider(client)
ctx := context.Background()
err := provider.DeleteItem(ctx, tableName, map[string]types.AttributeValue{
"pk": &types.AttributeValueMemberS{Value: "zyx"},
"sk": &types.AttributeValueMemberS{Value: "999"},
})
items, err := provider.ScanItems(ctx, tableName)
assert.NoError(t, err)
assert.Len(t, items, 3)
assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0]))
assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[1]))
assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[2]))
})
t.Run("should return error if table name does not exist", func(t *testing.T) {
client := testdynamo.SetupTestTable(t, tableName, testData)
provider := dynamo.NewProvider(client)
ctx := context.Background()
items, err := provider.ScanItems(ctx, "does-not-exist")
assert.Error(t, err)
assert.Nil(t, items)
})
}
var testData = testdynamo.TestData{
{
"pk": "abc",
"sk": "111",
"alpha": "This is some value",
},
{
"pk": "abc",
"sk": "222",
"alpha": "This is another some value",
"beta": 1231,
},
{
"pk": "bbb",
"sk": "131",
"beta": 2468,
"gamma": "foobar",
},
}

View file

@ -24,16 +24,18 @@ func (s *Service) Scan(ctx context.Context, table string) (*models.ResultSet, er
return nil, errors.Wrapf(err, "unable to scan table %v", table)
}
// Get the columns
// TODO: need to get PKs and SKs from table
pk, sk := "pk", "sk"
// Get the columns
seenColumns := make(map[string]int)
seenColumns["pk"] = 0
seenColumns["sk"] = 1
seenColumns[pk] = 0
seenColumns[sk] = 1
for _, result := range results {
for k := range result {
if _, isSeen := seenColumns[k]; !isSeen {
seenColumns[k] = len(seenColumns)
seenColumns[k] = 2
}
}
}
@ -43,12 +45,17 @@ func (s *Service) Scan(ctx context.Context, table string) (*models.ResultSet, er
columns = append(columns, k)
}
sort.Slice(columns, func(i, j int) bool {
if seenColumns[columns[i]] == seenColumns[columns[j]] {
return columns[i] < columns[j]
}
return seenColumns[columns[i]] < seenColumns[columns[j]]
})
models.Sort(results, pk, sk)
return &models.ResultSet{
Columns: columns,
Items: results,
Items: results,
}, nil
}

View file

@ -0,0 +1,51 @@
package tables_test
import (
"context"
"github.com/lmika/awstools/internal/dynamo-browse/providers/dynamo"
"github.com/lmika/awstools/internal/dynamo-browse/services/tables"
"github.com/lmika/awstools/test/testdynamo"
"github.com/stretchr/testify/assert"
"testing"
)
func TestService_Scan(t *testing.T) {
tableName := "test-table"
client := testdynamo.SetupTestTable(t, tableName, testData)
provider := dynamo.NewProvider(client)
t.Run("return all columns and fields in sorted order", func(t *testing.T) {
ctx := context.Background()
service := tables.NewService(provider)
rs, err := service.Scan(ctx, tableName)
assert.NoError(t, err)
// Hash first, then range, then columns in alphabetic order
assert.Equal(t, rs.Columns, []string{"pk", "sk", "alpha", "beta", "gamma"})
assert.Equal(t, rs.Items[0], testdynamo.TestRecordAsItem(t, testData[1]))
assert.Equal(t, rs.Items[1], testdynamo.TestRecordAsItem(t, testData[0]))
assert.Equal(t, rs.Items[2], testdynamo.TestRecordAsItem(t, testData[2]))
})
}
var testData = testdynamo.TestData{
{
"pk": "abc",
"sk": "222",
"alpha": "This is another some value",
"beta": 1231,
},
{
"pk": "abc",
"sk": "111",
"alpha": "This is some value",
},
{
"pk": "bbb",
"sk": "131",
"beta": 2468,
"gamma": "foobar",
},
}