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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +15 -1
- data/Gemfile +30 -3
- data/README.md +7 -2
- data/Rakefile +17 -0
- data/app/volt/models/user.rb +1 -1
- data/app/volt/tasks/live_query/live_query.rb +0 -1
- data/app/volt/tasks/live_query/live_query_pool.rb +8 -2
- data/app/volt/tasks/live_query/query_tracker.rb +2 -2
- data/app/volt/tasks/query_tasks.rb +10 -27
- data/app/volt/tasks/store_tasks.rb +6 -5
- data/app/volt/tasks/user_tasks.rb +2 -2
- data/docs/UPGRADE_GUIDE.md +14 -0
- data/lib/volt/boot.rb +1 -0
- data/lib/volt/cli/asset_compile.rb +25 -7
- data/lib/volt/cli/console.rb +6 -5
- data/lib/volt/cli/generate.rb +2 -2
- data/lib/volt/config.rb +2 -1
- data/lib/volt/controllers/http_controller.rb +4 -3
- data/lib/volt/controllers/model_controller.rb +41 -19
- data/lib/volt/controllers/template_helpers.rb +19 -0
- data/lib/volt/extra_core/array.rb +6 -0
- data/lib/volt/extra_core/hash.rb +8 -26
- data/lib/volt/extra_core/string.rb +1 -1
- data/lib/volt/models/array_model.rb +12 -4
- data/lib/volt/models/associations.rb +11 -13
- data/lib/volt/models/buffer.rb +1 -1
- data/lib/volt/models/model.rb +22 -13
- data/lib/volt/models/model_helpers/model_change_helpers.rb +0 -1
- data/lib/volt/models/model_helpers/model_helpers.rb +11 -0
- data/lib/volt/models/permissions.rb +9 -12
- data/lib/volt/models/persistors/array_store.rb +7 -7
- data/lib/volt/models/persistors/base.rb +9 -0
- data/lib/volt/models/persistors/cookies.rb +0 -4
- data/lib/volt/models/persistors/flash.rb +0 -4
- data/lib/volt/models/persistors/local_store.rb +0 -4
- data/lib/volt/models/persistors/model_store.rb +13 -21
- data/lib/volt/models/persistors/page.rb +22 -0
- data/lib/volt/models/persistors/params.rb +0 -4
- data/lib/volt/models/persistors/query/query_listener.rb +3 -2
- data/lib/volt/models/url.rb +2 -2
- data/lib/volt/models/validators/unique_validator.rb +1 -1
- data/lib/volt/models.rb +1 -0
- data/lib/volt/page/bindings/attribute_binding.rb +2 -2
- data/lib/volt/page/bindings/base_binding.rb +7 -3
- data/lib/volt/page/bindings/bindings.rb +9 -0
- data/lib/volt/page/bindings/content_binding.rb +2 -2
- data/lib/volt/page/bindings/each_binding.rb +16 -12
- data/lib/volt/page/bindings/event_binding.rb +4 -4
- data/lib/volt/page/bindings/if_binding.rb +3 -3
- data/lib/volt/page/bindings/view_binding.rb +4 -4
- data/lib/volt/page/bindings/yield_binding.rb +3 -3
- data/lib/volt/page/channel.rb +6 -0
- data/lib/volt/page/channel_stub.rb +1 -1
- data/lib/volt/page/page.rb +20 -54
- data/lib/volt/page/path_string_renderer.rb +5 -6
- data/lib/volt/page/string_template_renderer.rb +2 -2
- data/lib/volt/page/targets/attribute_section.rb +47 -0
- data/lib/volt/page/targets/base_section.rb +5 -5
- data/lib/volt/page/targets/binding_document/component_node.rb +6 -1
- data/lib/volt/page/template_renderer.rb +4 -4
- data/lib/volt/reactive/computation.rb +32 -3
- data/lib/volt/router/routes.rb +5 -5
- data/lib/volt/server/component_templates.rb +30 -2
- data/lib/volt/server/forking_server.rb +2 -2
- data/lib/volt/server/message_bus/base_message_bus.rb +52 -0
- data/lib/volt/server/message_bus/message_encoder.rb +64 -0
- data/lib/volt/server/message_bus/peer_to_peer/peer_connection.rb +186 -0
- data/lib/volt/server/message_bus/peer_to_peer/peer_server.rb +78 -0
- data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +57 -0
- data/lib/volt/server/message_bus/peer_to_peer/socket_with_timeout.rb +27 -0
- data/lib/volt/server/message_bus/peer_to_peer.rb +198 -0
- data/lib/volt/server/message_bus/redis.rb +1 -0
- data/lib/volt/server/rack/asset_files.rb +2 -2
- data/lib/volt/server/rack/component_paths.rb +1 -1
- data/lib/volt/server/rack/http_resource.rb +3 -2
- data/lib/volt/server/rack/opal_files.rb +6 -9
- data/lib/volt/server/websocket/websocket_handler.rb +0 -3
- data/lib/volt/server.rb +5 -3
- data/lib/volt/spec/setup.rb +11 -12
- data/lib/volt/tasks/dispatcher.rb +8 -12
- data/lib/volt/tasks/task_handler.rb +3 -2
- data/lib/volt/utils/csso_patch.rb +24 -0
- data/lib/volt/utils/promise_patch.rb +2 -0
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +73 -36
- data/lib/volt/volt/server_setup/app.rb +81 -0
- data/lib/volt.rb +22 -1
- data/spec/apps/kitchen_sink/Gemfile +1 -1
- data/spec/controllers/http_controller_spec.rb +5 -3
- data/spec/controllers/model_controller_spec.rb +2 -2
- data/spec/extra_core/hash_spec.rb +9 -0
- data/spec/integration/list_spec.rb +3 -3
- data/spec/models/associations_spec.rb +10 -2
- data/spec/models/dirty_spec.rb +7 -7
- data/spec/models/model_spec.rb +10 -2
- data/spec/models/permissions_spec.rb +9 -0
- data/spec/models/persistors/store_spec.rb +8 -0
- data/spec/page/bindings/content_binding_spec.rb +6 -2
- data/spec/page/bindings/each_binding_spec.rb +59 -0
- data/spec/page/bindings/if_binding_spec.rb +57 -0
- data/spec/page/path_string_renderer_spec.rb +5 -5
- data/spec/reactive/computation_spec.rb +65 -1
- data/spec/router/routes_spec.rb +1 -1
- data/spec/server/html_parser/sandlebars_parser_spec.rb +12 -22
- data/spec/server/message_bus/message_encoder_spec.rb +49 -0
- data/spec/server/message_bus/peer_to_peer/peer_connection_spec.rb +108 -0
- data/spec/server/message_bus/peer_to_peer/peer_server_spec.rb +66 -0
- data/spec/server/message_bus/peer_to_peer/socket_with_timeout_spec.rb +11 -0
- data/spec/server/message_bus/peer_to_peer_spec.rb +11 -0
- data/spec/server/rack/asset_files_spec.rb +1 -1
- data/spec/server/rack/http_resource_spec.rb +4 -4
- data/spec/spec_helper.rb +16 -3
- data/spec/tasks/dispatcher_spec.rb +17 -5
- data/spec/tasks/live_query_spec.rb +1 -1
- data/spec/tasks/query_tracker_spec.rb +34 -34
- data/spec/tasks/user_tasks_spec.rb +4 -2
- data/templates/project/Gemfile.tt +14 -3
- data/templates/project/config/app.rb.tt +27 -2
- data/volt.gemspec +3 -8
- metadata +32 -101
- data/docs/FAQ.md +0 -7
data/spec/models/model_spec.rb
CHANGED
@@ -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
|
-
|
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 = ->(
|
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(
|
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
|
-
|
9
|
-
@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
|
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
|
data/spec/router/routes_spec.rb
CHANGED
@@ -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
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
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
|
-
|
187
|
-
|
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
|
@@ -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/
|
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)
|