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