volt 0.9.3.pre1 → 0.9.3.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +15 -1
  4. data/Gemfile +30 -3
  5. data/README.md +7 -2
  6. data/Rakefile +17 -0
  7. data/app/volt/models/user.rb +1 -1
  8. data/app/volt/tasks/live_query/live_query.rb +0 -1
  9. data/app/volt/tasks/live_query/live_query_pool.rb +8 -2
  10. data/app/volt/tasks/live_query/query_tracker.rb +2 -2
  11. data/app/volt/tasks/query_tasks.rb +10 -27
  12. data/app/volt/tasks/store_tasks.rb +6 -5
  13. data/app/volt/tasks/user_tasks.rb +2 -2
  14. data/docs/UPGRADE_GUIDE.md +14 -0
  15. data/lib/volt/boot.rb +1 -0
  16. data/lib/volt/cli/asset_compile.rb +25 -7
  17. data/lib/volt/cli/console.rb +6 -5
  18. data/lib/volt/cli/generate.rb +2 -2
  19. data/lib/volt/config.rb +2 -1
  20. data/lib/volt/controllers/http_controller.rb +4 -3
  21. data/lib/volt/controllers/model_controller.rb +41 -19
  22. data/lib/volt/controllers/template_helpers.rb +19 -0
  23. data/lib/volt/extra_core/array.rb +6 -0
  24. data/lib/volt/extra_core/hash.rb +8 -26
  25. data/lib/volt/extra_core/string.rb +1 -1
  26. data/lib/volt/models/array_model.rb +12 -4
  27. data/lib/volt/models/associations.rb +11 -13
  28. data/lib/volt/models/buffer.rb +1 -1
  29. data/lib/volt/models/model.rb +22 -13
  30. data/lib/volt/models/model_helpers/model_change_helpers.rb +0 -1
  31. data/lib/volt/models/model_helpers/model_helpers.rb +11 -0
  32. data/lib/volt/models/permissions.rb +9 -12
  33. data/lib/volt/models/persistors/array_store.rb +7 -7
  34. data/lib/volt/models/persistors/base.rb +9 -0
  35. data/lib/volt/models/persistors/cookies.rb +0 -4
  36. data/lib/volt/models/persistors/flash.rb +0 -4
  37. data/lib/volt/models/persistors/local_store.rb +0 -4
  38. data/lib/volt/models/persistors/model_store.rb +13 -21
  39. data/lib/volt/models/persistors/page.rb +22 -0
  40. data/lib/volt/models/persistors/params.rb +0 -4
  41. data/lib/volt/models/persistors/query/query_listener.rb +3 -2
  42. data/lib/volt/models/url.rb +2 -2
  43. data/lib/volt/models/validators/unique_validator.rb +1 -1
  44. data/lib/volt/models.rb +1 -0
  45. data/lib/volt/page/bindings/attribute_binding.rb +2 -2
  46. data/lib/volt/page/bindings/base_binding.rb +7 -3
  47. data/lib/volt/page/bindings/bindings.rb +9 -0
  48. data/lib/volt/page/bindings/content_binding.rb +2 -2
  49. data/lib/volt/page/bindings/each_binding.rb +16 -12
  50. data/lib/volt/page/bindings/event_binding.rb +4 -4
  51. data/lib/volt/page/bindings/if_binding.rb +3 -3
  52. data/lib/volt/page/bindings/view_binding.rb +4 -4
  53. data/lib/volt/page/bindings/yield_binding.rb +3 -3
  54. data/lib/volt/page/channel.rb +6 -0
  55. data/lib/volt/page/channel_stub.rb +1 -1
  56. data/lib/volt/page/page.rb +20 -54
  57. data/lib/volt/page/path_string_renderer.rb +5 -6
  58. data/lib/volt/page/string_template_renderer.rb +2 -2
  59. data/lib/volt/page/targets/attribute_section.rb +47 -0
  60. data/lib/volt/page/targets/base_section.rb +5 -5
  61. data/lib/volt/page/targets/binding_document/component_node.rb +6 -1
  62. data/lib/volt/page/template_renderer.rb +4 -4
  63. data/lib/volt/reactive/computation.rb +32 -3
  64. data/lib/volt/router/routes.rb +5 -5
  65. data/lib/volt/server/component_templates.rb +30 -2
  66. data/lib/volt/server/forking_server.rb +2 -2
  67. data/lib/volt/server/message_bus/base_message_bus.rb +52 -0
  68. data/lib/volt/server/message_bus/message_encoder.rb +64 -0
  69. data/lib/volt/server/message_bus/peer_to_peer/peer_connection.rb +186 -0
  70. data/lib/volt/server/message_bus/peer_to_peer/peer_server.rb +78 -0
  71. data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +57 -0
  72. data/lib/volt/server/message_bus/peer_to_peer/socket_with_timeout.rb +27 -0
  73. data/lib/volt/server/message_bus/peer_to_peer.rb +198 -0
  74. data/lib/volt/server/message_bus/redis.rb +1 -0
  75. data/lib/volt/server/rack/asset_files.rb +2 -2
  76. data/lib/volt/server/rack/component_paths.rb +1 -1
  77. data/lib/volt/server/rack/http_resource.rb +3 -2
  78. data/lib/volt/server/rack/opal_files.rb +6 -9
  79. data/lib/volt/server/websocket/websocket_handler.rb +0 -3
  80. data/lib/volt/server.rb +5 -3
  81. data/lib/volt/spec/setup.rb +11 -12
  82. data/lib/volt/tasks/dispatcher.rb +8 -12
  83. data/lib/volt/tasks/task_handler.rb +3 -2
  84. data/lib/volt/utils/csso_patch.rb +24 -0
  85. data/lib/volt/utils/promise_patch.rb +2 -0
  86. data/lib/volt/version.rb +1 -1
  87. data/lib/volt/volt/app.rb +73 -36
  88. data/lib/volt/volt/server_setup/app.rb +81 -0
  89. data/lib/volt.rb +22 -1
  90. data/spec/apps/kitchen_sink/Gemfile +1 -1
  91. data/spec/controllers/http_controller_spec.rb +5 -3
  92. data/spec/controllers/model_controller_spec.rb +2 -2
  93. data/spec/extra_core/hash_spec.rb +9 -0
  94. data/spec/integration/list_spec.rb +3 -3
  95. data/spec/models/associations_spec.rb +10 -2
  96. data/spec/models/dirty_spec.rb +7 -7
  97. data/spec/models/model_spec.rb +10 -2
  98. data/spec/models/permissions_spec.rb +9 -0
  99. data/spec/models/persistors/store_spec.rb +8 -0
  100. data/spec/page/bindings/content_binding_spec.rb +6 -2
  101. data/spec/page/bindings/each_binding_spec.rb +59 -0
  102. data/spec/page/bindings/if_binding_spec.rb +57 -0
  103. data/spec/page/path_string_renderer_spec.rb +5 -5
  104. data/spec/reactive/computation_spec.rb +65 -1
  105. data/spec/router/routes_spec.rb +1 -1
  106. data/spec/server/html_parser/sandlebars_parser_spec.rb +12 -22
  107. data/spec/server/message_bus/message_encoder_spec.rb +49 -0
  108. data/spec/server/message_bus/peer_to_peer/peer_connection_spec.rb +108 -0
  109. data/spec/server/message_bus/peer_to_peer/peer_server_spec.rb +66 -0
  110. data/spec/server/message_bus/peer_to_peer/socket_with_timeout_spec.rb +11 -0
  111. data/spec/server/message_bus/peer_to_peer_spec.rb +11 -0
  112. data/spec/server/rack/asset_files_spec.rb +1 -1
  113. data/spec/server/rack/http_resource_spec.rb +4 -4
  114. data/spec/spec_helper.rb +16 -3
  115. data/spec/tasks/dispatcher_spec.rb +17 -5
  116. data/spec/tasks/live_query_spec.rb +1 -1
  117. data/spec/tasks/query_tracker_spec.rb +34 -34
  118. data/spec/tasks/user_tasks_spec.rb +4 -2
  119. data/templates/project/Gemfile.tt +14 -3
  120. data/templates/project/config/app.rb.tt +27 -2
  121. data/volt.gemspec +3 -8
  122. metadata +32 -101
  123. data/docs/FAQ.md +0 -7
@@ -61,7 +61,7 @@ describe Volt::Model do
61
61
 
62
62
  it "should return an empty model for an underscore value that doesn't exist" do
63
63
  a = Volt::Model.new
64
- expect(a._something!.attributes).to eq({})
64
+ expect(a._something!.attributes.without(:id)).to eq({})
65
65
  end
66
66
 
67
67
  it 'should trigger changed once when a new value is assigned.' do
@@ -425,7 +425,15 @@ describe Volt::Model do
425
425
  { name: 'Test1', other: { time: 'Now' } },
426
426
  { name: 'Test2', other: { time: 'Later' } }
427
427
  ]
428
- expect(all_items).to eq(a)
428
+
429
+ # Remove id's nested
430
+ items = all_items.map do |hash|
431
+ hash.without(:id).map do |k,v|
432
+ v = v.without(:id) if v.is_a?(Hash)
433
+ [k,v]
434
+ end.to_h
435
+ end
436
+ expect(items).to eq(a)
429
437
  end
430
438
 
431
439
  describe 'model paths' do
@@ -47,6 +47,13 @@ class ::TestUpdateReadCheck < Volt::Model
47
47
  end
48
48
 
49
49
  describe 'model permissions' do
50
+ let(:user_todo) { TestUserTodo.new }
51
+
52
+ it 'auto-associates users via own_by_user' do
53
+ #TODO: better assertions
54
+ expect(user_todo.respond_to?(:user)).to be(true)
55
+ end
56
+
50
57
  it 'should follow CRUD states when checking permissions' do
51
58
  todo = TestUserTodoWithCrudStates.new.buffer
52
59
 
@@ -111,6 +118,8 @@ describe 'model permissions' do
111
118
  it 'should not check the read permissions when updating (so that all fields are present for the permissions check)' do
112
119
  model = store._test_update_read_checks!.append(name: 'Ryan').sync
113
120
 
121
+ expect(model.new?).to eq(false)
122
+
114
123
  expect(model.create_check).to eq(true)
115
124
  expect(model.read_check).to eq(nil)
116
125
 
@@ -27,4 +27,12 @@ describe Volt::Persistors::Store do
27
27
 
28
28
  @model << 4
29
29
  end
30
+
31
+ it 'passes removed() to changed() by default' do
32
+ model = Volt::Model.new(abc: 123)
33
+ persistor = Volt::Persistors::Store.new(model)
34
+ expect(persistor.removed(:abc)).to eq(persistor.changed(:abc))
35
+ model._abc = 456
36
+ expect(persistor.removed(:abc)).to eq(persistor.changed(:abc))
37
+ end
30
38
  end
@@ -15,7 +15,7 @@ describe Volt::ContentBinding do
15
15
 
16
16
  it 'should render with a template' do
17
17
  context = { name: 'jimmy' }
18
- binding = ->(page, target, context, id) { Volt::ContentBinding.new(page, target, context, id, proc { self[:name] }) }
18
+ binding = ->(volt_app, target, context, id) { Volt::ContentBinding.new(volt_app, target, context, id, proc { self[:name] }) }
19
19
 
20
20
  templates = {
21
21
  'main/main' => {
@@ -27,9 +27,13 @@ describe Volt::ContentBinding do
27
27
  page = double('volt/page')
28
28
  expect(page).to receive(:templates).and_return(templates)
29
29
 
30
+ volt_app = double('volt/app')
31
+ expect(volt_app).to receive(:page).and_return(page)
32
+
33
+
30
34
  dom = Volt::AttributeTarget.new(0)
31
35
 
32
- Volt::TemplateRenderer.new(page, dom, context, 'main', 'main/main')
36
+ Volt::TemplateRenderer.new(volt_app, dom, context, 'main', 'main/main')
33
37
 
34
38
  expect(dom.to_html).to eq('hello jimmy')
35
39
  end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ class ::TestEachBindingController < Volt::ModelController
4
+ model :page
5
+ end
6
+
7
+ describe Volt::EachBinding do
8
+ it 'should render an each binding' do
9
+ dom = Volt::AttributeTarget.new(0)
10
+ context = ::TestEachBindingController.new(volt_app)
11
+ context._items << {name: 'One'}
12
+ context._items << {name: 'Two'}
13
+
14
+
15
+ getter = Proc.new { context._items }
16
+ variable_name = 'item'
17
+ index_name = 'index'
18
+ template_name = 'main/item'
19
+
20
+ # Setup the each binding
21
+ each_binding = ->(volt_app, target, context, id) do
22
+ Volt::EachBinding.new(volt_app, target, context, id, getter,
23
+ variable_name, index_name, template_name)
24
+ end
25
+
26
+ # Setup a content binding to make sure its passing the right item
27
+ content_binding = ->(volt_app, target, context, id) do
28
+ Volt::ContentBinding.new(volt_app, target, context, id,
29
+ proc { item._name })
30
+ end
31
+
32
+ templates = {
33
+ 'main/main' => {
34
+ 'html' => 'hello <!-- $1 --><!-- $/1 -->',
35
+ 'bindings' => { 1 => [each_binding] }
36
+ },
37
+ 'main/item' => {
38
+ 'html' => '<!-- $2 --><!-- $/2 -->, ',
39
+ 'bindings' => {
40
+ 2 => [content_binding]
41
+ }
42
+ }
43
+ }
44
+
45
+ page = double('volt/page')
46
+ expect(page).to receive(:templates).and_return(templates).at_least(1).times
47
+
48
+ volt_app = double('volt/app')
49
+ expect(volt_app).to receive(:page).and_return(page).at_least(1).times
50
+
51
+ Volt::TemplateRenderer.new(volt_app, dom, context, 'main', 'main/main')
52
+
53
+ expect(dom.to_html).to eq('hello One, Two, ')
54
+
55
+ context._items << {name: 'Three'}
56
+ Volt::Computation.flush!
57
+ expect(dom.to_html).to eq('hello One, Two, Three, ')
58
+ end
59
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ class ::TestIfBindingController < Volt::ModelController
4
+ model :page
5
+ end
6
+
7
+ describe Volt::IfBinding do
8
+ it 'should render an if' do
9
+ dom = Volt::AttributeTarget.new(0)
10
+ context = ::TestIfBindingController.new(volt_app)
11
+ context._name = 'jimmy'
12
+
13
+ branches = [
14
+ [
15
+ proc { _name == 'jimmy' },
16
+ 'main/if_true'
17
+ ],
18
+ [
19
+ nil,
20
+ 'main/if_false'
21
+ ]
22
+ ]
23
+
24
+ binding = ->(volt_app, target, context, id) do
25
+ Volt::IfBinding.new(volt_app, target, context, 0, branches)
26
+ end
27
+
28
+ templates = {
29
+ 'main/main' => {
30
+ 'html' => 'hello <!-- $1 --><!-- $/1 -->',
31
+ 'bindings' => { 1 => [binding] }
32
+ },
33
+ 'main/if_true' => {
34
+ 'html' => 'yes, true',
35
+ 'bindings' => {}
36
+ },
37
+ 'main/if_false' => {
38
+ 'html' => 'no, false',
39
+ 'bindings' => {}
40
+ }
41
+ }
42
+
43
+ page = double('volt/page')
44
+ expect(page).to receive(:templates).and_return(templates).at_least(1).times
45
+
46
+ volt_app = double('volt/app')
47
+ expect(volt_app).to receive(:page).and_return(page).at_least(1).times
48
+
49
+ Volt::TemplateRenderer.new(volt_app, dom, context, 'main', 'main/main')
50
+
51
+ expect(dom.to_html).to eq('yes, true')
52
+
53
+ context._name = 'bob'
54
+ Volt::Computation.flush!
55
+ expect(dom.to_html).to eq('no, false')
56
+ end
57
+ end
@@ -5,23 +5,23 @@ unless RUBY_PLATFORM == 'opal'
5
5
  describe Volt::PathStringRenderer do
6
6
  before do
7
7
  kitchen_sink_path = File.expand_path(File.join(File.dirname(__FILE__), '../apps/kitchen_sink'))
8
- app = Volt::App.new(kitchen_sink_path)
9
- @page = app.page
8
+ @volt_app = Volt::App.new(kitchen_sink_path)
9
+ @page = @volt_app.page
10
10
  end
11
11
 
12
12
  it 'should render a section' do
13
- html = Volt::PathStringRenderer.new('main/mailers/welcome/subject', nil, @page).html
13
+ html = Volt::PathStringRenderer.new(@volt_app, 'main/mailers/welcome/subject', nil, @page).html
14
14
  expect(html).to eq("\n Welcome to the site!\n\n")
15
15
  end
16
16
 
17
17
  it 'should render a section with a variable' do
18
- html = Volt::PathStringRenderer.new('main/mailers/welcome/html', { name: 'Jimmy' }, @page).html
18
+ html = Volt::PathStringRenderer.new(@volt_app, 'main/mailers/welcome/html', { name: 'Jimmy' }, @page).html
19
19
  expect(html).to eq("\n <h1>Welcome Jimmy</h1>\n\n <p>Glad you signed up!</p>\n\n")
20
20
  end
21
21
 
22
22
  it 'Raises raises ViewLookupException if full_path is nil' do
23
23
  expect do
24
- Volt::PathStringRenderer.new('', { name: 'Jimmy' }, Volt::Page.new).html
24
+ Volt::PathStringRenderer.new(@volt_app, '', { name: 'Jimmy' }, Volt::Page.new(@volt_app)).html
25
25
  end.to raise_error(Volt::ViewLookupException)
26
26
  end
27
27
  end
@@ -114,7 +114,7 @@ describe Volt::Computation do
114
114
 
115
115
  describe 'watch_and_resolve!' do
116
116
  it 'should resolve any returnted promises' do
117
- promise = Promise.new.resolve('resolved')
117
+ promise = Promise.new
118
118
  count = 0
119
119
 
120
120
  -> { promise }.watch_and_resolve! do |result|
@@ -122,8 +122,72 @@ describe Volt::Computation do
122
122
  count += 1
123
123
  end
124
124
 
125
+ expect(count).to eq(0)
126
+
127
+ promise.resolve('resolved')
128
+
129
+ Volt::Computation.flush!
125
130
  expect(count).to eq(1)
126
131
  end
132
+
133
+ it 'should not resolve a promise if another value came in' do
134
+ dep = Volt::Dependency.new
135
+
136
+ promise = Promise.new
137
+ cur_val = promise
138
+
139
+ results = []
140
+ -> { dep.depend ; cur_val }.watch_and_resolve! do |val|
141
+ results << val
142
+ end
143
+
144
+ expect(results).to eq([])
145
+
146
+ cur_val = 5
147
+ dep.changed!
148
+ Volt::Computation.flush!
149
+
150
+ expect(results).to eq([5])
151
+
152
+ promise.resolve(10)
153
+ expect(results).to eq([5])
154
+ end
155
+
156
+ it 'should yield nil for an unresolved promise when asked' do
157
+ dep = Volt::Dependency.new
158
+
159
+ cur_val = Promise.new
160
+
161
+ results = []
162
+ -> { dep.depend ; cur_val }.watch_and_resolve!(true) do |val|
163
+ results << val
164
+ end
165
+
166
+ expect(results).to eq([nil])
167
+
168
+ cur_val.resolve(5)
169
+
170
+ expect(results).to eq([nil, 5])
171
+ end
172
+
173
+ it 'should not resolve if the computation was stopped' do
174
+ dep = Volt::Dependency.new
175
+
176
+ cur_val = Promise.new
177
+
178
+ results = []
179
+ computation = -> { dep.depend ; cur_val }.watch_and_resolve! do |val|
180
+ results << val
181
+ end
182
+
183
+ expect(results).to eq([])
184
+
185
+ computation.stop
186
+
187
+ cur_val.resolve(5)
188
+
189
+ expect(results).to eq([])
190
+ end
127
191
  end
128
192
 
129
193
  # Currently Class#class_variable_set/get isn't in opal
@@ -233,7 +233,7 @@ describe Volt::Routes do
233
233
 
234
234
  path, cleaned_params = @routes.params_to_url(params.to_h)
235
235
  expect(path).to eq('/blog')
236
- expect(cleaned_params).to eq(index: '5')
236
+ expect(cleaned_params.without(:id)).to eq(index: '5')
237
237
  end
238
238
 
239
239
  it 'should handle routes with bindings in them' do
@@ -37,20 +37,6 @@ class HTMLHandler
37
37
  end
38
38
  end
39
39
 
40
- def parse_url(url)
41
- require 'open-uri'
42
- html = open("http://#{url}").read
43
-
44
- # html = File.read("/Users/ryanstout/Desktop/tests/#{url}1.html")
45
-
46
- File.open("/Users/ryanstout/Desktop/tests/#{url}1.html", 'w') { |f| f.write(html) }
47
-
48
- handler = HTMLHandler.new
49
- Volt::SandlebarsParser.new(html, handler)
50
-
51
- File.open("/Users/ryanstout/Desktop/tests/#{url}2.html", 'w') { |f| f.write(handler.html) }
52
- end
53
-
54
40
  describe Volt::SandlebarsParser do
55
41
  def test_html(html, match = nil)
56
42
  handler = HTMLHandler.new
@@ -176,15 +162,19 @@ describe Volt::SandlebarsParser do
176
162
  test_html(html)
177
163
  end
178
164
 
179
- it 'should be fast' do
180
- html = File.read(File.join(File.dirname(__FILE__), 'sample_page.html'))
181
- handler = HTMLHandler.new
182
- time = Benchmark.measure do
183
- Volt::SandlebarsParser.new(html, handler)
184
- end
165
+ # On jruby, hotspot will optimize this, but it takes a while, so we should
166
+ # just look for MRI performance regresions
167
+ if RUBY_PLATFORM != 'java'
168
+ it 'should be fast' do
169
+ html = File.read(File.join(File.dirname(__FILE__), 'sample_page.html'))
170
+ handler = HTMLHandler.new
171
+ time = Benchmark.measure do
172
+ Volt::SandlebarsParser.new(html, handler)
173
+ end
185
174
 
186
- # Less than 100ms
187
- expect(time.total).to be < 0.1
175
+ # Less than 100ms
176
+ expect(time.total).to be < 0.1
177
+ end
188
178
  end
189
179
 
190
180
  it 'should parse nested components' do
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ unless RUBY_PLATFORM == 'opal'
4
+ describe Volt::MessageBus do
5
+ before do
6
+ # Stub socket stuff
7
+ allow_any_instance_of(Volt::MessageBus).to receive(:connect_to_peers).and_return(nil)
8
+ end
9
+
10
+ describe "encryption" do
11
+ before do
12
+ @msg_bus_config = double('volt/config')
13
+
14
+ expect(Volt.config).to receive(:message_bus).and_return(@msg_bus_config)
15
+ end
16
+
17
+ it 'should get disabled state from Volt.config.message_bus.encryption_disabled' do
18
+ expect(@msg_bus_config).to receive(:disable_encryption).and_return(true)
19
+
20
+ encoder = Volt::MessageBus::MessageEncoder.new
21
+
22
+ expect(encoder.encrypted).to eq(false)
23
+ end
24
+
25
+ it 'should get enabled state from Volt.config.message_bus.encryption_disabled' do
26
+ expect(@msg_bus_config).to receive(:disable_encryption).and_return(false)
27
+
28
+ encoder = Volt::MessageBus::MessageEncoder.new
29
+
30
+ expect(encoder.encrypted).to eq(true)
31
+ end
32
+ end
33
+
34
+ it 'should encrypt and decrypt' do
35
+ message = 'this is my message that should be encrypted'
36
+ encoder = Volt::MessageBus::MessageEncoder.new
37
+
38
+ encrypted_message = encoder.encrypt(message)
39
+
40
+ # Should be encrypted
41
+ expect(encrypted_message).to_not eq(message)
42
+
43
+ decrypted_message = encoder.decrypt(encrypted_message)
44
+
45
+ expect(decrypted_message).to eq(message)
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ unless RUBY_PLATFORM == 'opal'
4
+ describe Volt::MessageBus::PeerConnection do
5
+ describe 'pass the server_id back and forth' do
6
+ before do
7
+ @socket = double('socket')
8
+
9
+ @bus = double('message bus')
10
+ expect(@bus).to receive(:server_id).and_return('server one')
11
+ expect(@bus).to receive(:remove_duplicate_connections)
12
+
13
+ thread = double('thread')
14
+ allow(thread).to receive(:kill)
15
+ allow(Thread).to receive(:new).and_return(thread)
16
+
17
+ encoder = double('encoder')
18
+ expect(Volt::MessageBus::MessageEncoder).to receive(:new).and_return(encoder)
19
+
20
+ expect(encoder).to receive(:receive_message).with(@socket)
21
+ .and_return('server two')
22
+
23
+ expect(encoder).to receive(:send_message).with(@socket, 'server one')
24
+ end
25
+
26
+ it 'should on server' do
27
+ Volt::MessageBus::PeerConnection.new(@socket, nil, nil, @bus, true)
28
+ end
29
+
30
+ it 'should pass the server_id back and forth to client' do
31
+ Volt::MessageBus::PeerConnection.new(@socket, nil, nil, @bus)
32
+ end
33
+ end
34
+
35
+ class MessageBusDouble
36
+ def initialize(id, receiver)
37
+ @id = id
38
+ @receiver = receiver
39
+ end
40
+
41
+ def server_id
42
+ @id
43
+ end
44
+
45
+ def remove_duplicate_connections
46
+ end
47
+
48
+ def remove_peer_connection(conn)
49
+ end
50
+
51
+ def handle_message(message)
52
+ @receiver << message
53
+ end
54
+ end
55
+
56
+ # Disable for jruby for now
57
+ if RUBY_PLATFORM != 'java'
58
+ it 'should pass messages between two peer conections' do
59
+ responses1 = []
60
+ bus1 = MessageBusDouble.new('server one', responses1)
61
+
62
+ responses2 = []
63
+ bus2 = MessageBusDouble.new('server two', responses2)
64
+
65
+ server = TCPServer.new(0)
66
+ port = server.addr[1]
67
+
68
+ threads = []
69
+ threads << Thread.new do
70
+ @server = server.accept
71
+ end
72
+
73
+ threads << Thread.new do
74
+ @client = TCPSocket.new('localhost', port)
75
+ end
76
+
77
+ threads.each(&:join)
78
+
79
+ threads = []
80
+
81
+ conn1 = nil
82
+ threads << Thread.new do
83
+ conn1 = Volt::MessageBus::PeerConnection.new(@server, nil, nil, bus1, true)
84
+ end
85
+
86
+ conn2 = nil
87
+ threads << Thread.new do
88
+ conn2 = Volt::MessageBus::PeerConnection.new(@client, nil, nil, bus2)
89
+ end
90
+
91
+ threads.each(&:join)
92
+
93
+ conn1.publish('test message')
94
+
95
+ loop do
96
+ break if responses2.size > 0
97
+ sleep 0.05
98
+ end
99
+
100
+ expect(responses2).to eq(['test message'])
101
+
102
+ conn1.disconnect
103
+ conn2.disconnect
104
+
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ unless RUBY_PLATFORM == 'opal'
4
+ describe Volt::MessageBus::PeerServer do
5
+ describe "ip and ports" do
6
+ before do
7
+ allow_any_instance_of(Volt::MessageBus::PeerServer).to receive(:run_server)
8
+ end
9
+
10
+ it 'should use Volt.config.message_bus.bind_port_ranges to connect' do
11
+ config = double('volt/config')
12
+ expect(Volt.config).to receive(:message_bus).and_return(config)
13
+ .at_least(:once)
14
+
15
+ ports = [5000,6000,7000]
16
+
17
+ expect(config).to receive(:bind_port_ranges).and_return(ports)
18
+ .at_least(:once)
19
+
20
+ tried_ports = []
21
+
22
+ # Act like all sockets are in use to test NoAvailablePortException
23
+ expect(TCPServer).to receive(:new) do |port|
24
+ tried_ports << port
25
+ end.at_least(:once).and_raise(Errno::EADDRINUSE)
26
+
27
+ expect do
28
+ peer_server = Volt::MessageBus::PeerServer.new(nil)
29
+ end.to raise_error(Volt::MessageBus::NoAvailablePortException)
30
+
31
+ expect(tried_ports.sort).to eq(ports)
32
+ end
33
+ end
34
+
35
+ it 'should start a server that creates peer connections when accepted' do
36
+ expect(Thread).to receive(:new).and_yield
37
+ # The PeerConnection that will be created
38
+ new_peer = double('new peer connection')
39
+
40
+ message_bus = double('message bus')
41
+ expect(message_bus).to receive(:add_peer_connection) do |peer_conn|
42
+ expect(peer_conn).to eq(new_peer)
43
+ # Raise an exception to get out of the loop
44
+ end.and_raise(Exception)
45
+
46
+ # Stub the socket connection
47
+ socket = double('tcp server socket')
48
+
49
+ # Stub the incoming connection
50
+ connection = double('client socket connection')
51
+
52
+ expect(socket).to receive(:accept).and_return(connection)
53
+
54
+ expect(Thread).to receive(:start).with(connection).and_yield(connection)
55
+ expect(TCPServer).to receive(:new).and_return(socket)
56
+
57
+ expect(Volt::MessageBus::PeerConnection).to receive(:new)
58
+ .and_return(new_peer)
59
+
60
+ expect do
61
+ peer_server = Volt::MessageBus::PeerServer.new(message_bus)
62
+ end.to raise_error(Exception)
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ unless RUBY_PLATFORM == 'opal'
4
+ describe Volt::SocketWithTimeout do
5
+ it 'should setup a connection manually and then specify a timeout' do
6
+ allow_any_instance_of(Socket).to receive(:connect)
7
+
8
+ Volt::SocketWithTimeout.new('google.com', 80, 10)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ unless RUBY_PLATFORM == 'opal'
4
+ describe Volt::MessageBus::PeerToPeer do
5
+ before do
6
+ # Stub socket stuff
7
+ allow_any_instance_of(Volt::MessageBus::PeerToPeer).to receive(:connect_to_peers).and_return(nil)
8
+ end
9
+
10
+ end
11
+ end
@@ -19,7 +19,7 @@ if RUBY_PLATFORM != 'opal'
19
19
  it 'should list all JS files' do
20
20
  main = Volt::AssetFiles.new('main', @component_paths)
21
21
 
22
- expect(main.javascript_files(nil)).to eq(['/assets/js/jquery-2.0.3.js', '/assets/js/volt_js_polyfills.js', '/assets/js/volt_watch.js', '/assets/js/bootstrap.js', '/assets/js/test2.js', '/assets/js/test3.js', '/assets/js/test1.js', '/assets/volt/page/page.js', '/components/main.js'])
22
+ expect(main.javascript_files(nil)).to eq(['/assets/js/jquery-2.0.3.js', '/assets/js/volt_js_polyfills.js', '/assets/js/volt_watch.js', '/assets/js/bootstrap.js', '/assets/js/test2.js', '/assets/js/test3.js', '/assets/js/test1.js', '/assets/volt/volt/app.js', '/components/main.js'])
23
23
  end
24
24
 
25
25
  it 'should raise an exception for a missing component gem' do
@@ -34,10 +34,10 @@ if RUBY_PLATFORM != 'opal'
34
34
  end
35
35
 
36
36
  it 'should initialize the correct controller and call the correct action' do
37
- http_resource = Volt::HttpResource.new(app, @routes)
37
+ http_resource = Volt::HttpResource.new(app, volt_app, @routes)
38
38
  env = Rack::MockRequest.env_for('http://example.com/stuff')
39
39
  request = Volt::HttpRequest.new(env)
40
- controller = SimpleController.new({}, request)
40
+ controller = SimpleController.new(volt_app, {}, request)
41
41
  expect(SimpleController).to receive(:new).and_return(controller)
42
42
 
43
43
  response = http_resource.call(env)
@@ -47,7 +47,7 @@ if RUBY_PLATFORM != 'opal'
47
47
  end
48
48
 
49
49
  it 'should parse the correct params to the controller' do
50
- http_resource = Volt::HttpResource.new(app, @routes)
50
+ http_resource = Volt::HttpResource.new(app, volt_app, @routes)
51
51
  env = Rack::MockRequest.env_for('http://example.com/stuff/99?test=another_param')
52
52
  request = Volt::HttpRequest.new(env)
53
53
 
@@ -57,7 +57,7 @@ if RUBY_PLATFORM != 'opal'
57
57
  end
58
58
 
59
59
  it 'should call the supplied app if routes are not matched and cause a 404' do
60
- http_resource = Volt::HttpResource.new(app, @routes)
60
+ http_resource = Volt::HttpResource.new(app, volt_app, @routes)
61
61
  env = Rack::MockRequest.env_for('http://example.com/not_a_valid_param')
62
62
  request = Volt::HttpRequest.new(env)
63
63
  response = http_resource.call(env)