github.com/Jeffail/benthos/v3@v3.65.0/lib/output/writer/sqs_test.go (about) 1 package writer 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "testing" 8 9 "github.com/Jeffail/benthos/v3/lib/log" 10 "github.com/Jeffail/benthos/v3/lib/message" 11 "github.com/Jeffail/benthos/v3/lib/metrics" 12 "github.com/Jeffail/benthos/v3/lib/types" 13 "github.com/aws/aws-sdk-go/aws" 14 "github.com/aws/aws-sdk-go/service/sqs" 15 "github.com/aws/aws-sdk-go/service/sqs/sqsiface" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 func TestSQSHeaderCheck(t *testing.T) { 21 type testCase struct { 22 k, v string 23 expected bool 24 } 25 26 tests := []testCase{ 27 { 28 k: "foo", v: "bar", 29 expected: true, 30 }, 31 { 32 k: "foo.bar", v: "bar.baz", 33 expected: true, 34 }, 35 { 36 k: "foo_bar", v: "bar_baz", 37 expected: true, 38 }, 39 { 40 k: "foo-bar", v: "bar-baz", 41 expected: true, 42 }, 43 { 44 k: ".foo", v: "bar", 45 expected: false, 46 }, 47 { 48 k: "foo", v: ".bar", 49 expected: true, 50 }, 51 { 52 k: "f..oo", v: "bar", 53 expected: false, 54 }, 55 { 56 k: "foo", v: "ba..r", 57 expected: true, 58 }, 59 { 60 k: "aws.foo", v: "bar", 61 expected: false, 62 }, 63 { 64 k: "amazon.foo", v: "bar", 65 expected: false, 66 }, 67 { 68 k: "foo.", v: "bar", 69 expected: false, 70 }, 71 { 72 k: "foo", v: "bar.", 73 expected: true, 74 }, 75 { 76 k: "fo$o", v: "bar", 77 expected: false, 78 }, 79 { 80 k: "foo", v: "ba$r", 81 expected: true, 82 }, 83 { 84 k: "foo_with_10_numbers", v: "bar", 85 expected: true, 86 }, 87 { 88 k: "foo", v: "bar_with_10_numbers and a space", 89 expected: true, 90 }, 91 { 92 k: "foo with space", v: "bar", 93 expected: false, 94 }, 95 { 96 k: "iso_date", v: "1997-07-16T19:20:30.45+01:00", 97 expected: true, 98 }, 99 { 100 k: "has_a_char_in_the_valid_range", v: "#x9 | #xA | #xD | #x20 to #xD7FF | #xE000 to #xFFFD | #x10000 to #x10FFFF - Ѱ", 101 expected: true, 102 }, 103 } 104 105 for i, test := range tests { 106 if act, exp := isValidSQSAttribute(test.k, test.v), test.expected; act != exp { 107 t.Errorf("Unexpected result for test '%v': %v != %v", i, act, exp) 108 } 109 } 110 } 111 112 type mockSqs struct { 113 sqsiface.SQSAPI 114 fn func(*sqs.SendMessageBatchInput) (*sqs.SendMessageBatchOutput, error) 115 } 116 117 func (m *mockSqs) SendMessageBatch(input *sqs.SendMessageBatchInput) (*sqs.SendMessageBatchOutput, error) { 118 return m.fn(input) 119 } 120 121 type inMsg struct { 122 id string 123 content string 124 } 125 type inEntries []inMsg 126 127 func TestSQSRetries(t *testing.T) { 128 tCtx := context.Background() 129 130 conf := NewAmazonSQSConfig() 131 w, err := NewAmazonSQSV2(conf, types.NoopMgr(), log.Noop(), metrics.Noop()) 132 require.NoError(t, err) 133 134 var in []inEntries 135 var out []*sqs.SendMessageBatchOutput 136 w.sqs = &mockSqs{ 137 fn: func(smbi *sqs.SendMessageBatchInput) (*sqs.SendMessageBatchOutput, error) { 138 var e inEntries 139 for _, entry := range smbi.Entries { 140 e = append(e, inMsg{ 141 id: *entry.Id, 142 content: *entry.MessageBody, 143 }) 144 } 145 in = append(in, e) 146 147 if len(out) == 0 { 148 return nil, errors.New("ran out of mock outputs") 149 } 150 outBatch := out[0] 151 out = out[1:] 152 return outBatch, nil 153 }, 154 } 155 156 out = []*sqs.SendMessageBatchOutput{ 157 { 158 Failed: []*sqs.BatchResultErrorEntry{ 159 { 160 Code: aws.String("xx"), 161 Id: aws.String("1"), 162 Message: aws.String("test error"), 163 SenderFault: aws.Bool(false), 164 }, 165 }, 166 }, 167 {}, 168 } 169 170 inMsg := message.New([][]byte{ 171 []byte("hello world 1"), 172 []byte("hello world 2"), 173 []byte("hello world 3"), 174 }) 175 require.NoError(t, w.WriteWithContext(tCtx, inMsg)) 176 177 assert.Equal(t, []inEntries{ 178 { 179 {id: "0", content: "hello world 1"}, 180 {id: "1", content: "hello world 2"}, 181 {id: "2", content: "hello world 3"}, 182 }, 183 { 184 {id: "1", content: "hello world 2"}, 185 }, 186 }, in) 187 } 188 189 func TestSQSSendLimit(t *testing.T) { 190 tCtx := context.Background() 191 192 conf := NewAmazonSQSConfig() 193 w, err := NewAmazonSQSV2(conf, types.NoopMgr(), log.Noop(), metrics.Noop()) 194 require.NoError(t, err) 195 196 var in []inEntries 197 var out []*sqs.SendMessageBatchOutput 198 w.sqs = &mockSqs{ 199 fn: func(smbi *sqs.SendMessageBatchInput) (*sqs.SendMessageBatchOutput, error) { 200 var e inEntries 201 for _, entry := range smbi.Entries { 202 e = append(e, inMsg{ 203 id: *entry.Id, 204 content: *entry.MessageBody, 205 }) 206 } 207 in = append(in, e) 208 209 if len(out) == 0 { 210 return nil, errors.New("ran out of mock outputs") 211 } 212 outBatch := out[0] 213 out = out[1:] 214 return outBatch, nil 215 }, 216 } 217 218 out = []*sqs.SendMessageBatchOutput{ 219 {}, {}, 220 } 221 222 inMsg := message.New(nil) 223 for i := 0; i < 15; i++ { 224 inMsg.Append(message.NewPart([]byte(fmt.Sprintf("hello world %v", i+1)))) 225 } 226 require.NoError(t, w.WriteWithContext(tCtx, inMsg)) 227 228 assert.Equal(t, []inEntries{ 229 { 230 {id: "0", content: "hello world 1"}, 231 {id: "1", content: "hello world 2"}, 232 {id: "2", content: "hello world 3"}, 233 {id: "3", content: "hello world 4"}, 234 {id: "4", content: "hello world 5"}, 235 {id: "5", content: "hello world 6"}, 236 {id: "6", content: "hello world 7"}, 237 {id: "7", content: "hello world 8"}, 238 {id: "8", content: "hello world 9"}, 239 {id: "9", content: "hello world 10"}, 240 }, 241 { 242 {id: "10", content: "hello world 11"}, 243 {id: "11", content: "hello world 12"}, 244 {id: "12", content: "hello world 13"}, 245 {id: "13", content: "hello world 14"}, 246 {id: "14", content: "hello world 15"}, 247 }, 248 }, in) 249 }