github.com/Jeffail/benthos/v3@v3.65.0/lib/input/reader/amqp_1_test.go (about) 1 package reader 2 3 import ( 4 "context" 5 "flag" 6 "fmt" 7 "os" 8 "regexp" 9 "strings" 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/Azure/go-amqp" 15 "github.com/Jeffail/benthos/v3/lib/log" 16 "github.com/Jeffail/benthos/v3/lib/metrics" 17 "github.com/Jeffail/benthos/v3/lib/response" 18 "github.com/Jeffail/benthos/v3/lib/types" 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 ) 22 23 func TestAMQP1Integration(t *testing.T) { 24 if m := flag.Lookup("test.run").Value.String(); m == "" || regexp.MustCompile(strings.Split(m, "/")[0]).FindString(t.Name()) == "" { 25 t.Skip("Skipping as execution was not requested explicitly using go test -run ^TestIntegration$") 26 } 27 28 if testing.Short() { 29 t.Skip("Skipping integration test in short mode") 30 } 31 32 url := os.Getenv("TEST_SB_URL") 33 sourceAddress := os.Getenv("TEST_SB_SOURCE_ADDRESS") 34 if url == "" || sourceAddress == "" { 35 t.Skip("Skipping because of missing TEST_SB_URL or TEST_SB_SOURCE_ADDRESS. Those should be point to Azure Service Bus configured with Message lock duration to 5 seconds.") 36 } 37 38 t.Run("TestAMQP1Connected", func(t *testing.T) { 39 testAMQP1Connected(url, sourceAddress, t) 40 }) 41 t.Run("TestAMQP1Disconnected", func(t *testing.T) { 42 testAMQP1Disconnected(url, sourceAddress, t) 43 }) 44 } 45 46 func testAMQP1Connected(url, sourceAddress string, t *testing.T) { 47 ctx := context.Background() 48 49 conf := NewAMQP1Config() 50 conf.URL = url 51 conf.SourceAddress = sourceAddress 52 conf.AzureRenewLock = true 53 54 m, err := NewAMQP1(conf, log.Noop(), metrics.Noop()) 55 require.NoError(t, err) 56 57 err = m.ConnectWithContext(ctx) 58 require.NoError(t, err) 59 60 defer func() { 61 m.CloseAsync() 62 err := m.WaitForClose(time.Second) 63 assert.NoError(t, err) 64 }() 65 66 client, err := amqp.Dial(url) 67 require.NoError(t, err) 68 defer client.Close() 69 70 session, err := client.NewSession() 71 require.NoError(t, err) 72 defer session.Close(ctx) 73 74 sender, err := session.NewSender( 75 amqp.LinkTargetAddress("/test"), 76 ) 77 require.NoError(t, err) 78 defer sender.Close(ctx) 79 80 N := 10 81 wg := sync.WaitGroup{} 82 83 testMsgs := map[string]bool{} 84 for i := 0; i < N; i++ { 85 wg.Add(1) 86 87 str := fmt.Sprintf("hello world: %v", i) 88 testMsgs[str] = true 89 go func(testStr string) { 90 defer wg.Done() 91 92 contentType := "plain/text" 93 contentEncoding := "utf-8" 94 createdAt := time.Date(2020, time.January, 30, 1, 0, 0, 0, time.UTC) 95 err := sender.Send(ctx, &amqp.Message{ 96 Properties: &amqp.MessageProperties{ 97 ContentType: &contentType, 98 ContentEncoding: &contentEncoding, 99 CreationTime: &createdAt, 100 }, 101 Data: [][]byte{[]byte(str)}, 102 }) 103 require.NoError(t, err) 104 }(str) 105 } 106 107 for i := 0; i < N; i++ { 108 actM, ackFn, err := m.ReadWithContext(ctx) 109 assert.NoError(t, err) 110 wg.Add(1) 111 112 go func() { 113 defer wg.Done() 114 115 assert.True(t, testMsgs[string(actM.Get(0).Get())], "Unexpected message") 116 assert.Equal(t, "plain/text", actM.Get(0).Metadata().Get("amqp_content_type")) 117 assert.Equal(t, "utf-8", actM.Get(0).Metadata().Get("amqp_content_encoding")) 118 119 time.Sleep(6 * time.Second) // Simulate long processing before ack so message lock expires and lock renewal is requires 120 121 assert.NoError(t, ackFn(ctx, response.NewAck())) 122 }() 123 } 124 wg.Wait() 125 126 readCtx, cancel := context.WithTimeout(ctx, 3*time.Second) 127 defer cancel() 128 _, _, err = m.ReadWithContext(readCtx) 129 assert.Error(t, err, "got unexpected message (redelivery?)") 130 131 } 132 133 func testAMQP1Disconnected(url, sourceAddress string, t *testing.T) { 134 ctx := context.Background() 135 136 conf := NewAMQP1Config() 137 conf.URL = url 138 conf.SourceAddress = sourceAddress 139 conf.AzureRenewLock = true 140 141 m, err := NewAMQP1(conf, log.Noop(), metrics.Noop()) 142 require.NoError(t, err) 143 144 err = m.ConnectWithContext(ctx) 145 require.NoError(t, err) 146 147 wg := sync.WaitGroup{} 148 wg.Add(1) 149 go func() { 150 m.CloseAsync() 151 err := m.WaitForClose(time.Second) 152 require.NoError(t, err) 153 wg.Done() 154 }() 155 156 if _, _, err = m.ReadWithContext(ctx); err != types.ErrTypeClosed && err != types.ErrNotConnected { 157 t.Errorf("Wrong error: %v != %v", err, types.ErrTypeClosed) 158 } 159 160 wg.Wait() 161 }