voicemail 0.2.0 → 1.0.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +57 -2
  4. data/lib/voicemail.rb +15 -8
  5. data/lib/voicemail/{application_controller.rb → call_controllers/application_controller.rb} +14 -1
  6. data/lib/voicemail/call_controllers/authentication_controller.rb +60 -0
  7. data/lib/voicemail/call_controllers/mailbox_controller.rb +46 -0
  8. data/lib/voicemail/{mailbox_main_menu_controller.rb → call_controllers/mailbox_main_menu_controller.rb} +9 -4
  9. data/lib/voicemail/call_controllers/mailbox_messages_controller.rb +48 -0
  10. data/lib/voicemail/{mailbox_play_message_controller.rb → call_controllers/mailbox_play_message_controller.rb} +26 -10
  11. data/lib/voicemail/call_controllers/mailbox_play_message_intro_controller.rb +72 -0
  12. data/lib/voicemail/{mailbox_set_greeting_controller.rb → call_controllers/mailbox_set_greeting_controller.rb} +2 -2
  13. data/lib/voicemail/{mailbox_set_pin_controller.rb → call_controllers/mailbox_set_pin_controller.rb} +0 -0
  14. data/lib/voicemail/call_controllers/voicemail_controller.rb +57 -0
  15. data/lib/voicemail/localization_loader.rb +28 -0
  16. data/lib/voicemail/matcher.rb +14 -0
  17. data/lib/voicemail/plugin.rb +40 -15
  18. data/lib/voicemail/storage_pstore.rb +49 -2
  19. data/lib/voicemail/version.rb +1 -1
  20. data/spec/voicemail/call_controllers/application_controller_spec.rb +31 -0
  21. data/spec/voicemail/call_controllers/authentication_controller_spec.rb +59 -0
  22. data/spec/voicemail/call_controllers/mailbox_controller_spec.rb +107 -0
  23. data/spec/voicemail/{mailbox_main_menu_controller_spec.rb → call_controllers/mailbox_main_menu_controller_spec.rb} +9 -2
  24. data/spec/voicemail/call_controllers/mailbox_messages_controller_spec.rb +110 -0
  25. data/spec/voicemail/call_controllers/mailbox_play_message_controller_spec.rb +97 -0
  26. data/spec/voicemail/call_controllers/mailbox_play_message_intro_controller_spec.rb +81 -0
  27. data/spec/voicemail/{mailbox_set_greeting_controller_spec.rb → call_controllers/mailbox_set_greeting_controller_spec.rb} +24 -6
  28. data/spec/voicemail/{mailbox_set_pin_controller_spec.rb → call_controllers/mailbox_set_pin_controller_spec.rb} +0 -0
  29. data/spec/voicemail/call_controllers/voicemail_controller_spec.rb +97 -0
  30. data/spec/voicemail/localization_loader_spec.rb +21 -0
  31. data/spec/voicemail/storage_pstore_spec.rb +64 -2
  32. data/templates/en.yml +67 -0
  33. data/voicemail.gemspec +2 -2
  34. metadata +42 -26
  35. data/lib/voicemail/mailbox_controller.rb +0 -56
  36. data/lib/voicemail/mailbox_messages_controller.rb +0 -55
  37. data/lib/voicemail/voicemail_controller.rb +0 -33
  38. data/spec/voicemail/mailbox_controller_spec.rb +0 -79
  39. data/spec/voicemail/mailbox_messages_controller_spec.rb +0 -71
  40. data/spec/voicemail/mailbox_play_message_controller_spec.rb +0 -70
  41. data/spec/voicemail/voicemail_controller_spec.rb +0 -76
@@ -35,8 +35,8 @@ module Voicemail
35
35
 
36
36
  def record_greeting
37
37
  play config.set_greeting.before_record
38
- record_comp = record config.set_greeting.recording.to_hash.merge(interruptible: true)
39
- @temp_recording = record_comp.complete_event.recording.uri.gsub(/file:\/\//, '').gsub(/\.wav/, '')
38
+ record_comp = record record_options
39
+ @temp_recording = record_comp.complete_event.recording.uri
40
40
  play_audio @temp_recording
41
41
 
42
42
  menu config.set_greeting.after_record,
@@ -0,0 +1,57 @@
1
+ module Voicemail
2
+ class VoicemailController < ApplicationController
3
+
4
+ attr_accessor :recording
5
+
6
+ def run
7
+ answer if config.when_to_answer == :before_greeting
8
+ if mailbox
9
+ play_greeting
10
+ answer if config.when_to_answer == :after_greeting
11
+ record_message
12
+ hangup
13
+ else
14
+ mailbox_not_found
15
+ end
16
+ end
17
+
18
+ def play_greeting
19
+ play mailbox[:greeting_message] || config.default_greeting
20
+ end
21
+
22
+ def record_message
23
+ @recording = record record_options
24
+
25
+ config.allow_rerecording ? recording_menu : save_recording
26
+ end
27
+
28
+ def recording_menu
29
+ ensure_message_saved_if_hangup
30
+ menu recording_url, config.after_record, tries: 3, timeout: 10 do
31
+ match('1') { save_recording }
32
+ match('2') { record_message }
33
+
34
+ invalid { }
35
+ timeout { save_recording }
36
+ failure { save_recording }
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def ensure_message_saved_if_hangup
43
+ call.on_end do
44
+ save_recording unless @saved
45
+ end
46
+ end
47
+
48
+ def save_recording
49
+ storage.save_recording mailbox[:id], call.from, recording.complete_event.recording
50
+ @saved = true
51
+ end
52
+
53
+ def recording_url
54
+ recording.complete_event.recording.uri
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,28 @@
1
+ module Voicemail::LocalizationLoader
2
+
3
+ def self.replace_config
4
+ translation_keys.each { |key, value| override_config key, value }
5
+ end
6
+
7
+ #
8
+ #This method scans the keys in the template en.yml - it doesn't use any values,
9
+ #it just sets up methods to call i18n.translate later
10
+ #
11
+ def self.override_config(key, value)
12
+ if value.class == String
13
+ Voicemail::Plugin.config[key.to_sym] = Proc.new { I18n.t "voicemail.#{key}" }
14
+ else
15
+ value.keys.each do |k, v|
16
+ Voicemail::Plugin.config[key.to_sym][k.to_sym] = Proc.new { I18n.t("voicemail.#{key}.#{k}") }
17
+ end
18
+ end
19
+ end
20
+
21
+ def self.translation_keys
22
+ YAML.load(File.open("#{current_path}/../../templates/en.yml"))['en']['voicemail']
23
+ end
24
+
25
+ def self.current_path
26
+ File.expand_path File.dirname(__FILE__)
27
+ end
28
+ end
@@ -0,0 +1,14 @@
1
+ module Voicemail
2
+ class Matcher
3
+ def initialize(entered, actual)
4
+ @entered = entered.try :to_s
5
+ @actual = actual.try :to_s
6
+ end
7
+
8
+ def matches?
9
+ logger.info "input : #{@entered}"
10
+ logger.info "actual: #{@actual}"
11
+ @entered == @actual
12
+ end
13
+ end
14
+ end
@@ -2,37 +2,55 @@ module Voicemail
2
2
  class Plugin < Adhearsion::Plugin
3
3
 
4
4
  init :voicemail do
5
- logger.info "Voicemail has been loaded"
5
+ if config.use_i18n
6
+ LocalizationLoader.replace_config
7
+ logger.info "Voicemail has been loaded with i18n support"
8
+ else
9
+ logger.info "Voicemail has been loaded"
10
+ end
6
11
  end
7
12
 
8
13
  config :voicemail do
9
- default_greeting "You have reached voicemail", desc: "What to use to greet users"
10
- mailbox_not_found "Mailbox not found", desc: "Message to use for a missing mailbox"
14
+ use_i18n false, desc: "Whether to use i18n for voice prompts"
11
15
  prompt_timeout 5, desc: "Timeout for the various prompts, in seconds"
12
16
  menu_timeout 15.seconds, desc: "Timeout for all menus"
13
17
  menu_tries 3, desc: "Tries to get matching input for all menus"
14
- datetime_format "Q 'digits/at' IMp", desc: "Fromat to use for message date and time TTS"
18
+ datetime_format "Q 'digits/at' IMp", desc: "Format to use for message date and time formatting"
19
+
20
+ when_to_answer :before_greeting, desc: "#answer :before_greeting or :after_greeting"
21
+ numeric_method :play_numeric, desc: "Whether to use #play_numeric type methods, AhnSay, or a single I18n string"
22
+
23
+ matcher_class Voicemail::Matcher, desc: "Class that checks for a match in pin authentication"
24
+ main_menu_class Voicemail::MailboxMainMenuController, desc: "Class runs the main menu prompts"
25
+
26
+ default_greeting "You have reached voicemail", desc: "What to use to greet users"
27
+ mailbox_not_found "Mailbox not found", desc: "Message to use for a missing mailbox"
15
28
 
16
- force_183 false, desc: "Only #answer if the mailbox is found"
29
+ allow_rerecording true, desc: "Allow caller to rerecord their voicemail"
30
+ after_record "Press 1 to save your voicemail. Press 2 to rerecord.", desc: "Message to play if allow_rerecording is set"
17
31
 
18
- desc "Voicemail recording options"
32
+ desc "Default recording options"
19
33
  recording {
34
+ interruptible true, desc: "Whether you can stop the recording with a DTMF input"
35
+ direction :send, desc: "The direction to record; you probably want :send"
20
36
  final_timeout 2, desc: "Maximum duration to run after recording in seconds"
21
37
  max_duration 30, desc: "Maximum duration for recording in seconds"
22
38
  start_beep true, desc: "Play a beep before recording"
23
39
  stop_beep false, desc: "Play a beep after recording"
24
40
  }
41
+ use_mailbox_opts_for_recording false, desc: "Whether per-mailbox settings can override defaults"
25
42
 
26
43
  desc "Configuration for registered users"
27
44
  mailbox {
28
45
  greeting_message "Welcome to the mailbox system.", desc: "Message to greet voicemail users"
29
46
  please_enter_pin "Please enter your PIN.", desc: "Message asking to enter PIN."
30
- pin_tries 3, desc: "Number of tries to authenticate before failure"
47
+ pin_tries 3, desc: "Number of tries to authenticate before failure - set to 0 for infinite"
31
48
  pin_wrong "The PIN you entered does not match. Please try again.", desc: "Message for an user that enters the wrong PIN"
32
49
  could_not_auth "We are sorry, the system could not authenticate you", desc: "Message for authentication final failure."
33
50
  number_before "You have ", desc: "What to play before the number of new messages"
34
- number_after " new messages", desc: "What to play after the number of new messages"
35
- menu_greeting "Press 1 to listen to new messages, 2 to change your greeting, 3 to change your PIN", desc: "What to say before the main menu"
51
+ number_after_new " new messages", desc: "What to play after the number of new messages"
52
+ number_after_saved " saved messages", desc: "What to play after the number of saved messages"
53
+ menu_greeting "Press 1 to listen to new messages, 2 to listen to saved messages, 3 to change your greeting, 4 to change your PIN", desc: "What to say before the main menu"
36
54
  menu_timeout_message "Please enter a digit for the menu", desc: "Message to play on main menu timeout"
37
55
  menu_invalid_message "Please enter valid input", desc: "Message to play on main menu invalid"
38
56
  menu_failure_message "Sorry, unable to understand your input.", desc: "Message to play on main menu failure"
@@ -44,10 +62,6 @@ module Voicemail
44
62
  before_record "Please speak after the beep. The prompt will be played back after.", desc: "Recording instructions"
45
63
  after_record "Press 1 to save your new greeting, 2 to discard it, 9 to go back to the menu", desc: "Menu to use after recording"
46
64
  no_personal_greeting "You do not currently have a personalized greeting.", desc: "What to play if there is no specific greeting"
47
- recording {
48
- max_duration 5_000, desc: "Maximum duration for recording in milliseconds"
49
- start_beep true, desc: "Play a beep before recording"
50
- }
51
65
  }
52
66
 
53
67
  desc "Set PIN configuration"
@@ -63,8 +77,10 @@ module Voicemail
63
77
 
64
78
  desc "Listen to messages menu configuration"
65
79
  messages {
66
- menu "Press 1 to archive the message and go to the next, press 5 to delete the message and go to the next, press 7 to hear the message again, press 9 for the main menu", desc: "Menu to use inside messages"
80
+ menu_new "Press 1 to archive the message and go to the next, press 5 to delete the message and go to the next, press 7 to hear the message again, press 9 for the main menu", desc: "Menu to use inside new messages"
81
+ menu_saved "Press 1 to unarchive the message and go to the next, press 5 to delete the message and go to the next, press 7 to hear the message again, press 9 for the main menu", desc: "Menu to use inside saved messages"
67
82
  no_new_messages "There are no new messages", desc: "Message to inform the user he has no new messages"
83
+ no_saved_messages "There are no saved messages", desc: "Message to inform the user he has no saved messages"
68
84
  message_received_on "Message received on ", desc: "Prefix to menu intro"
69
85
  from " from ", desc: "Used in message intro"
70
86
  }
@@ -83,8 +99,17 @@ module Voicemail
83
99
  task :info do
84
100
  STDOUT.puts "Voicemail plugin v. #{VERSION}"
85
101
  end
102
+
103
+ desc "Copy an initial translation file (en) to your adhearsion project (ahn_root/config/locales/en.yml)"
104
+ task :i18n_init do
105
+ current_path = File.expand_path(File.dirname(__FILE__))
106
+ template_file = "#{current_path}/../../templates/en.yml"
107
+ new_location = "#{Dir.pwd}/config/locales/"
108
+
109
+ FileUtils.mkdir_p(new_location) unless File.directory?(new_location)
110
+ FileUtils.copy template_file, "#{new_location}en.yml"
111
+ end
86
112
  end
87
113
  end
88
-
89
114
  end
90
115
  end
@@ -5,6 +5,7 @@ module Voicemail
5
5
  attr_accessor :store
6
6
 
7
7
  def initialize
8
+ logger.fatal "#new storage pstore!"
8
9
  @store = PStore.new config.storage.pstore_location
9
10
  setup_schema
10
11
  end
@@ -21,12 +22,24 @@ module Voicemail
21
22
  end
22
23
  end
23
24
 
25
+ def count_saved_messages(mailbox_id)
26
+ store.transaction true do
27
+ store[:archived][mailbox_id].size
28
+ end
29
+ end
30
+
24
31
  def next_new_message(mailbox_id)
25
32
  store.transaction true do
26
33
  store[:recordings][mailbox_id].first
27
34
  end
28
35
  end
29
36
 
37
+ def next_saved_message(mailbox_id)
38
+ store.transaction true do
39
+ store[:archived][mailbox_id].first
40
+ end
41
+ end
42
+
30
43
  def archive_message(mailbox_id, message_id)
31
44
  store.transaction do
32
45
  item = store[:recordings][mailbox_id].select { |i| i[:id] == message_id }
@@ -38,6 +51,17 @@ module Voicemail
38
51
  end
39
52
  end
40
53
 
54
+ def unarchive_message(mailbox_id, message_id)
55
+ store.transaction do
56
+ item = store[:archived][mailbox_id].select { |i| i[:id] == message_id }
57
+ rec = item.first
58
+ if rec
59
+ store[:recordings][mailbox_id] << rec
60
+ store[:archived][mailbox_id].delete(rec)
61
+ end
62
+ end
63
+ end
64
+
41
65
  def delete_message(mailbox_id, message_id)
42
66
  File.unlink(rec[:uri]) if File.exists?(rec[:uri])
43
67
  store[:recordings][mailbox_id].delete(rec)
@@ -55,13 +79,13 @@ module Voicemail
55
79
  end
56
80
  end
57
81
 
58
- def save_recording(mailbox_id, from, recording_uri)
82
+ def save_recording(mailbox_id, from, recording_object)
59
83
  store.transaction do
60
84
  recording = {
61
85
  id: SecureRandom.uuid,
62
86
  from: from,
63
87
  received: Time.now,
64
- uri: recording_uri.gsub(/file:\/\//, '')
88
+ uri: recording_object.uri
65
89
  }
66
90
  store[:recordings][mailbox_id] << recording
67
91
  logger.info "Saving recording: #{recording.inspect}"
@@ -78,6 +102,29 @@ module Voicemail
78
102
  store[:mailboxes] ||= {}
79
103
  store[:recordings] ||= {}
80
104
  store[:archived] ||= {}
105
+
106
+ store[:mailboxes][1] = {greeting_message: "Hello.", id: 1, pin: '1234', record_options: {max_duration: 10}}
107
+ store[:recordings][1] ||= []
108
+ store[:archived][1] ||= []
109
+ end
110
+
111
+ store.transaction do
112
+ foo_recording = {
113
+ id: "e31823a5-1e2e-4038-a03b-2b5795190142",
114
+ from: "123456",
115
+ received: DateTime.new(2013,8,29,14,10,12),
116
+ uri: "https://gh-audio-development.s3.amazonaws.com/voicemails/f911f9c4-10e6-11e3-a9cb-5dc153dadb7c-3.mp3"
117
+ }
118
+
119
+ foo_archived = {
120
+ id: "7a88a931-fd9f-4816-8a92-d055050387a8",
121
+ from: "123456",
122
+ received: DateTime.new(2013,8,29,14,10,12),
123
+ uri: "https://gh-audio-development.s3.amazonaws.com/voicemails/9a1ca46c-0f53-11e3-a1f7-2b3c646a58f5-3.mp3"
124
+ }
125
+
126
+ store[:recordings][1] = [foo_recording]
127
+ store[:archived][1] = [foo_archived]
81
128
  end
82
129
  end
83
130
 
@@ -1,3 +1,3 @@
1
1
  module Voicemail
2
- VERSION = "0.2.0"
2
+ VERSION = "1.0.0.beta"
3
3
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Voicemail::ApplicationController do
4
+ include VoicemailControllerSpecHelper
5
+
6
+ describe "#main_menu" do
7
+ context "with the defaults" do
8
+ it "passes to MainMenuController" do
9
+ subject.should_receive(:pass).once.with Voicemail::MailboxMainMenuController, mailbox: mailbox[:id], storage: storage_instance
10
+ controller.main_menu
11
+ end
12
+ end
13
+
14
+ context "with a custom class" do
15
+
16
+ class Foo; end
17
+
18
+ before do
19
+ @saved_option = config.main_menu_class
20
+ config.main_menu_class = Foo
21
+ end
22
+
23
+ after { config.main_menu_class = @saved_option }
24
+
25
+ it "passes to custom controller class" do
26
+ subject.should_receive(:pass).once.with Foo, mailbox: mailbox[:id], storage: storage_instance
27
+ controller.main_menu
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Voicemail::AuthenticationController do
4
+ include VoicemailControllerSpecHelper
5
+
6
+ describe "#run" do
7
+ context "with a missing mailbox parameter in metadata" do
8
+ let(:metadata) { Hash.new }
9
+
10
+ it "should raise an error if there is no mailbox in the metadata" do
11
+ expect { controller.run }.to raise_error ArgumentError
12
+ end
13
+ end
14
+
15
+ context "with a present mailbox parameter in metadata" do
16
+ context "with an invalid mailbox" do
17
+ let(:mailbox) { nil }
18
+
19
+ it "plays the mailbox not found message and hangs up" do
20
+ should_play config.mailbox_not_found
21
+ subject.should_receive(:hangup).once
22
+ controller.run
23
+ end
24
+ end
25
+
26
+ context "with an existing mailbox" do
27
+ it "plays the mailbox greeting message" do
28
+ should_play config.mailbox.greeting_message
29
+ subject.should_receive(:authenticate)
30
+ subject.should_receive(:auth_ok).and_return true
31
+ subject.should_receive(:pass).with Voicemail::MailboxController, mailbox: 100
32
+ controller.run
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "#authenticate" do
39
+ it "authenticates an user that enters the correct pin" do
40
+ should_ask(config.mailbox.please_enter_pin, terminator: "#", timeout: config.prompt_timeout).once.and_return(1234)
41
+ controller.authenticate
42
+ controller.auth_ok.should == true
43
+ end
44
+
45
+ it "tell a user his pin is wrong and retries" do
46
+ subject.should_receive(:ask).times(2).and_return(1111, 1234)
47
+ should_play config.mailbox.pin_wrong
48
+ controller.authenticate
49
+ controller.auth_ok.should == true
50
+ end
51
+
52
+ it "fails with a message if the user enters a wrong PIN the set number of times" do
53
+ subject.should_receive(:ask).times(3).and_return(1111, 2222, 3333)
54
+ subject.should_receive(:play).with(config.mailbox.pin_wrong).times(3)
55
+ controller.authenticate
56
+ controller.auth_ok.should == false
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ describe Voicemail::MailboxController do
4
+ include VoicemailControllerSpecHelper
5
+
6
+ describe "#run" do
7
+ context "with a missing mailbox parameter in metadata" do
8
+ let(:metadata) { Hash.new }
9
+
10
+ it "should raise an error if there is no mailbox in the metadata" do
11
+ expect { controller.run }.to raise_error ArgumentError
12
+ end
13
+ end
14
+
15
+ context "with a present mailbox parameter in metadata" do
16
+ context "with an invalid mailbox" do
17
+ let(:mailbox) { nil }
18
+
19
+ it "plays the mailbox not found message and hangs up" do
20
+ should_play config.mailbox_not_found
21
+ subject.should_receive(:hangup).once
22
+ controller.run
23
+ end
24
+ end
25
+
26
+ context "with an existing mailbox" do
27
+ it "plays the mailbox greeting message" do
28
+ subject.should_receive(:play_number_of_messages).and_return(true)
29
+ subject.should_receive(:main_menu).and_return(true)
30
+ controller.run
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#play_number_of_messages" do
37
+ before { config.numeric_method = :play_numeric }
38
+ after do
39
+ controller.play_number_of_messages type
40
+ end
41
+
42
+ context ":new" do
43
+ let(:type) { :new }
44
+
45
+ context "with at least one new message" do
46
+ before { storage_instance.should_receive(:count_new_messages).once.with(mailbox[:id]).and_return 3 }
47
+
48
+ it "plays the number of new messages" do
49
+ should_play(config.mailbox.number_before).ordered
50
+ subject.should_receive(:play_numeric).ordered.with(3)
51
+ should_play(config.mailbox.number_after_new).ordered
52
+ end
53
+
54
+ context "when it's set to use ahnsay" do
55
+ before { config.numeric_method = :ahn_say }
56
+
57
+ it "plays the number of messages using ahn say" do
58
+ should_play(config.mailbox.number_before).ordered
59
+ subject.should_receive(:sounds_for_number).with(3).and_return "3.ul"
60
+ subject.should_receive(:play).ordered.with "3.ul"
61
+ should_play(config.mailbox.number_after_new).ordered
62
+ end
63
+ end
64
+
65
+ context "when it's set to use I18n" do
66
+ before { config.numeric_method = :i18n_string }
67
+
68
+ it "plays the number of messages using i18n's pluralization" do
69
+ flexmock(I18n).should_receive(:t).with("voicemail.mailbox.x_new_messages", count: 3).and_return "You have 3 new messages"
70
+ should_play "You have 3 new messages"
71
+ end
72
+ end
73
+ end
74
+
75
+ context "with no new message" do
76
+ before { storage_instance.should_receive(:count_new_messages).once.with(mailbox[:id]).and_return 0 }
77
+
78
+ it "plays the no new messages audio" do
79
+ should_play(config.messages.no_new_messages).ordered
80
+ end
81
+ end
82
+ end
83
+
84
+ context ":saved" do
85
+ let(:type) { :saved }
86
+
87
+ it "plays the number of saved messages if there is at least one" do
88
+ storage_instance.should_receive(:count_saved_messages).once.with(mailbox[:id]).and_return(3)
89
+ should_play(config.mailbox.number_before).ordered
90
+ subject.should_receive(:play_numeric).ordered.with(3)
91
+ should_play(config.mailbox.number_after_saved).ordered
92
+ end
93
+
94
+ it "does play the no saved messages audio if there are none" do
95
+ storage_instance.should_receive(:count_saved_messages).once.with(mailbox[:id]).and_return(0)
96
+ should_play(config.messages.no_saved_messages).ordered
97
+ end
98
+ end
99
+ end
100
+
101
+ describe "#main_menu" do
102
+ it "passes to MainMenuController" do
103
+ subject.should_receive(:pass).once.with Voicemail::MailboxMainMenuController, mailbox: mailbox[:id], storage: storage_instance
104
+ controller.main_menu
105
+ end
106
+ end
107
+ end