adhearsion 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +10 -0
  2. data/CHANGELOG +8 -0
  3. data/README.markdown +33 -0
  4. data/Rakefile +28 -68
  5. data/adhearsion.gemspec +19 -133
  6. data/app_generators/ahn/templates/Gemfile +0 -4
  7. data/app_generators/ahn/templates/components/disabled/restful_rpc/spec/restful_rpc_spec.rb +4 -16
  8. data/lib/adhearsion/cli.rb +17 -0
  9. data/lib/adhearsion/component_manager/component_tester.rb +1 -3
  10. data/lib/adhearsion/component_manager/spec_framework.rb +4 -10
  11. data/lib/adhearsion/foundation/object.rb +10 -0
  12. data/lib/adhearsion/version.rb +1 -1
  13. data/spec/ahn_command_spec.rb +284 -0
  14. data/spec/component_manager_spec.rb +292 -0
  15. data/spec/constants_spec.rb +8 -0
  16. data/spec/drb_spec.rb +65 -0
  17. data/spec/fixtures/dialplan.rb +3 -0
  18. data/spec/foundation/event_socket_spec.rb +168 -0
  19. data/spec/host_definitions_spec.rb +79 -0
  20. data/spec/initialization_spec.rb +163 -0
  21. data/spec/initializer/configuration_spec.rb +270 -0
  22. data/spec/initializer/loading_spec.rb +149 -0
  23. data/spec/initializer/paths_spec.rb +74 -0
  24. data/spec/logging_spec.rb +86 -0
  25. data/spec/relationship_properties_spec.rb +54 -0
  26. data/spec/silence.rb +10 -0
  27. data/spec/spec_helper.rb +101 -0
  28. data/spec/voip/asterisk/agi_server_spec.rb +473 -0
  29. data/spec/voip/asterisk/ami/ami_spec.rb +549 -0
  30. data/spec/voip/asterisk/ami/lexer/ami_fixtures.yml +30 -0
  31. data/spec/voip/asterisk/ami/lexer/lexer_story +291 -0
  32. data/spec/voip/asterisk/ami/lexer/lexer_story.rb +241 -0
  33. data/spec/voip/asterisk/ami/lexer/story_helper.rb +124 -0
  34. data/spec/voip/asterisk/ami/old_tests.rb +204 -0
  35. data/spec/voip/asterisk/ami/super_manager/super_manager_story +25 -0
  36. data/spec/voip/asterisk/ami/super_manager/super_manager_story.rb +15 -0
  37. data/spec/voip/asterisk/ami/super_manager/super_manager_story_helper.rb +5 -0
  38. data/spec/voip/asterisk/commands_spec.rb +2179 -0
  39. data/spec/voip/asterisk/config_file_generators/agents_spec.rb +251 -0
  40. data/spec/voip/asterisk/config_file_generators/queues_spec.rb +323 -0
  41. data/spec/voip/asterisk/config_file_generators/voicemail_spec.rb +306 -0
  42. data/spec/voip/asterisk/config_manager_spec.rb +127 -0
  43. data/spec/voip/asterisk/menu_command/calculated_match_spec.rb +109 -0
  44. data/spec/voip/asterisk/menu_command/matchers_spec.rb +97 -0
  45. data/spec/voip/call_routing_spec.rb +125 -0
  46. data/spec/voip/dialplan_manager_spec.rb +468 -0
  47. data/spec/voip/dsl/dialing_dsl_spec.rb +270 -0
  48. data/spec/voip/dsl/dispatcher_spec.rb +82 -0
  49. data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
  50. data/spec/voip/dsl/parser_spec.rb +69 -0
  51. data/spec/voip/freeswitch/basic_connection_manager_spec.rb +39 -0
  52. data/spec/voip/freeswitch/inbound_connection_manager_spec.rb +39 -0
  53. data/spec/voip/freeswitch/oes_server_spec.rb +9 -0
  54. data/spec/voip/numerical_string_spec.rb +61 -0
  55. data/spec/voip/phone_number_spec.rb +45 -0
  56. data/theatre-spec/dsl_examples/dynamic_stomp.rb +7 -0
  57. data/theatre-spec/dsl_examples/simple_before_call.rb +7 -0
  58. data/theatre-spec/dsl_spec.rb +43 -0
  59. data/theatre-spec/invocation_spec.rb +167 -0
  60. data/theatre-spec/namespace_spec.rb +125 -0
  61. data/theatre-spec/spec_helper.rb +37 -0
  62. data/theatre-spec/spec_helper_spec.rb +28 -0
  63. data/theatre-spec/theatre_class_spec.rb +150 -0
  64. metadata +171 -34
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'adhearsion/voip/freeswitch/basic_connection_manager'
3
+
4
+ include Adhearsion::VoIP::FreeSwitch
5
+
6
+ describe "FreeSwitch BasicConnectionManager" do
7
+ attr_reader :manager, :io
8
+ before(:each) do
9
+ @io = StringIO.new
10
+ @manager = BasicConnectionManager.new io
11
+ end
12
+
13
+ it "<<() should add two newlines" do
14
+ manager << "foobar"
15
+ io.string.should == "foobar\n\n"
16
+ end
17
+
18
+ end
19
+
20
+ describe "FreeSwitch BasicConnectionManager's header parser" do
21
+ it "YAML-like headers are read properly" do
22
+ header = {
23
+ "Foo-Bar" => "bar",
24
+ "Qaz-Monkey-Charlie-Zebra" => "qwerty"
25
+ }
26
+
27
+ string_header = header.inject("") do |string, (key, value)|
28
+ string + "#{key}: #{value}\n"
29
+ end
30
+
31
+ string_header << "\n"
32
+
33
+ manager = BasicConnectionManager.new StringIO.new(string_header)
34
+ manager.get_raw_header.should == string_header.strip
35
+
36
+ manager = BasicConnectionManager.new StringIO.new(string_header)
37
+ manager.get_header.should == header
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'adhearsion/voip/freeswitch/inbound_connection_manager'
3
+ include Adhearsion::VoIP::FreeSwitch
4
+
5
+ describe "A FreeSwitch InboundConnectionManager" do
6
+
7
+ it "authenticatating with the given password" do
8
+ manager = InboundConnectionManager.new io_mock
9
+ manager.login password
10
+ end
11
+
12
+ it "a hash is accepted when creating a new InboundConnectionManager" do
13
+ host, port = "myhost.mydomain", 31337
14
+
15
+ flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return io_mock
16
+
17
+ InboundConnectionManager.new :host => host, :port => port, :pass => password
18
+ end
19
+
20
+ it "an IO is accepted when creating a new InboundConnectionManager"
21
+
22
+ private
23
+ def io_mock
24
+ @io_mock ||=
25
+ begin
26
+ io_mock = StringIO.new
27
+ flexmock(io_mock) do |io|
28
+ io.should_receive(:write).with("auth #{password}\n\n")
29
+ io.should_receive(:gets).and_return "connection: kthnx\n",
30
+ "\n", "login: +OK\n", "\n"
31
+ end
32
+ io_mock
33
+ end
34
+ end
35
+
36
+ def password
37
+ "supersecret"
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+ require File.dirname(__FILE__) + "/../dsl/dispatcher_spec_helper"
3
+ require 'adhearsion/voip/freeswitch/oes_server'
4
+
5
+
6
+ describe "Adhearsion::VoIP::FreeSwitch::OesServer::OesDispatcher" do
7
+ include StandardDispatcherBehavior
8
+ before(:each) { @dispatcher_class = Adhearsion::VoIP::FreeSwitch::OesServer::OesDispatcher }
9
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ require 'adhearsion/voip/dsl/numerical_string'
4
+ require 'adhearsion/voip/constants'
5
+
6
+ describe "A NumericalString" do
7
+ # FIXME: This test is fundamentally broken in Ruby 1.9.
8
+ # See https://adhearsion.lighthouseapp.com/projects/5871/tickets/127-ruby-19-and-numericalstring-comparisons-in-case-statements
9
+ # The suggested workaround is to cast the object to a string:
10
+ # case numerical_string_object.to_s
11
+ # when "0987" then ...
12
+ # end
13
+ # it "should appear to be behave like a Fixnum in a case statement" do
14
+ # case numerical_string_for("123")
15
+ # when 123 then true
16
+ # else false
17
+ # end.should be true
18
+ #
19
+ # case numerical_string_for("0987")
20
+ # when 987 then true
21
+ # else false
22
+ # end.should be true
23
+ # end
24
+
25
+ it "should appear to behave like a String in a case statement" do
26
+ numerical_string_for("123").should === "123"
27
+ numerical_string_for("0987").should === "0987"
28
+ end
29
+
30
+ it "when compared against a Range that contains the numeric equivalent, the NumericalString is seen as a member" do
31
+ (100..200).should === numerical_string_for("150")
32
+ (100..200).should === numerical_string_for("0150")
33
+ (100..200).should_not === numerical_string_for("1000000")
34
+ end
35
+
36
+ it "comparing against a regular expression works" do
37
+ %r|^\d+$|.should === numerical_string_for("027316287")
38
+ end
39
+
40
+ it "checking if a string representation of a number starts with a leading zero" do
41
+ with_leading_zeros = %w(01 01234 01.23 01.2)
42
+ without_leading_zeros = %w(1 1.2 0 0.0)
43
+
44
+ with_leading_zeros.each do |number|
45
+ numerical_string.starts_with_leading_zero?(number).should_not be false
46
+ end
47
+
48
+ without_leading_zeros.each do |number|
49
+ numerical_string.starts_with_leading_zero?(number).should_not be true
50
+ end
51
+ end
52
+
53
+ private
54
+ def numerical_string
55
+ Adhearsion::VoIP::DSL::NumericalString
56
+ end
57
+
58
+ def numerical_string_for(string)
59
+ numerical_string.new(string)
60
+ end
61
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'adhearsion/voip/constants'
3
+ require 'adhearsion/voip/dsl/numerical_string'
4
+
5
+
6
+ # Use cases...
7
+ # case extension
8
+ # when US_NUMBER
9
+ # when (100..200)
10
+ # when _('12Z')
11
+ # when 123
12
+ # when "123"
13
+ # end
14
+
15
+ def should_be_nil_or_false(arg)
16
+ [nil, false].include?(arg).should == true
17
+ end
18
+
19
+ def should_not_be_nil_or_false(arg)
20
+ [nil, false].include?(arg).should == false
21
+ end
22
+
23
+ describe "A PhoneNumber" do
24
+
25
+ it "should have an ISN pattern-matching method" do
26
+ should_be_nil_or_false Adhearsion::VoIP::DSL::PhoneNumber.new("0115544332211").isn?
27
+ should_not_be_nil_or_false Adhearsion::VoIP::DSL::PhoneNumber.new("1*548").isn?
28
+ end
29
+
30
+ it "should have a US local number pattern-matching method" do
31
+ should_be_nil_or_false Adhearsion::VoIP::DSL::PhoneNumber.new("18887776665555").us_local_number?
32
+ should_be_nil_or_false Adhearsion::VoIP::DSL::PhoneNumber.new("18887776665555").us_national_number?
33
+
34
+ should_be_nil_or_false Adhearsion::VoIP::DSL::PhoneNumber.new("8887776665555").us_local_number?
35
+ should_be_nil_or_false Adhearsion::VoIP::DSL::PhoneNumber.new("8887776665555").us_national_number?
36
+
37
+ should_not_be_nil_or_false Adhearsion::VoIP::DSL::PhoneNumber.new("4445555").us_local_number?
38
+ should_be_nil_or_false Adhearsion::VoIP::DSL::PhoneNumber.new("4445555").us_national_number?
39
+ end
40
+
41
+ it "should convert from vanity numbers properly" do
42
+ Adhearsion::VoIP::DSL::PhoneNumber.from_vanity("1-800-FUDGEME").should == "18003834363"
43
+ end
44
+
45
+ end
@@ -0,0 +1,7 @@
1
+ events.stomp.this_is_a_dynamic_name.each do
2
+
3
+ end
4
+
5
+ events.stomp.new_call.each do
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+ =begin YAML
2
+ namespaces:
3
+ - ["asterisk", "before_call"]
4
+ =end
5
+ events.asterisk.before_call.each do |call|
6
+ call.variables[:channel]
7
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe "CallbackDefinitionContainer" do
4
+
5
+ it "should successfully load the :simple_before_call example" do
6
+ example = Example.new(:simple_before_call)
7
+ theatre = Theatre::Theatre.new
8
+ example.register_namespaces_on theatre
9
+
10
+ flexmock(theatre.namespace_manager).should_receive(:register_callback_at_namespace).
11
+ with([:asterisk, :before_call], Proc).once
12
+
13
+ loader = Theatre::CallbackDefinitionLoader.new(theatre)
14
+ loader.load_events_file example.file
15
+ end
16
+
17
+ it "should let you override the recorder method name" do
18
+ theatre = Theatre::Theatre.new
19
+ theatre.namespace_manager.register_namespace_name "/foo/bar/qaz"
20
+ flexmock(theatre.namespace_manager).should_receive(:register_callback_at_namespace).
21
+ with([:foo, :bar, :qaz], Proc).once
22
+
23
+ loader = Theatre::CallbackDefinitionLoader.new(theatre, :roflcopter)
24
+ loader.roflcopter.foo.bar.qaz.each {}
25
+ end
26
+
27
+ end
28
+
29
+ # High level specs to test the entire library.
30
+
31
+ describe "Misuses of the Theatre" do
32
+
33
+ it "should not allow callbacks to be registered for namespaces which have not been registered" do
34
+ theatre = Theatre::Theatre.new
35
+ example = Example.new(:simple_before_call)
36
+
37
+ loader = Theatre::CallbackDefinitionLoader.new(theatre)
38
+ lambda do
39
+ loader.events.foo.each {}
40
+ end.should raise_error(Theatre::NamespaceNotFound)
41
+ end
42
+
43
+ end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+
3
+ GUID_REGEXP = /^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$/i
4
+
5
+ module InvocationTestHelper
6
+ def new_invocation(payload=@payload)
7
+ Theatre::Invocation.new(@namespace, @block, @payload)
8
+ end
9
+ end
10
+
11
+ describe "The lifecycle of an Invocation" do
12
+
13
+ include InvocationTestHelper
14
+
15
+ before :all do
16
+ @block = lambda {}
17
+ @payload = 123
18
+ @namespace = "/some/namespace"
19
+ end
20
+
21
+ it "should have an initial state of :new" do
22
+ new_invocation.current_state.should eql(:new)
23
+ end
24
+
25
+ it "should not have a @queued_time until state becomes :queued" do
26
+ invocation = new_invocation
27
+ invocation.queued_time.should eql(nil)
28
+ invocation.queued
29
+ invocation.queued_time.should be_instance_of(Time)
30
+ invocation.current_state.should eql(:queued)
31
+ end
32
+
33
+ it "should have a valid guid when instantiated" do
34
+ new_invocation.unique_id.should =~ GUID_REGEXP
35
+ end
36
+
37
+ it "should execute the callback when moving to the 'start' state" do
38
+ flexmock(@block).should_receive(:call).once
39
+ invocation = new_invocation
40
+ invocation.queued
41
+ invocation.start
42
+ end
43
+
44
+ end
45
+
46
+ describe "Using Invocations that've been ran through the Theatre" do
47
+
48
+ it "should pass the payload to the callback" do
49
+ destined_payload = [:i_feel_so_pretty, :OH, :SO, :PRETTY!]
50
+ expecting_callback = lambda do |payload|
51
+ payload.should equal(destined_payload)
52
+ end
53
+ invocation = Theatre::Invocation.new("/namespace/whatever", expecting_callback, destined_payload)
54
+ invocation.queued
55
+ invocation.start
56
+ end
57
+
58
+ it "should have a status of :error if an exception was raised and set the #error property" do
59
+ errorful_callback = lambda { raise ArgumentError, "this error is intentional" } # Simulate logic error
60
+ invocation = Theatre::Invocation.new("/namespace/whatever", errorful_callback)
61
+ invocation.queued
62
+ invocation.start
63
+ invocation.current_state.should equal(:error)
64
+ invocation.should be_error
65
+ invocation.error.should be_instance_of(ArgumentError)
66
+ end
67
+
68
+ it "should have a status of :success if no expection was raised" do
69
+ callback = lambda { "No errors raised here!" }
70
+ invocation = Theatre::Invocation.new("/namespace/whatever", callback)
71
+ invocation.queued
72
+ invocation.start
73
+ invocation.current_state.should equal(:success)
74
+ invocation.should be_success
75
+ end
76
+
77
+ it "should set the #returned_value property to the returned value callback when a payload was given" do
78
+ doubler = lambda { |num| num * 2 }
79
+ invocation = Theatre::Invocation.new('/foo/bar', doubler, 5)
80
+ invocation.queued
81
+ invocation.start
82
+ invocation.returned_value.should equal(10)
83
+ end
84
+
85
+ it "should set the #returned_value property to the returned value callback when a payload was NOT given" do
86
+ doubler = lambda { :ohai }
87
+ invocation = Theatre::Invocation.new('/foo/bar', doubler)
88
+ invocation.queued
89
+ invocation.start
90
+ invocation.returned_value.should equal(:ohai)
91
+ end
92
+
93
+ it "should set the #finished_time property when a success was encountered" do
94
+ block = lambda {}
95
+ invocation = Theatre::Invocation.new('/foo/bar', block)
96
+ invocation.queued
97
+
98
+ now = Time.now
99
+ flexmock(Time).should_receive(:now).twice.and_return now
100
+
101
+ invocation.start
102
+ invocation.should be_success
103
+ end
104
+
105
+ it "should set the #finished_time property when a failure was encountered" do
106
+ block = lambda { raise LocalJumpError }
107
+ invocation = Theatre::Invocation.new('/foo/bar', block)
108
+ invocation.queued
109
+
110
+ now = Time.now
111
+ flexmock(Time).should_receive(:now).twice.and_return now
112
+
113
+ invocation.start
114
+ invocation.should be_error
115
+ end
116
+
117
+ it "should set the #started_time property after starting" do
118
+ invocation = Theatre::Invocation.new('/foo/bar', lambda { sleep 0.01 } )
119
+ invocation.queued
120
+ invocation.started_time.should be_nil
121
+ invocation.start
122
+ invocation.started_time.should be_kind_of(Time)
123
+ end
124
+
125
+ it "should properly calculate #execution_duration" do
126
+ time_ago_difference = 60 * 5 # Five minutes
127
+ time_now = Time.now
128
+ time_ago = time_now - time_ago_difference
129
+
130
+ invocation = Theatre::Invocation.new('/foo/bar', lambda {} )
131
+ invocation.queued
132
+ invocation.start
133
+
134
+ invocation.send(:instance_variable_set, :@started_time, time_ago)
135
+ invocation.send(:instance_variable_set, :@finished_time, time_now)
136
+
137
+ invocation.execution_duration.should be_close(time_ago_difference.to_f, 0.01)
138
+ end
139
+
140
+ it "should return the set value of returned_value when one has been set to a non-nil value" do
141
+ return_nil = lambda { 123 }
142
+ invocation = Theatre::Invocation.new("/namespace/whatever", return_nil)
143
+ invocation.queued
144
+ invocation.start
145
+ invocation.returned_value.should eql(123)
146
+ end
147
+
148
+ it "should return nil for returned_value when it has been set to nil" do
149
+ return_nil = lambda { nil }
150
+ invocation = Theatre::Invocation.new("/namespace/whatever", return_nil)
151
+ invocation.queued
152
+ invocation.start
153
+ invocation.returned_value.should eql(nil)
154
+ end
155
+
156
+ it "waiting on an Invocation should execute properly" do
157
+ wait_on_invocation = lambda { 123 }
158
+ invocation = Theatre::Invocation.new("/namespace/whatever", wait_on_invocation)
159
+ Thread.new do
160
+ invocation.queued
161
+ invocation.start
162
+ end
163
+ invocation.wait.should eql(123)
164
+ invocation.success?.should eql(true)
165
+ end
166
+
167
+ end
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+
3
+ module NamespaceHelper
4
+ class BeValidNamespace
5
+
6
+ def matches?(target)
7
+ @target = target
8
+ Theatre::ActorNamespaceManager.valid_namespace_path? target
9
+ end
10
+
11
+ def failure_message
12
+ "expected #{@target.inspect} to be a valid namespace"
13
+ end
14
+
15
+ def negative_failure_message
16
+ "expected #{@target.inspect} not to be a valid namespace"
17
+ end
18
+
19
+ end
20
+
21
+ def be_valid_actor_event_namespace
22
+ BeValidNamespace.new
23
+ end
24
+
25
+ end
26
+
27
+ describe "ActorNamespaceManager" do
28
+
29
+ it "should make a registered namespace findable once registered" do
30
+ nm = Theatre::ActorNamespaceManager.new
31
+ nm.register_namespace_name "/foo/bar/qaz"
32
+ nm.search_for_namespace("/foo/bar/qaz").should be_kind_of(Theatre::ActorNamespaceManager::NamespaceNode)
33
+ end
34
+
35
+ it "should return the new namespace when registering it" do
36
+
37
+ end
38
+
39
+ it "#search_for_namespace should raise a NamespaceNotFound exception if a namespace one level deep was not found" do
40
+ nm = Theatre::ActorNamespaceManager.new
41
+ lambda do
42
+ nm.search_for_namespace "/foo"
43
+ end.should raise_error(Theatre::NamespaceNotFound)
44
+ end
45
+
46
+ it "#search_for_namespace should raise a NamespaceNotFound exception if a namespace two levels deep was not found" do
47
+ nm = Theatre::ActorNamespaceManager.new
48
+ lambda do
49
+ nm.search_for_namespace "/foo/bar"
50
+ end.should raise_error(Theatre::NamespaceNotFound)
51
+ end
52
+
53
+ describe '::normalize_path_to_array' do
54
+ it "should split a standard path properly" do
55
+ Theatre::ActorNamespaceManager.normalize_path_to_array("/foo/bar/qaz").should == [:foo, :bar, :qaz]
56
+ end
57
+
58
+ it "should split out Array()'d form of a String path properly" do
59
+ Theatre::ActorNamespaceManager.normalize_path_to_array(["/jay/thomas/phillips"]).should == [:jay,:thomas,:phillips]
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ describe "NamespaceNode" do
66
+
67
+ it "when registering a new namespace, the new NamespaceNode should be returned" do
68
+ node = Theatre::ActorNamespaceManager::NamespaceNode.new "foobar"
69
+ node.register_namespace_name("foobar").should be_instance_of(Theatre::ActorNamespaceManager::NamespaceNode)
70
+ end
71
+
72
+ it "should not blow away an existing callback when registering a new one with the same name" do
73
+ name = "blah"
74
+ node = Theatre::ActorNamespaceManager::NamespaceNode.new name
75
+ node.register_namespace_name name
76
+ before = node.child_named(name)
77
+ before.should be_instance_of(Theatre::ActorNamespaceManager::NamespaceNode)
78
+ node.register_namespace_name name
79
+ before.should eql(node.child_named(name))
80
+ end
81
+
82
+ describe '#register_namespace_name' do
83
+ it "should return the NamespaceNode" do
84
+ Theatre::ActorNamespaceManager::NamespaceNode.new("foo").register_namespace_name("bar").should \
85
+ be_instance_of(Theatre::ActorNamespaceManager::NamespaceNode)
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ describe "Valid namespace segments" do
92
+
93
+ include NamespaceHelper
94
+
95
+ describe "a valid namespace path" do
96
+
97
+ it "should require a namespace path start with a /" do
98
+ "/foo". should be_valid_actor_event_namespace
99
+ "foo". should_not be_valid_actor_event_namespace
100
+ "foo/bar".should_not be_valid_actor_event_namespace
101
+ end
102
+
103
+ it "should allow multiple namespace segments" do
104
+ "/foo_foo/bar".should be_valid_actor_event_namespace
105
+ end
106
+
107
+ it "should not allow a trailing forward slash" do
108
+ "/foo/bar/".should_not be_valid_actor_event_namespace
109
+ end
110
+
111
+ it "should not allow backslashes" do
112
+ '\foo'.should_not be_valid_actor_event_namespace
113
+ '\foo\bar'.should_not be_valid_actor_event_namespace
114
+ 'foo\bar'.should_not be_valid_actor_event_namespace
115
+ '\bar\\'.should_not be_valid_actor_event_namespace
116
+ end
117
+
118
+ it "should not allow weird characters" do
119
+ %w[ ! @ # $ % ^ & * ( ) { } | ' : ? > < - = ].each do |bad_character|
120
+ "/foo#{bad_character}foo/bar".should_not be_valid_actor_event_namespace
121
+ end
122
+ end
123
+
124
+ end
125
+ end