/
minidyn.go
200 lines (165 loc) · 5.14 KB
/
minidyn.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package client
import (
"errors"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
)
// FailureCondition describe the failure condtion to emulate
type FailureCondition string
const (
// FailureConditionNone emulates the system is working
FailureConditionNone FailureCondition = "none"
// FailureConditionInternalServerError emulates dynamodb having internal issues
FailureConditionInternalServerError FailureCondition = "internal_server"
// FailureConditionDeprecated returns the old error
FailureConditionDeprecated FailureCondition = "deprecated"
)
var (
// emulatedInternalServeError represents the error for dynamodb internal server error
emulatedInternalServeError = awserr.New(dynamodb.ErrCodeInternalServerError, "emulated error", nil)
// ErrForcedFailure when the error is forced
// Deprecated: use EmulateFailure instead
ErrForcedFailure = errors.New("forced failure response")
emulatingErrors = map[FailureCondition]error{
FailureConditionNone: nil,
FailureConditionInternalServerError: emulatedInternalServeError,
FailureConditionDeprecated: ErrForcedFailure,
}
)
// EmulateFailure forces the fake client to fail
func EmulateFailure(client dynamodbiface.DynamoDBAPI, condition FailureCondition) {
fakeClient, ok := client.(*Client)
if !ok {
panic("EmulateFailure: invalid client type")
}
fakeClient.setFailureCondition(condition)
}
// ActiveForceFailure active force operation to fail
func ActiveForceFailure(client dynamodbiface.DynamoDBAPI) {
fakeClient, ok := client.(*Client)
if !ok {
panic("ActiveForceFailure: invalid client type")
}
fakeClient.setFailureCondition(FailureConditionDeprecated)
}
// DeactiveForceFailure deactive force operation to fail
func DeactiveForceFailure(client dynamodbiface.DynamoDBAPI) {
fakeClient, ok := client.(*Client)
if !ok {
panic("DeactiveForceFailure: invalid client type")
}
fakeClient.setFailureCondition(FailureConditionNone)
}
// AddTable add a new table
func AddTable(client dynamodbiface.DynamoDBAPI, tableName, partitionKey, rangeKey string) error {
input := generateAddTableInput(tableName, partitionKey, rangeKey)
_, err := client.CreateTable(input)
return err
}
// AddIndex add a new index to the table table
func AddIndex(client dynamodbiface.DynamoDBAPI, tableName, indexName, partitionKey, rangeKey string) error {
keySchema := []*dynamodb.KeySchemaElement{
{
AttributeName: aws.String(partitionKey),
KeyType: aws.String("HASH"),
},
}
attributes := []*dynamodb.AttributeDefinition{
{
AttributeName: aws.String(partitionKey),
AttributeType: aws.String("S"),
},
}
if rangeKey != "" {
keySchema = append(keySchema, &dynamodb.KeySchemaElement{
AttributeName: aws.String(rangeKey),
KeyType: aws.String("RANGE"),
})
attributes = append(attributes, &dynamodb.AttributeDefinition{
AttributeName: aws.String(rangeKey),
AttributeType: aws.String("S"),
})
}
input := &dynamodb.UpdateTableInput{
AttributeDefinitions: attributes,
TableName: aws.String(tableName),
GlobalSecondaryIndexUpdates: []*dynamodb.GlobalSecondaryIndexUpdate{
{
Create: &dynamodb.CreateGlobalSecondaryIndexAction{
IndexName: aws.String(indexName),
KeySchema: keySchema,
Projection: &dynamodb.Projection{
ProjectionType: aws.String("ALL"),
},
},
},
},
}
_, err := client.UpdateTable(input)
return err
}
// ClearTable removes all data from a specific table
func ClearTable(client dynamodbiface.DynamoDBAPI, tableName string) error {
fakeClient, ok := client.(*Client)
if !ok {
panic("ClearTable: invalid client type")
}
table, err := fakeClient.getTable(tableName)
if err != nil {
return err
}
fakeClient.mu.Lock()
defer fakeClient.mu.Unlock()
table.Clear()
for _, index := range table.Indexes {
index.Clear()
}
return nil
}
func generateAddTableInput(tableName, hashKey, rangeKey string) *dynamodb.CreateTableInput {
var cunit int64 = 10
input := &dynamodb.CreateTableInput{
AttributeDefinitions: []*dynamodb.AttributeDefinition{
{
AttributeName: aws.String(hashKey),
AttributeType: aws.String("S"),
},
},
BillingMode: aws.String("PAY_PER_REQUEST"),
KeySchema: []*dynamodb.KeySchemaElement{
{
AttributeName: aws.String(hashKey),
KeyType: aws.String("HASH"),
},
},
TableName: aws.String(tableName),
ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
ReadCapacityUnits: &cunit,
WriteCapacityUnits: &cunit,
},
}
if rangeKey != "" {
input.AttributeDefinitions = append(input.AttributeDefinitions,
&dynamodb.AttributeDefinition{
AttributeName: aws.String(rangeKey),
AttributeType: aws.String("S"),
},
)
input.KeySchema = append(input.KeySchema,
&dynamodb.KeySchemaElement{
AttributeName: aws.String(rangeKey),
KeyType: aws.String("RANGE"),
},
)
}
return input
}
func copyItem(item map[string]*dynamodb.AttributeValue) map[string]*dynamodb.AttributeValue {
copy := map[string]*dynamodb.AttributeValue{}
for key, val := range item {
copy[key] = val
}
return copy
}