Skip to content

Commit 90f420e

Browse files
authored
Calls, Recordings, Conferences, and Statistics Integration Tests (#71)
* DX-2937 Calls Integration Tests * update ignore * separate tests * remove test.rb * split tests and add 4xx tests * add 403 * update call test * update call * clearer variable name and update env vars * secrets. * finish calls * add env vars, refactoring, and recording tests * conferences test * more recordings tests * finish recordings * add asserts for response objects * finalize calls * reorder recordings * finish conferences * complete or partial * fix test.yml * spaces * updates and statistics tests (#79) * use stricter type matching for asserts * stricter asserts * add statistics tests * add retry logic to call cleanup * add sleep and retry less
1 parent 79b4553 commit 90f420e

10 files changed

+635
-137
lines changed

.github/workflows/test.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,19 @@ jobs:
3535
BW_ACCOUNT_ID: ${{ secrets.BW_ACCOUNT_ID }}
3636
BW_USERNAME: ${{ secrets.BW_USERNAME }}
3737
BW_PASSWORD: ${{ secrets.BW_PASSWORD }}
38+
BW_USERNAME_FORBIDDEN: ${{ secrets.BW_USERNAME_FORBIDDEN }}
39+
BW_PASSWORD_FORBIDDEN: ${{ secrets.BW_PASSWORD_FORBIDDEN }}
3840
BW_VOICE_APPLICATION_ID: ${{ secrets.BW_VOICE_APPLICATION_ID }}
3941
BW_MESSAGING_APPLICATION_ID: ${{ secrets.BW_MESSAGING_APPLICATION_ID }}
4042
BW_NUMBER: ${{ secrets.BW_NUMBER }}
4143
USER_NUMBER: ${{ secrets.USER_NUMBER }}
4244
BASE_CALLBACK_URL: ${{ secrets.BASE_CALLBACK_URL }}
45+
MANTECA_ACTIVE_NUMBER: ${{ secrets.MANTECA_ACTIVE_NUMBER }}
46+
MANTECA_IDLE_NUMBER: ${{ secrets.MANTECA_IDLE_NUMBER }}
47+
MANTECA_BASE_URL: ${{ secrets.MANTECA_BASE_URL }}
48+
MANTECA_APPLICATION_ID: ${{ secrets.MANTECA_APPLICATION_ID }}
49+
OPERATING_SYSTEM: ${{ matrix.os }}
50+
RUBY_VERSION: ${{ matrix.ruby-version }}
4351
run: rake
4452

4553
- name: Notify Slack of Failures

spec/call_utils.rb

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Helper functions for voice calls
2+
# These are reused in multiple tests
3+
4+
def setup_manteca(type)
5+
manteca_body = {
6+
os: OPERATING_SYSTEM,
7+
language: RUBY_VERSION,
8+
type: type
9+
}
10+
manteca_test_url = URI(MANTECA_BASE_URL + "/tests")
11+
manteca_header = { 'Content-Type': 'application/json' }
12+
13+
begin
14+
test_id = Net::HTTP.post(manteca_test_url, manteca_body.to_json, manteca_header)
15+
return test_id.body.to_s.gsub("\"", "")
16+
rescue => e
17+
puts e.inspect
18+
end
19+
end
20+
21+
def create_manteca_call(tag = "ruby", answer_path = "/bxml/pause", calls_api)
22+
manteca_call_body = Bandwidth::CreateCall.new(
23+
application_id: MANTECA_APPLICATION_ID,
24+
to: MANTECA_IDLE_NUMBER,
25+
from: MANTECA_ACTIVE_NUMBER,
26+
answer_url: MANTECA_BASE_URL + answer_path,
27+
tag: tag
28+
)
29+
30+
response = calls_api.create_call(BW_ACCOUNT_ID, manteca_call_body)
31+
$active_calls.append(response.call_id)
32+
return response.call_id
33+
end
34+
35+
def get_manteca_test_status(test_id)
36+
manteca_status_url = URI(MANTECA_BASE_URL + "/tests/" + test_id)
37+
response = JSON.parse(Net::HTTP.get(manteca_status_url))
38+
return response
39+
end
40+
41+
def cleanup_calls(calls, calls_api)
42+
attempts = 0
43+
44+
while (calls.length > 0 && attempts < 10)
45+
calls.delete_if { |call_id| call_ended(call_id, calls_api) }
46+
sleep(SLEEP_TIME_S)
47+
attempts += 1
48+
end
49+
50+
if (calls.length > 0)
51+
error_message = "Failed to terminate all calls" + calls.to_s
52+
raise StandardError.new error_message
53+
end
54+
end
55+
56+
def call_ended(call_id, calls_api)
57+
begin
58+
response = calls_api.get_call_state(BW_ACCOUNT_ID, call_id)
59+
rescue Bandwidth::ApiError
60+
return false
61+
end
62+
63+
if !(response.state == 'disconnected')
64+
begin
65+
calls_api.update_call(BW_ACCOUNT_ID, call_id, $complete_call_body)
66+
return true
67+
rescue Bandwidth::ApiError
68+
end
69+
else
70+
return true
71+
end
72+
73+
return false
74+
end

spec/integration/calls_api_integration_spec.rb

Lines changed: 157 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,180 @@
11
require 'spec_helper'
22
require 'json'
3+
require_relative '../call_utils'
34

45
# Integration Tests for Bandwidth::CallsApi
56
describe 'CallsApi Integration Tests' do
6-
before do
7-
# run before each test
8-
@api_instance = Bandwidth::CallsApi.new
9-
end
10-
11-
after do
12-
# run after each test
7+
before(:all) do
8+
Bandwidth.configure do |config|
9+
config.username = BW_USERNAME
10+
config.password = BW_PASSWORD
11+
end
12+
@api_instance_calls = Bandwidth::CallsApi.new
13+
$call_info_id = ""
1314
end
1415

1516
# Create Call
16-
describe 'create_call test' do
17-
it 'should work' do
18-
# assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
17+
describe 'create_call' do
18+
it 'creates a call with amd' do
19+
amd_config = Bandwidth::MachineDetectionConfiguration.new(
20+
mode: "async",
21+
detection_timeout: 5.0,
22+
silence_timeout: 5.0,
23+
speech_threshold: 5.0,
24+
speech_end_threshold: 5.0,
25+
delay_result: true,
26+
callback_url: BASE_CALLBACK_URL + "/machineDetection",
27+
callback_method: Bandwidth::CallbackMethodEnum::POST
28+
)
29+
30+
call_body = Bandwidth::CreateCall.new(
31+
application_id: BW_VOICE_APPLICATION_ID,
32+
to: USER_NUMBER,
33+
from: BW_NUMBER,
34+
answer_url: BASE_CALLBACK_URL + "/callbacks/answer",
35+
answer_method: "POST",
36+
disconnect_url: BASE_CALLBACK_URL + "/callbacks/disconnect",
37+
disconnect_method: "GET",
38+
machine_detection: amd_config,
39+
call_timeout: 30.0,
40+
callback_timeout: 15.0
41+
)
42+
43+
response = @api_instance_calls.create_call_with_http_info(BW_ACCOUNT_ID, call_body)
44+
sleep(SLEEP_TIME_S)
45+
46+
expect(response[CODE]).to eq(201)
47+
expect(response[DATA]).to be_instance_of(Bandwidth::CreateCallResponse)
48+
expect(response[DATA].call_id.length).to eq(47)
49+
expect(response[DATA].account_id).to eq(BW_ACCOUNT_ID)
50+
expect(response[DATA].application_id).to eq(BW_VOICE_APPLICATION_ID)
51+
expect(response[DATA].to).to eq(USER_NUMBER)
52+
expect(response[DATA].from).to eq(BW_NUMBER)
53+
expect(response[DATA].call_id)
54+
expect(response[DATA].call_timeout).to eq(30.0)
55+
expect(response[DATA].callback_timeout).to eq(15.0)
56+
expect(response[DATA].enqueued_time).to be_instance_of(Time)
57+
expect(response[DATA].answer_method).to eq(Bandwidth::CallbackMethodEnum::POST)
58+
expect(response[DATA].disconnect_method).to eq("GET")
59+
expect(response[DATA].answer_url).to eq(BASE_CALLBACK_URL + "/callbacks/answer")
60+
expect(response[DATA].disconnect_url).to eq(BASE_CALLBACK_URL + "/callbacks/disconnect")
61+
62+
$call_info_id = response[DATA].call_id
63+
$active_calls.append($call_info_id)
1964
end
2065
end
2166

2267
# Get Call State Information
23-
describe 'get_call_state test' do
24-
it 'should work' do
25-
# assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
68+
describe 'get_call_state' do
69+
it 'gets the call state' do
70+
response = @api_instance_calls.get_call_state_with_http_info(BW_ACCOUNT_ID, $call_info_id)
71+
72+
expect(response[CODE]).to eq(200)
73+
expect(response[DATA]).to be_instance_of(Bandwidth::CallState)
74+
expect(response[DATA].call_id).to eq($call_info_id)
75+
expect(response[DATA].account_id).to eq(BW_ACCOUNT_ID)
76+
expect(response[DATA].application_id).to eq(BW_VOICE_APPLICATION_ID)
77+
expect(response[DATA].start_time).to be_instance_of(Time)
78+
expect(response[DATA].last_update).to be_instance_of(Time)
79+
expect(response[DATA].state).to be_instance_of(String)
80+
expect(response[DATA].direction).to eq(Bandwidth::CallDirectionEnum::OUTBOUND)
2681
end
2782
end
2883

2984
# Update Call
30-
describe 'update_call test' do
31-
it 'should work' do
32-
# assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
85+
describe 'update_call' do
86+
it 'creates and updates a call' do
87+
update_call_body = Bandwidth::UpdateCall.new(
88+
state: Bandwidth::CallStateEnum::ACTIVE,
89+
redirect_url: MANTECA_BASE_URL + "/bxml/pause"
90+
)
91+
92+
update_call_id = create_manteca_call(@api_instance_calls)
93+
sleep(SLEEP_TIME_S)
94+
95+
update_response = @api_instance_calls.update_call_with_http_info(BW_ACCOUNT_ID, update_call_id, update_call_body)
96+
expect(update_response[CODE]).to eq(200)
97+
sleep(SLEEP_TIME_S)
98+
99+
complete_response = @api_instance_calls.update_call_with_http_info(BW_ACCOUNT_ID, update_call_id, $complete_call_body)
100+
expect(complete_response[CODE]).to eq(200)
33101
end
34102
end
35103

36104
# Update Call BXML
37-
describe 'update_call_bxml test' do
38-
it 'should work' do
39-
# assertion here. ref: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
105+
describe 'update_call_bxml' do
106+
it 'updates a call using bxml' do
107+
update_call_id = create_manteca_call(@api_instance_calls)
108+
sleep(SLEEP_TIME_S)
109+
110+
update_bxml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Bxml><SpeakSentence locale=\"en_US\" gender=\"female\" voice=\"susan\">This is a test bxml response</SpeakSentence><Pause duration=\"3\"/></Bxml>";
111+
update_response = @api_instance_calls.update_call_bxml_with_http_info(BW_ACCOUNT_ID, update_call_id, update_bxml)
112+
expect(update_response[CODE]).to eq(204)
113+
sleep(SLEEP_TIME_S)
114+
115+
complete_response = @api_instance_calls.update_call_with_http_info(BW_ACCOUNT_ID, update_call_id, $complete_call_body)
116+
expect(complete_response[CODE]).to eq(200)
117+
end
118+
end
119+
120+
# HTTP 4XX Errors
121+
describe 'http error' do
122+
it 'causes a 400 error' do
123+
call_body_bad = Bandwidth::CreateCall.new(
124+
application_id: BW_VOICE_APPLICATION_ID,
125+
to: "+1invalid",
126+
from: BW_NUMBER,
127+
answer_url: BASE_CALLBACK_URL + "/callbacks/answer",
128+
answer_method: "POST",
129+
disconnect_url: BASE_CALLBACK_URL + "/callbacks/disconnect",
130+
disconnect_method: "GET"
131+
)
132+
133+
expect {
134+
@api_instance_calls.create_call_with_http_info(BW_ACCOUNT_ID, call_body_bad)
135+
}.to raise_error { |e|
136+
expect(e).to be_instance_of(Bandwidth::ApiError)
137+
expect(e.code).to eq(400)
138+
}
139+
end
140+
141+
it 'causes a 404 error' do
142+
dne_id = "does-not-exist"
143+
144+
expect {
145+
@api_instance_calls.get_call_state_with_http_info(BW_ACCOUNT_ID, dne_id)
146+
}.to raise_error { |e|
147+
expect(e).to be_instance_of(Bandwidth::ApiError)
148+
expect(e.code).to eq(404)
149+
}
150+
end
151+
152+
it 'causes a 401 error' do
153+
Bandwidth.configure do |config|
154+
config.username = 'bad_username'
155+
config.password = 'bad_password'
156+
end
157+
158+
expect {
159+
@api_instance_calls.get_call_state_with_http_info(BW_ACCOUNT_ID, $call_info_id)
160+
}.to raise_error { |e|
161+
expect(e).to be_instance_of(Bandwidth::ApiError)
162+
expect(e.code).to eq(401)
163+
}
164+
end
165+
166+
it 'causes a 403 error' do
167+
Bandwidth.configure do |config|
168+
config.username = FORBIDDEN_USERNAME
169+
config.password = FORBIDDEN_PASSWORD
170+
end
171+
172+
expect {
173+
@api_instance_calls.get_call_state_with_http_info(BW_ACCOUNT_ID, $call_info_id)
174+
}.to raise_error { |e|
175+
expect(e).to be_instance_of(Bandwidth::ApiError)
176+
expect(e.code).to eq(403)
177+
}
40178
end
41179
end
42180

0 commit comments

Comments
 (0)