convert twilio unit test from groovy to java (#13077)
Co-authored-by: Jean Bisutti <jean.bisutti@gmail.com> Co-authored-by: Jay DeLuca <jaydeluca4@gmail.com>
This commit is contained in:
parent
e210c0ea02
commit
9e70f93d35
|
@ -1,628 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package test
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.twilio.Twilio
|
||||
import com.twilio.exception.ApiException
|
||||
import com.twilio.http.NetworkHttpClient
|
||||
import com.twilio.http.Response
|
||||
import com.twilio.http.TwilioRestClient
|
||||
import com.twilio.rest.api.v2010.account.Call
|
||||
import com.twilio.rest.api.v2010.account.Message
|
||||
import com.twilio.type.PhoneNumber
|
||||
|
||||
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
|
||||
import io.opentelemetry.semconv.ServerAttributes
|
||||
import io.opentelemetry.semconv.ErrorAttributes
|
||||
import io.opentelemetry.semconv.HttpAttributes
|
||||
import io.opentelemetry.semconv.NetworkAttributes
|
||||
import io.opentelemetry.semconv.UrlAttributes
|
||||
import org.apache.http.HttpEntity
|
||||
import org.apache.http.StatusLine
|
||||
import org.apache.http.client.methods.CloseableHttpResponse
|
||||
import org.apache.http.impl.client.CloseableHttpClient
|
||||
import org.apache.http.impl.client.HttpClientBuilder
|
||||
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import static io.opentelemetry.api.trace.SpanKind.CLIENT
|
||||
import static io.opentelemetry.api.trace.StatusCode.ERROR
|
||||
|
||||
class TwilioClientTest extends AgentInstrumentationSpecification {
|
||||
final static String ACCOUNT_SID = "abc"
|
||||
final static String AUTH_TOKEN = "efg"
|
||||
|
||||
final static String MESSAGE_RESPONSE_BODY = """
|
||||
{
|
||||
"account_sid": "AC14984e09e497506cf0d5eb59b1f6ace7",
|
||||
"api_version": "2010-04-01",
|
||||
"body": "Hello, World!",
|
||||
"date_created": "Thu, 30 Jul 2015 20:12:31 +0000",
|
||||
"date_sent": "Thu, 30 Jul 2015 20:12:33 +0000",
|
||||
"date_updated": "Thu, 30 Jul 2015 20:12:33 +0000",
|
||||
"direction": "outbound-api",
|
||||
"from": "+14155552345",
|
||||
"messaging_service_sid": "MGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"num_media": "0",
|
||||
"num_segments": "1",
|
||||
"price": -0.00750,
|
||||
"price_unit": "USD",
|
||||
"sid": "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"status": "sent",
|
||||
"subresource_uris": {
|
||||
"media": "/2010-04-01/Accounts/AC14984e09e497506cf0d5eb59b1f6ace7/Messages/SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Media.json"
|
||||
},
|
||||
"to": "+14155552345",
|
||||
"uri": "/2010-04-01/Accounts/AC14984e09e497506cf0d5eb59b1f6ace7/Messages/SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.json"
|
||||
}
|
||||
"""
|
||||
|
||||
final static String CALL_RESPONSE_BODY = """
|
||||
{
|
||||
"account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"annotation": null,
|
||||
"answered_by": null,
|
||||
"api_version": "2010-04-01",
|
||||
"caller_name": null,
|
||||
"date_created": "Tue, 31 Aug 2010 20:36:28 +0000",
|
||||
"date_updated": "Tue, 31 Aug 2010 20:36:44 +0000",
|
||||
"direction": "inbound",
|
||||
"duration": "15",
|
||||
"end_time": "Tue, 31 Aug 2010 20:36:44 +0000",
|
||||
"forwarded_from": "+141586753093",
|
||||
"from": "+15017122661",
|
||||
"from_formatted": "(501) 712-2661",
|
||||
"group_sid": null,
|
||||
"parent_call_sid": null,
|
||||
"phone_number_sid": "PNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"price": -0.03000,
|
||||
"price_unit": "USD",
|
||||
"sid": "CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"start_time": "Tue, 31 Aug 2010 20:36:29 +0000",
|
||||
"status": "completed",
|
||||
"subresource_uris": {
|
||||
"notifications": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Notifications.json",
|
||||
"recordings": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Recordings.json",
|
||||
"feedback": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Feedback.json",
|
||||
"feedback_summaries": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/FeedbackSummary.json"
|
||||
},
|
||||
"to": "+15558675310",
|
||||
"to_formatted": "(555) 867-5310",
|
||||
"uri": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.json"
|
||||
}
|
||||
"""
|
||||
|
||||
final static String ERROR_RESPONSE_BODY = """
|
||||
{
|
||||
"code": 123,
|
||||
"message": "Testing Failure",
|
||||
"code": 567,
|
||||
"more_info": "Testing"
|
||||
}
|
||||
"""
|
||||
|
||||
TwilioRestClient twilioRestClient = Mock()
|
||||
|
||||
def setupSpec() {
|
||||
Twilio.init(ACCOUNT_SID, AUTH_TOKEN)
|
||||
}
|
||||
|
||||
def cleanup() {
|
||||
Twilio.getExecutorService().shutdown()
|
||||
Twilio.setExecutorService(null)
|
||||
Twilio.setRestClient(null)
|
||||
}
|
||||
|
||||
def "synchronous message"() {
|
||||
setup:
|
||||
twilioRestClient.getObjectMapper() >> new ObjectMapper()
|
||||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(MESSAGE_RESPONSE_BODY.getBytes()), 200)
|
||||
|
||||
Message message = runWithSpan("test") {
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).create(twilioRestClient)
|
||||
}
|
||||
|
||||
expect:
|
||||
|
||||
message.body == "Hello, World!"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
span(0) {
|
||||
name "test"
|
||||
hasNoParent()
|
||||
attributes {
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name "MessageCreator.create"
|
||||
kind CLIENT
|
||||
attributes {
|
||||
"twilio.type" "com.twilio.rest.api.v2010.account.Message"
|
||||
"twilio.account" "AC14984e09e497506cf0d5eb59b1f6ace7"
|
||||
"twilio.sid" "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"twilio.status" "sent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "synchronous call"() {
|
||||
setup:
|
||||
twilioRestClient.getObjectMapper() >> new ObjectMapper()
|
||||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(CALL_RESPONSE_BODY.getBytes()), 200)
|
||||
|
||||
Call call = runWithSpan("test") {
|
||||
Call.creator(
|
||||
new PhoneNumber("+15558881234"), // To number
|
||||
new PhoneNumber("+15559994321"), // From number
|
||||
|
||||
// Read TwiML at this URL when a call connects (hold music)
|
||||
new URI("http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient")
|
||||
).create(twilioRestClient)
|
||||
}
|
||||
|
||||
expect:
|
||||
|
||||
call.status == Call.Status.COMPLETED
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
span(0) {
|
||||
name "test"
|
||||
hasNoParent()
|
||||
attributes {
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name "CallCreator.create"
|
||||
kind CLIENT
|
||||
attributes {
|
||||
"twilio.type" "com.twilio.rest.api.v2010.account.Call"
|
||||
"twilio.account" "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"twilio.sid" "CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"twilio.status" "completed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "http client"() {
|
||||
setup:
|
||||
CloseableHttpClient httpClient = Mock()
|
||||
httpClient.execute(_) >> mockResponse(MESSAGE_RESPONSE_BODY, 200)
|
||||
|
||||
HttpClientBuilder clientBuilder = Mock()
|
||||
clientBuilder.build() >> httpClient
|
||||
|
||||
NetworkHttpClient networkHttpClient = new NetworkHttpClient(clientBuilder)
|
||||
|
||||
TwilioRestClient realTwilioRestClient =
|
||||
new TwilioRestClient.Builder("username", "password")
|
||||
.accountSid(ACCOUNT_SID)
|
||||
.httpClient(networkHttpClient)
|
||||
.build()
|
||||
|
||||
Message message = runWithSpan("test") {
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).create(realTwilioRestClient)
|
||||
}
|
||||
|
||||
expect:
|
||||
|
||||
message.body == "Hello, World!"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 3) {
|
||||
span(0) {
|
||||
name "test"
|
||||
hasNoParent()
|
||||
attributes {
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name "MessageCreator.create"
|
||||
kind CLIENT
|
||||
childOf(span(0))
|
||||
attributes {
|
||||
"twilio.type" "com.twilio.rest.api.v2010.account.Message"
|
||||
"twilio.account" "AC14984e09e497506cf0d5eb59b1f6ace7"
|
||||
"twilio.sid" "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"twilio.status" "sent"
|
||||
}
|
||||
}
|
||||
span(2) {
|
||||
name "POST"
|
||||
kind CLIENT
|
||||
childOf span(1)
|
||||
attributes {
|
||||
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
|
||||
"$ServerAttributes.SERVER_ADDRESS.key" "api.twilio.com"
|
||||
"$HttpAttributes.HTTP_REQUEST_METHOD.key" "POST"
|
||||
"$UrlAttributes.URL_FULL.key" "https://api.twilio.com/2010-04-01/Accounts/abc/Messages.json"
|
||||
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE.key" 200
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "http client retry"() {
|
||||
setup:
|
||||
CloseableHttpClient httpClient = Mock()
|
||||
httpClient.execute(_) >>> [
|
||||
mockResponse(ERROR_RESPONSE_BODY, 500),
|
||||
mockResponse(MESSAGE_RESPONSE_BODY, 200)
|
||||
]
|
||||
|
||||
HttpClientBuilder clientBuilder = Mock()
|
||||
clientBuilder.build() >> httpClient
|
||||
|
||||
NetworkHttpClient networkHttpClient = new NetworkHttpClient(clientBuilder)
|
||||
|
||||
TwilioRestClient realTwilioRestClient =
|
||||
new TwilioRestClient.Builder("username", "password")
|
||||
.accountSid(ACCOUNT_SID)
|
||||
.httpClient(networkHttpClient)
|
||||
.build()
|
||||
|
||||
Message message = runWithSpan("test") {
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).create(realTwilioRestClient)
|
||||
}
|
||||
|
||||
expect:
|
||||
message.body == "Hello, World!"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 4) {
|
||||
span(0) {
|
||||
name "test"
|
||||
hasNoParent()
|
||||
attributes {
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name "MessageCreator.create"
|
||||
kind CLIENT
|
||||
childOf(span(0))
|
||||
attributes {
|
||||
"twilio.type" "com.twilio.rest.api.v2010.account.Message"
|
||||
"twilio.account" "AC14984e09e497506cf0d5eb59b1f6ace7"
|
||||
"twilio.sid" "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"twilio.status" "sent"
|
||||
}
|
||||
}
|
||||
span(2) {
|
||||
name "POST"
|
||||
kind CLIENT
|
||||
childOf span(1)
|
||||
status ERROR
|
||||
attributes {
|
||||
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
|
||||
"$ServerAttributes.SERVER_ADDRESS.key" "api.twilio.com"
|
||||
"$HttpAttributes.HTTP_REQUEST_METHOD.key" "POST"
|
||||
"$UrlAttributes.URL_FULL.key" "https://api.twilio.com/2010-04-01/Accounts/abc/Messages.json"
|
||||
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE.key" 500
|
||||
"$ErrorAttributes.ERROR_TYPE" "500"
|
||||
}
|
||||
}
|
||||
span(3) {
|
||||
name "POST"
|
||||
kind CLIENT
|
||||
childOf span(1)
|
||||
attributes {
|
||||
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
|
||||
"$ServerAttributes.SERVER_ADDRESS.key" "api.twilio.com"
|
||||
"$HttpAttributes.HTTP_REQUEST_METHOD.key" "POST"
|
||||
"$UrlAttributes.URL_FULL.key" "https://api.twilio.com/2010-04-01/Accounts/abc/Messages.json"
|
||||
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE.key" 200
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "http client retry async"() {
|
||||
setup:
|
||||
CloseableHttpClient httpClient = Mock()
|
||||
httpClient.execute(_) >>> [
|
||||
mockResponse(ERROR_RESPONSE_BODY, 500),
|
||||
mockResponse(MESSAGE_RESPONSE_BODY, 200)
|
||||
]
|
||||
|
||||
HttpClientBuilder clientBuilder = Mock()
|
||||
clientBuilder.build() >> httpClient
|
||||
|
||||
NetworkHttpClient networkHttpClient = new NetworkHttpClient(clientBuilder)
|
||||
|
||||
TwilioRestClient realTwilioRestClient =
|
||||
new TwilioRestClient.Builder("username", "password")
|
||||
.accountSid(ACCOUNT_SID)
|
||||
.httpClient(networkHttpClient)
|
||||
.build()
|
||||
|
||||
Message message = runWithSpan("test") {
|
||||
ListenableFuture<Message> future = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).createAsync(realTwilioRestClient)
|
||||
|
||||
try {
|
||||
return future.get(10, TimeUnit.SECONDS)
|
||||
} finally {
|
||||
// Give the future callback a chance to run
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
}
|
||||
|
||||
expect:
|
||||
message.body == "Hello, World!"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 4) {
|
||||
span(0) {
|
||||
name "test"
|
||||
hasNoParent()
|
||||
attributes {
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name "MessageCreator.createAsync"
|
||||
kind CLIENT
|
||||
childOf(span(0))
|
||||
attributes {
|
||||
"twilio.type" "com.twilio.rest.api.v2010.account.Message"
|
||||
"twilio.account" "AC14984e09e497506cf0d5eb59b1f6ace7"
|
||||
"twilio.sid" "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"twilio.status" "sent"
|
||||
}
|
||||
}
|
||||
span(2) {
|
||||
name "POST"
|
||||
kind CLIENT
|
||||
childOf span(1)
|
||||
status ERROR
|
||||
attributes {
|
||||
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
|
||||
"$ServerAttributes.SERVER_ADDRESS.key" "api.twilio.com"
|
||||
"$HttpAttributes.HTTP_REQUEST_METHOD.key" "POST"
|
||||
"$UrlAttributes.URL_FULL.key" "https://api.twilio.com/2010-04-01/Accounts/abc/Messages.json"
|
||||
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE.key" 500
|
||||
"$ErrorAttributes.ERROR_TYPE" "500"
|
||||
}
|
||||
}
|
||||
span(3) {
|
||||
name "POST"
|
||||
kind CLIENT
|
||||
childOf span(1)
|
||||
attributes {
|
||||
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
|
||||
"$ServerAttributes.SERVER_ADDRESS.key" "api.twilio.com"
|
||||
"$HttpAttributes.HTTP_REQUEST_METHOD.key" "POST"
|
||||
"$UrlAttributes.URL_FULL.key" "https://api.twilio.com/2010-04-01/Accounts/abc/Messages.json"
|
||||
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE.key" 200
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
Twilio.getExecutorService().shutdown()
|
||||
Twilio.setExecutorService(null)
|
||||
Twilio.setRestClient(null)
|
||||
}
|
||||
|
||||
def "Sync Failure"() {
|
||||
setup:
|
||||
|
||||
twilioRestClient.getObjectMapper() >> new ObjectMapper()
|
||||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(ERROR_RESPONSE_BODY.getBytes()), 500)
|
||||
|
||||
when:
|
||||
runWithSpan("test") {
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).create(twilioRestClient)
|
||||
}
|
||||
|
||||
then:
|
||||
thrown(ApiException)
|
||||
|
||||
expect:
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
span(0) {
|
||||
name "test"
|
||||
status ERROR
|
||||
errorEvent(ApiException, "Testing Failure")
|
||||
hasNoParent()
|
||||
}
|
||||
span(1) {
|
||||
name "MessageCreator.create"
|
||||
kind CLIENT
|
||||
status ERROR
|
||||
errorEvent(ApiException, "Testing Failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "root span"() {
|
||||
setup:
|
||||
twilioRestClient.getObjectMapper() >> new ObjectMapper()
|
||||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(MESSAGE_RESPONSE_BODY.getBytes()), 200)
|
||||
|
||||
Message message = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).create(twilioRestClient)
|
||||
|
||||
expect:
|
||||
|
||||
message.body == "Hello, World!"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
name "MessageCreator.create"
|
||||
kind CLIENT
|
||||
hasNoParent()
|
||||
attributes {
|
||||
"twilio.type" "com.twilio.rest.api.v2010.account.Message"
|
||||
"twilio.account" "AC14984e09e497506cf0d5eb59b1f6ace7"
|
||||
"twilio.sid" "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"twilio.status" "sent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "asynchronous call"(a) {
|
||||
setup:
|
||||
twilioRestClient.getObjectMapper() >> new ObjectMapper()
|
||||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(MESSAGE_RESPONSE_BODY.getBytes()), 200)
|
||||
|
||||
when:
|
||||
|
||||
Message message = runWithSpan("test") {
|
||||
|
||||
ListenableFuture<Message> future = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).createAsync(twilioRestClient)
|
||||
|
||||
try {
|
||||
return future.get(10, TimeUnit.SECONDS)
|
||||
} finally {
|
||||
// Give the future callback a chance to run
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
}
|
||||
|
||||
then:
|
||||
|
||||
message != null
|
||||
message.body == "Hello, World!"
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
span(0) {
|
||||
name "test"
|
||||
hasNoParent()
|
||||
attributes {
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
name "MessageCreator.createAsync"
|
||||
kind CLIENT
|
||||
attributes {
|
||||
"twilio.type" "com.twilio.rest.api.v2010.account.Message"
|
||||
"twilio.account" "AC14984e09e497506cf0d5eb59b1f6ace7"
|
||||
"twilio.sid" "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"twilio.status" "sent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
Twilio.getExecutorService().shutdown()
|
||||
Twilio.setExecutorService(null)
|
||||
Twilio.setRestClient(null)
|
||||
|
||||
where:
|
||||
a | _
|
||||
1 | _
|
||||
2 | _
|
||||
}
|
||||
|
||||
def "asynchronous error"() {
|
||||
setup:
|
||||
twilioRestClient.getObjectMapper() >> new ObjectMapper()
|
||||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(ERROR_RESPONSE_BODY.getBytes()), 500)
|
||||
|
||||
when:
|
||||
runWithSpan("test") {
|
||||
ListenableFuture<Message> future = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).createAsync(twilioRestClient)
|
||||
|
||||
try {
|
||||
return future.get(10, TimeUnit.SECONDS)
|
||||
} finally {
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
}
|
||||
|
||||
then:
|
||||
thrown(ExecutionException)
|
||||
|
||||
expect:
|
||||
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
span(0) {
|
||||
name "test"
|
||||
status ERROR
|
||||
errorEvent(ApiException, "Testing Failure")
|
||||
hasNoParent()
|
||||
}
|
||||
span(1) {
|
||||
name "MessageCreator.createAsync"
|
||||
kind CLIENT
|
||||
status ERROR
|
||||
errorEvent(ApiException, "Testing Failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CloseableHttpResponse mockResponse(String body, int statusCode) {
|
||||
HttpEntity httpEntity = Mock()
|
||||
httpEntity.getContent() >> { new ByteArrayInputStream(body.getBytes()) }
|
||||
httpEntity.isRepeatable() >> true
|
||||
httpEntity.getContentLength() >> body.length()
|
||||
|
||||
StatusLine statusLine = Mock()
|
||||
statusLine.getStatusCode() >> statusCode
|
||||
|
||||
CloseableHttpResponse httpResponse = Mock()
|
||||
httpResponse.getEntity() >> httpEntity
|
||||
httpResponse.getStatusLine() >> statusLine
|
||||
|
||||
return httpResponse
|
||||
}
|
||||
}
|
|
@ -0,0 +1,551 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.twilio;
|
||||
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
import static io.opentelemetry.api.trace.SpanKind.CLIENT;
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.twilio.Twilio;
|
||||
import com.twilio.exception.ApiException;
|
||||
import com.twilio.http.NetworkHttpClient;
|
||||
import com.twilio.http.Response;
|
||||
import com.twilio.http.TwilioRestClient;
|
||||
import com.twilio.rest.api.v2010.account.Call;
|
||||
import com.twilio.rest.api.v2010.account.Message;
|
||||
import com.twilio.type.PhoneNumber;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class TwilioClientTest {
|
||||
|
||||
@RegisterExtension
|
||||
private static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||
|
||||
private static final String ACCOUNT_SID = "abc";
|
||||
private static final String AUTH_TOKEN = "efg";
|
||||
|
||||
private static final String MESSAGE_RESPONSE_BODY =
|
||||
" {\n"
|
||||
+ " \"account_sid\": \"AC14984e09e497506cf0d5eb59b1f6ace7\",\n"
|
||||
+ " \"api_version\": \"2010-04-01\",\n"
|
||||
+ " \"body\": \"Hello, World!\",\n"
|
||||
+ " \"date_created\": \"Thu, 30 Jul 2015 20:12:31 +0000\",\n"
|
||||
+ " \"date_sent\": \"Thu, 30 Jul 2015 20:12:33 +0000\",\n"
|
||||
+ " \"date_updated\": \"Thu, 30 Jul 2015 20:12:33 +0000\",\n"
|
||||
+ " \"direction\": \"outbound-api\",\n"
|
||||
+ " \"from\": \"+14155552345\",\n"
|
||||
+ " \"messaging_service_sid\": \"MGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n"
|
||||
+ " \"num_media\": \"0\",\n"
|
||||
+ " \"num_segments\": \"1\",\n"
|
||||
+ " \"price\": -0.00750,\n"
|
||||
+ " \"price_unit\": \"USD\",\n"
|
||||
+ " \"sid\": \"MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n"
|
||||
+ " \"status\": \"sent\",\n"
|
||||
+ " \"subresource_uris\": {\n"
|
||||
+ " \"media\": \"/2010-04-01/Accounts/AC14984e09e497506cf0d5eb59b1f6ace7/Messages/SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Media.json\"\n"
|
||||
+ " },\n"
|
||||
+ " \"to\": \"+14155552345\",\n"
|
||||
+ " \"uri\": \"/2010-04-01/Accounts/AC14984e09e497506cf0d5eb59b1f6ace7/Messages/SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.json\"\n"
|
||||
+ " }";
|
||||
private static final String CALL_RESPONSE_BODY =
|
||||
" {\n"
|
||||
+ " \"account_sid\": \"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n"
|
||||
+ " \"annotation\": null,\n"
|
||||
+ " \"answered_by\": null,\n"
|
||||
+ " \"api_version\": \"2010-04-01\",\n"
|
||||
+ " \"caller_name\": null,\n"
|
||||
+ " \"date_created\": \"Tue, 31 Aug 2010 20:36:28 +0000\",\n"
|
||||
+ " \"date_updated\": \"Tue, 31 Aug 2010 20:36:44 +0000\",\n"
|
||||
+ " \"direction\": \"inbound\",\n"
|
||||
+ " \"duration\": \"15\",\n"
|
||||
+ " \"end_time\": \"Tue, 31 Aug 2010 20:36:44 +0000\",\n"
|
||||
+ " \"forwarded_from\": \"+141586753093\",\n"
|
||||
+ " \"from\": \"+15017122661\",\n"
|
||||
+ " \"from_formatted\": \"(501) 712-2661\",\n"
|
||||
+ " \"group_sid\": null,\n"
|
||||
+ " \"parent_call_sid\": null,\n"
|
||||
+ " \"phone_number_sid\": \"PNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n"
|
||||
+ " \"price\": -0.03000,\n"
|
||||
+ " \"price_unit\": \"USD\",\n"
|
||||
+ " \"sid\": \"CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n"
|
||||
+ " \"start_time\": \"Tue, 31 Aug 2010 20:36:29 +0000\",\n"
|
||||
+ " \"status\": \"completed\",\n"
|
||||
+ " \"subresource_uris\": {\n"
|
||||
+ " \"notifications\": \"/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Notifications.json\",\n"
|
||||
+ " \"recordings\": \"/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Recordings.json\",\n"
|
||||
+ " \"feedback\": \"/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Feedback.json\",\n"
|
||||
+ " \"feedback_summaries\": \"/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/FeedbackSummary.json\"\n"
|
||||
+ " },\n"
|
||||
+ " \"to\": \"+15558675310\",\n"
|
||||
+ " \"to_formatted\": \"(555) 867-5310\",\n"
|
||||
+ " \"uri\": \"/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.json\"\n"
|
||||
+ " }";
|
||||
private static final String ERROR_RESPONSE_BODY =
|
||||
"{\n"
|
||||
+ " \"code\": 123,\n"
|
||||
+ " \"message\": \"Testing Failure\",\n"
|
||||
+ " \"code\": 567,\n"
|
||||
+ " \"more_info\": \"Testing\"\n"
|
||||
+ " }";
|
||||
|
||||
@Mock private TwilioRestClient twilioRestClient;
|
||||
|
||||
@Mock private CloseableHttpClient httpClient;
|
||||
|
||||
@BeforeAll
|
||||
static void setUp() {
|
||||
Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
Twilio.getExecutorService().shutdown();
|
||||
Twilio.setExecutorService(null);
|
||||
Twilio.setRestClient(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void synchronousMessage() {
|
||||
when(twilioRestClient.getObjectMapper()).thenReturn(new ObjectMapper());
|
||||
when(twilioRestClient.request(any()))
|
||||
.thenReturn(
|
||||
new Response(
|
||||
new ByteArrayInputStream(MESSAGE_RESPONSE_BODY.getBytes(StandardCharsets.UTF_8)),
|
||||
200));
|
||||
|
||||
Message message =
|
||||
testing.runWithSpan(
|
||||
"test",
|
||||
() ->
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"),
|
||||
new PhoneNumber("+1 555 555 5215"),
|
||||
"Hello world!")
|
||||
.create(twilioRestClient));
|
||||
|
||||
assertThat(message.getBody()).isEqualTo("Hello, World!");
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("test").hasNoParent().hasAttributes(Attributes.empty()),
|
||||
span ->
|
||||
span.hasName("MessageCreator.create")
|
||||
.hasKind(CLIENT)
|
||||
.hasParent(trace.getSpan(0))
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
stringKey("twilio.type"),
|
||||
"com.twilio.rest.api.v2010.account.Message"),
|
||||
equalTo(
|
||||
stringKey("twilio.account"), "AC14984e09e497506cf0d5eb59b1f6ace7"),
|
||||
equalTo(stringKey("twilio.sid"), "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
|
||||
equalTo(stringKey("twilio.status"), "sent"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void synchronousCall() throws URISyntaxException {
|
||||
when(twilioRestClient.getObjectMapper()).thenReturn(new ObjectMapper());
|
||||
when(twilioRestClient.request(any()))
|
||||
.thenReturn(
|
||||
new Response(
|
||||
new ByteArrayInputStream(CALL_RESPONSE_BODY.getBytes(StandardCharsets.UTF_8)),
|
||||
200));
|
||||
|
||||
Call call =
|
||||
testing.runWithSpan(
|
||||
"test",
|
||||
() ->
|
||||
Call.creator(
|
||||
new PhoneNumber("+15558881234"),
|
||||
new PhoneNumber("+15559994321"),
|
||||
new URI("http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient"))
|
||||
.create(twilioRestClient));
|
||||
|
||||
assertThat(call.getStatus()).isEqualTo(Call.Status.COMPLETED);
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("test").hasNoParent().hasAttributes(Attributes.empty()),
|
||||
span ->
|
||||
span.hasName("CallCreator.create")
|
||||
.hasKind(CLIENT)
|
||||
.hasParent(trace.getSpan(0))
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
stringKey("twilio.type"), "com.twilio.rest.api.v2010.account.Call"),
|
||||
equalTo(
|
||||
stringKey("twilio.account"), "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
|
||||
equalTo(stringKey("twilio.sid"), "CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
|
||||
equalTo(stringKey("twilio.status"), "completed"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void httpClient() throws IOException {
|
||||
CloseableHttpResponse response = mockResponse(MESSAGE_RESPONSE_BODY, 200);
|
||||
when(httpClient.execute(any())).thenReturn(response);
|
||||
|
||||
HttpClientBuilder clientBuilder = getHttpClientBuilder(httpClient);
|
||||
|
||||
NetworkHttpClient networkHttpClient = new NetworkHttpClient(clientBuilder);
|
||||
|
||||
TwilioRestClient realTwilioRestClient =
|
||||
new TwilioRestClient.Builder("username", "password")
|
||||
.accountSid(ACCOUNT_SID)
|
||||
.httpClient(networkHttpClient)
|
||||
.build();
|
||||
|
||||
Message message =
|
||||
testing.runWithSpan(
|
||||
"test",
|
||||
() ->
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"),
|
||||
new PhoneNumber("+1 555 555 5215"),
|
||||
"Hello world!")
|
||||
.create(realTwilioRestClient));
|
||||
|
||||
assertThat(message.getBody()).isEqualTo("Hello, World!");
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("test").hasNoParent().hasAttributes(Attributes.empty()),
|
||||
span ->
|
||||
span.hasName("MessageCreator.create")
|
||||
.hasKind(CLIENT)
|
||||
.hasParent(trace.getSpan(0))
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
stringKey("twilio.type"),
|
||||
"com.twilio.rest.api.v2010.account.Message"),
|
||||
equalTo(
|
||||
stringKey("twilio.account"), "AC14984e09e497506cf0d5eb59b1f6ace7"),
|
||||
equalTo(stringKey("twilio.sid"), "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
|
||||
equalTo(stringKey("twilio.status"), "sent"))));
|
||||
}
|
||||
|
||||
@SuppressWarnings("CannotMockMethod")
|
||||
private static @NotNull HttpClientBuilder getHttpClientBuilder(CloseableHttpClient httpClient) {
|
||||
HttpClientBuilder clientBuilder = spy(HttpClientBuilder.create());
|
||||
when(clientBuilder.build()).thenReturn(httpClient);
|
||||
return clientBuilder;
|
||||
}
|
||||
|
||||
@Test
|
||||
void httpClientRetry() throws IOException {
|
||||
CloseableHttpResponse response1 = mockResponse(ERROR_RESPONSE_BODY, 500);
|
||||
CloseableHttpResponse response2 = mockResponse(MESSAGE_RESPONSE_BODY, 200);
|
||||
when(httpClient.execute(any())).thenReturn(response1, response2);
|
||||
|
||||
HttpClientBuilder clientBuilder = getHttpClientBuilder(httpClient);
|
||||
|
||||
NetworkHttpClient networkHttpClient = new NetworkHttpClient(clientBuilder);
|
||||
|
||||
TwilioRestClient realTwilioRestClient =
|
||||
new TwilioRestClient.Builder("username", "password")
|
||||
.accountSid(ACCOUNT_SID)
|
||||
.httpClient(networkHttpClient)
|
||||
.build();
|
||||
|
||||
Message message =
|
||||
testing.runWithSpan(
|
||||
"test",
|
||||
() ->
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"),
|
||||
new PhoneNumber("+1 555 555 5215"),
|
||||
"Hello world!")
|
||||
.create(realTwilioRestClient));
|
||||
|
||||
assertThat(message.getBody()).isEqualTo("Hello, World!");
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("test").hasNoParent().hasAttributes(Attributes.empty()),
|
||||
span ->
|
||||
span.hasName("MessageCreator.create")
|
||||
.hasParent(trace.getSpan(0))
|
||||
.hasKind(CLIENT)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
stringKey("twilio.type"),
|
||||
"com.twilio.rest.api.v2010.account.Message"),
|
||||
equalTo(
|
||||
stringKey("twilio.account"), "AC14984e09e497506cf0d5eb59b1f6ace7"),
|
||||
equalTo(stringKey("twilio.sid"), "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
|
||||
equalTo(stringKey("twilio.status"), "sent"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void httpClientRetryAsync() throws Exception {
|
||||
CloseableHttpResponse response1 = mockResponse(ERROR_RESPONSE_BODY, 500);
|
||||
CloseableHttpResponse response2 = mockResponse(MESSAGE_RESPONSE_BODY, 200);
|
||||
when(httpClient.execute(any())).thenReturn(response1, response2);
|
||||
|
||||
HttpClientBuilder clientBuilder = getHttpClientBuilder(httpClient);
|
||||
|
||||
NetworkHttpClient networkHttpClient = new NetworkHttpClient(clientBuilder);
|
||||
|
||||
TwilioRestClient realTwilioRestClient =
|
||||
new TwilioRestClient.Builder("username", "password")
|
||||
.accountSid(ACCOUNT_SID)
|
||||
.httpClient(networkHttpClient)
|
||||
.build();
|
||||
|
||||
Message message =
|
||||
testing.runWithSpan(
|
||||
"test",
|
||||
() -> {
|
||||
ListenableFuture<Message> future =
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"),
|
||||
new PhoneNumber("+1 555 555 5215"),
|
||||
"Hello world!")
|
||||
.createAsync(realTwilioRestClient);
|
||||
|
||||
try {
|
||||
return future.get(10, TimeUnit.SECONDS);
|
||||
} finally {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
});
|
||||
|
||||
assertThat(message.getBody()).isEqualTo("Hello, World!");
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("test").hasNoParent().hasAttributes(Attributes.empty()),
|
||||
span ->
|
||||
span.hasName("MessageCreator.createAsync")
|
||||
.hasKind(CLIENT)
|
||||
.hasParent(trace.getSpan(0))
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
stringKey("twilio.type"),
|
||||
"com.twilio.rest.api.v2010.account.Message"),
|
||||
equalTo(
|
||||
stringKey("twilio.account"), "AC14984e09e497506cf0d5eb59b1f6ace7"),
|
||||
equalTo(stringKey("twilio.sid"), "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
|
||||
equalTo(stringKey("twilio.status"), "sent"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void syncFailure() {
|
||||
when(twilioRestClient.getObjectMapper()).thenReturn(new ObjectMapper());
|
||||
when(twilioRestClient.request(any()))
|
||||
.thenReturn(
|
||||
new Response(
|
||||
new ByteArrayInputStream(ERROR_RESPONSE_BODY.getBytes(StandardCharsets.UTF_8)),
|
||||
500));
|
||||
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
testing.runWithSpan(
|
||||
"test",
|
||||
() ->
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"),
|
||||
new PhoneNumber("+1 555 555 5215"),
|
||||
"Hello world!")
|
||||
.create(twilioRestClient)))
|
||||
.isInstanceOf(ApiException.class);
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("test")
|
||||
.hasNoParent()
|
||||
.hasStatus(StatusData.error())
|
||||
.hasException(new ApiException("Testing Failure")),
|
||||
span ->
|
||||
span.hasName("MessageCreator.create")
|
||||
.hasKind(CLIENT)
|
||||
.hasParent(trace.getSpan(0))
|
||||
.hasStatus(StatusData.error())
|
||||
.hasException(new ApiException("Testing Failure"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rootSpan() {
|
||||
when(twilioRestClient.getObjectMapper()).thenReturn(new ObjectMapper());
|
||||
when(twilioRestClient.request(any()))
|
||||
.thenReturn(
|
||||
new Response(
|
||||
new ByteArrayInputStream(MESSAGE_RESPONSE_BODY.getBytes(StandardCharsets.UTF_8)),
|
||||
200));
|
||||
|
||||
Message message =
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"),
|
||||
new PhoneNumber("+1 555 555 5215"),
|
||||
"Hello world!")
|
||||
.create(twilioRestClient);
|
||||
|
||||
assertThat(message.getBody()).isEqualTo("Hello, World!");
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("MessageCreator.create")
|
||||
.hasKind(CLIENT)
|
||||
.hasNoParent()
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
stringKey("twilio.type"),
|
||||
"com.twilio.rest.api.v2010.account.Message"),
|
||||
equalTo(
|
||||
stringKey("twilio.account"), "AC14984e09e497506cf0d5eb59b1f6ace7"),
|
||||
equalTo(stringKey("twilio.sid"), "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
|
||||
equalTo(stringKey("twilio.status"), "sent"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void asynchronousCall() throws Exception {
|
||||
when(twilioRestClient.getObjectMapper()).thenReturn(new ObjectMapper());
|
||||
when(twilioRestClient.request(any()))
|
||||
.thenReturn(
|
||||
new Response(
|
||||
new ByteArrayInputStream(MESSAGE_RESPONSE_BODY.getBytes(StandardCharsets.UTF_8)),
|
||||
200));
|
||||
|
||||
Message message =
|
||||
testing.runWithSpan(
|
||||
"test",
|
||||
() -> {
|
||||
ListenableFuture<Message> future =
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"),
|
||||
new PhoneNumber("+1 555 555 5215"),
|
||||
"Hello world!")
|
||||
.createAsync(twilioRestClient);
|
||||
|
||||
try {
|
||||
return future.get(10, TimeUnit.SECONDS);
|
||||
} finally {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
});
|
||||
|
||||
assertThat(message).isNotNull();
|
||||
assertThat(message.getBody()).isEqualTo("Hello, World!");
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("test").hasNoParent().hasAttributes(Attributes.empty()),
|
||||
span ->
|
||||
span.hasName("MessageCreator.createAsync")
|
||||
.hasKind(CLIENT)
|
||||
.hasParent(trace.getSpan(0))
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
stringKey("twilio.type"),
|
||||
"com.twilio.rest.api.v2010.account.Message"),
|
||||
equalTo(
|
||||
stringKey("twilio.account"), "AC14984e09e497506cf0d5eb59b1f6ace7"),
|
||||
equalTo(stringKey("twilio.sid"), "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
|
||||
equalTo(stringKey("twilio.status"), "sent"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void asynchronousError() {
|
||||
when(twilioRestClient.getObjectMapper()).thenReturn(new ObjectMapper());
|
||||
when(twilioRestClient.request(any()))
|
||||
.thenReturn(
|
||||
new Response(
|
||||
new ByteArrayInputStream(ERROR_RESPONSE_BODY.getBytes(StandardCharsets.UTF_8)),
|
||||
500));
|
||||
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
testing.runWithSpan(
|
||||
"test",
|
||||
() -> {
|
||||
ListenableFuture<Message> future =
|
||||
Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"),
|
||||
new PhoneNumber("+1 555 555 5215"),
|
||||
"Hello world!")
|
||||
.createAsync(twilioRestClient);
|
||||
|
||||
try {
|
||||
return future.get(10, TimeUnit.SECONDS);
|
||||
} finally {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}))
|
||||
.isInstanceOf(ExecutionException.class);
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("test")
|
||||
.hasNoParent()
|
||||
.hasStatus(StatusData.error())
|
||||
.hasException(new ApiException("Testing Failure")),
|
||||
span ->
|
||||
span.hasName("MessageCreator.createAsync")
|
||||
.hasKind(CLIENT)
|
||||
.hasParent(trace.getSpan(0))
|
||||
.hasStatus(StatusData.error())
|
||||
.hasException(new ApiException("Testing Failure"))));
|
||||
}
|
||||
|
||||
private static CloseableHttpResponse mockResponse(String body, int statusCode)
|
||||
throws IOException {
|
||||
HttpEntity httpEntity = mock(HttpEntity.class);
|
||||
when(httpEntity.getContent())
|
||||
.thenReturn(new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)));
|
||||
when(httpEntity.isRepeatable()).thenReturn(true);
|
||||
|
||||
StatusLine statusLine = mock(StatusLine.class);
|
||||
when(statusLine.getStatusCode()).thenReturn(statusCode);
|
||||
|
||||
CloseableHttpResponse httpResponse = mock(CloseableHttpResponse.class);
|
||||
when(httpResponse.getEntity()).thenReturn(httpEntity);
|
||||
when(httpResponse.getStatusLine()).thenReturn(statusLine);
|
||||
|
||||
return httpResponse;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue