volt 0.9.3.pre1 → 0.9.3.pre2

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 (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)