flok 0.0.38 → 0.0.39

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/drivers/chrome/src/dispatch.js +41 -6
  3. data/app/drivers/chrome/src/persist.js +1 -10
  4. data/app/kern/dispatch.js +17 -23
  5. data/app/kern/gen_id.js +8 -0
  6. data/app/kern/macro.rb +20 -18
  7. data/app/kern/pagers/pg_spec0.js +20 -0
  8. data/app/kern/services/vm.rb +176 -30
  9. data/docs/client_api.md +3 -1
  10. data/docs/compilation.md +1 -1
  11. data/docs/dispatch.md +91 -0
  12. data/docs/kernel_api.md +3 -2
  13. data/docs/messaging.md +6 -1
  14. data/docs/mod/persist.md +4 -3
  15. data/docs/project_layout.md +2 -2
  16. data/docs/services/vm.md +116 -41
  17. data/docs/services/vm/pagers.md +38 -46
  18. data/lib/flok.rb +1 -0
  19. data/lib/flok/build.rb +3 -4
  20. data/lib/flok/macro.rb +27 -0
  21. data/lib/flok/services_compiler.rb +12 -8
  22. data/lib/flok/user_compiler.rb +131 -4
  23. data/lib/flok/version.rb +1 -1
  24. data/spec/env/kern.rb +71 -0
  25. data/spec/etc/macro_spec.rb +3 -8
  26. data/spec/etc/service_compiler/service3.rb +27 -0
  27. data/spec/etc/services_compiler_spec.rb +35 -27
  28. data/spec/iface/driver/dispatch_spec.rb +20 -0
  29. data/spec/iface/driver/persist_spec.rb +9 -24
  30. data/spec/iface/kern/ping_spec.rb +3 -24
  31. data/spec/kern/assets/vm/config4.rb +12 -0
  32. data/spec/kern/assets/vm/controller10.rb +26 -0
  33. data/spec/kern/assets/vm/controller11.rb +33 -0
  34. data/spec/kern/assets/vm/controller12.rb +45 -0
  35. data/spec/kern/assets/vm/controller13.rb +40 -0
  36. data/spec/kern/assets/vm/controller14.rb +14 -0
  37. data/spec/kern/assets/vm/controller15.rb +15 -0
  38. data/spec/kern/assets/vm/controller16.rb +29 -0
  39. data/spec/kern/assets/vm/controller17.rb +30 -0
  40. data/spec/kern/assets/vm/controller18.rb +28 -0
  41. data/spec/kern/assets/vm/controller19.rb +14 -0
  42. data/spec/kern/assets/vm/controller19b.rb +15 -0
  43. data/spec/kern/assets/vm/controller20.rb +19 -0
  44. data/spec/kern/assets/vm/controller21.rb +40 -0
  45. data/spec/kern/assets/vm/controller7.rb +18 -0
  46. data/spec/kern/assets/vm/controller8.rb +38 -0
  47. data/spec/kern/assets/vm/controller8b.rb +18 -0
  48. data/spec/kern/assets/vm/controller9.rb +20 -0
  49. data/spec/kern/assets/vm/controller_exc_2watch.rb +15 -0
  50. data/spec/kern/assets/vm/controller_exc_ewatch.rb +14 -0
  51. data/spec/kern/assets/vm/macros/copy_page_c.rb +23 -0
  52. data/spec/kern/assets/vm/macros/entry_del_c.rb +18 -0
  53. data/spec/kern/assets/vm/macros/entry_insert_c.rb +21 -0
  54. data/spec/kern/assets/vm/macros/entry_mutable_c.rb +33 -0
  55. data/spec/kern/assets/vm/macros/new_page_c.rb +7 -0
  56. data/spec/kern/assets/vm/macros/new_page_c2.rb +7 -0
  57. data/spec/kern/assets/vm/macros/set_page_head_c.rb +18 -0
  58. data/spec/kern/assets/vm/macros/set_page_next_c.rb +18 -0
  59. data/spec/kern/controller_macro_spec.rb +186 -0
  60. data/spec/kern/dispatch_spec.rb +125 -0
  61. data/spec/kern/functions_spec.rb +15 -0
  62. data/spec/kern/vm_service_spec.rb +874 -173
  63. metadata +70 -5
  64. data/docs/scheduling.md +0 -46
  65. data/spec/kern/rest_service_spec.rb +0 -45
@@ -0,0 +1,186 @@
1
+ #This was created later than the controllers, so not all macros may be
2
+ #tested in here. Additionally, some macros may be harder to test, so
3
+ #this contains mostly non-side-effect (functionalish) macros that do not
4
+ #make other function calls. e.g. vm page macros
5
+
6
+ Dir.chdir File.join File.dirname(__FILE__), '../../'
7
+ require './spec/env/kern.rb'
8
+ require './spec/lib/helpers.rb'
9
+ require './spec/lib/io_extensions.rb'
10
+ require './spec/lib/rspec_extensions.rb'
11
+
12
+ RSpec.describe "kern:controller_macro_spec" do
13
+ include_context "kern"
14
+
15
+ it "Can use the NewPage macro" do
16
+ #Compile the controller
17
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/macros/new_page_c.rb')
18
+ ctx.eval %{
19
+ base = _embed("controller", 0, {}, null);
20
+ int_dispatch([]);
21
+ }
22
+
23
+ #Check the page variable
24
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
25
+ expect(page).to eq({
26
+ "_head" => nil,
27
+ "_next" => nil,
28
+ "entries" => [],
29
+ "_id" => nil
30
+ })
31
+ end
32
+
33
+ it "Can use the NewPage macro with id" do
34
+ #Compile the controller
35
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/macros/new_page_c2.rb')
36
+ ctx.eval %{
37
+ base = _embed("controller", 0, {}, null);
38
+ int_dispatch([]);
39
+ }
40
+
41
+ #Check the page variable
42
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
43
+ expect(page).to eq({
44
+ "_head" => nil,
45
+ "_next" => nil,
46
+ "entries" => [],
47
+ "_id" => "test"
48
+ })
49
+ end
50
+
51
+ it "Can use the CopyPage macro" do
52
+ #Compile the controller
53
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/macros/copy_page_c.rb')
54
+ ctx.eval %{
55
+ base = _embed("controller", 0, {}, null);
56
+ int_dispatch([]);
57
+ }
58
+
59
+ #not_copied page is just a reference to original_page, checked for sanity
60
+ original_page = JSON.parse(ctx.eval("JSON.stringify(original_page)"))
61
+ not_copied_page = JSON.parse(ctx.eval("JSON.stringify(not_copied_page)"))
62
+ copied_page = JSON.parse(ctx.eval("JSON.stringify(copied_page)"))
63
+
64
+ #What the copied page should look like after a copy
65
+ copied_should_look_like = JSON.parse(original_page.to_json)
66
+ copied_should_look_like["_next"] = "test" #Set in controller
67
+ copied_should_look_like.delete "_hash"
68
+
69
+ expect(not_copied_page).to eq(original_page)
70
+ expect(copied_page).to eq(copied_should_look_like)
71
+ end
72
+
73
+ it "Can use the EntryDel macro" do
74
+ #Compile the controller
75
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/macros/entry_del_c.rb')
76
+ ctx.eval %{
77
+ base = _embed("controller", 0, {}, null);
78
+ int_dispatch([]);
79
+ }
80
+
81
+ #not_copied page is just a reference to original_page, checked for sanity
82
+ original_page = JSON.parse(ctx.eval("JSON.stringify(original_page)"))
83
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
84
+
85
+ expect(page).to eq({
86
+ "_head" => "head",
87
+ "_id" => "id",
88
+ "_next" => "next",
89
+ "entries" => []
90
+ })
91
+
92
+ expect(original_page).to eq({
93
+ "_head" => "head",
94
+ "_id" => "id",
95
+ "_next" => "next",
96
+ "entries" => [{
97
+ "_id" => "id", "_sig" => "sig"
98
+ }],
99
+ "_hash" => "hash"
100
+ })
101
+ end
102
+
103
+ it "Can use the EntryInsert macro" do
104
+ #Compile the controller
105
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/macros/entry_insert_c.rb')
106
+ ctx.eval %{
107
+ base = _embed("controller", 0, {}, null);
108
+ int_dispatch([]);
109
+ }
110
+
111
+ #not_copied page is just a reference to original_page, checked for sanity
112
+ original_page = JSON.parse(ctx.eval("JSON.stringify(original_page)"))
113
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
114
+
115
+ expect(page["entries"].count).to eq(3)
116
+ expect(page["entries"][0]["hello"]).to eq("world")
117
+ expect(page["entries"][2]["hello"]).to eq("world2")
118
+
119
+ expect(page["entries"][0]["_sig"]).not_to eq(nil)
120
+ expect(page["entries"][0]["_sig"]).not_to eq(page["entries"][1]["_sig"])
121
+ expect(page["entries"][0]["_id"]).not_to eq(nil)
122
+ expect(page["entries"][2]["_id"]).not_to eq(page["entries"][0]["_id"])
123
+ expect(page["entries"][2]["_id"]).not_to eq(page["entries"][1]["_id"])
124
+ end
125
+
126
+ it "Can use the EntryMutable macro" do
127
+ #Compile the controller
128
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/macros/entry_mutable_c.rb')
129
+ ctx.eval %{
130
+ base = _embed("controller", 0, {}, null);
131
+ int_dispatch([]);
132
+ }
133
+
134
+ #not_copied page is just a reference to original_page, checked for sanity
135
+ original_page = JSON.parse(ctx.eval("JSON.stringify(original_page)"))
136
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
137
+
138
+ entries = page["entries"]
139
+ original_entries = original_page["entries"]
140
+ expect(entries[0]["hello"]).to eq("world")
141
+ expect(entries[0]["foo"]).to eq(nil)
142
+ expect(entries[2]["hello"]).to eq("world")
143
+ expect(entries[2]["foo"]).to eq(nil)
144
+
145
+ #Shared
146
+ expect(entries[1]["foo"]).to eq("bar")
147
+ expect(entries[1]["hello"]).to eq(nil)
148
+
149
+ #This should remain unchanged
150
+ expect(original_page["entries"]).to eq([
151
+ {"_id" => "id", "_sig" => "sig"},
152
+ {"_id" => "id2", "_sig" => "sig2", "foo" => "bar"},
153
+ {"_id" => "id3", "_sig" => "sig3"},
154
+ ])
155
+ end
156
+
157
+ it "Can use the SetPageNext macro" do
158
+ #Compile the controller
159
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/macros/set_page_next_c.rb')
160
+ ctx.eval %{
161
+ base = _embed("controller", 0, {}, null);
162
+ int_dispatch([]);
163
+ }
164
+
165
+ #not_copied page is just a reference to original_page, checked for sanity
166
+ original_page = JSON.parse(ctx.eval("JSON.stringify(original_page)"))
167
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
168
+
169
+ expect(page["_next"]).to eq("test")
170
+ end
171
+
172
+ it "Can use the SetPageHead macro" do
173
+ #Compile the controller
174
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/macros/set_page_head_c.rb')
175
+ ctx.eval %{
176
+ base = _embed("controller", 0, {}, null);
177
+ int_dispatch([]);
178
+ }
179
+
180
+ #not_copied page is just a reference to original_page, checked for sanity
181
+ original_page = JSON.parse(ctx.eval("JSON.stringify(original_page)"))
182
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
183
+
184
+ expect(page["_head"]).to eq("test")
185
+ end
186
+ end
@@ -0,0 +1,125 @@
1
+ Dir.chdir File.join File.dirname(__FILE__), '../../'
2
+ require './spec/env/kern.rb'
3
+ require './spec/lib/helpers.rb'
4
+ require './spec/lib/io_extensions.rb'
5
+ require './spec/lib/rspec_extensions.rb'
6
+
7
+ RSpec.describe "kern:dispatch_spec" do
8
+ #Max number of items to be queued in queues other than main
9
+ #per dispatch (as per specs)
10
+ MAX_Q = 5
11
+
12
+ include_context "kern"
13
+
14
+ it "Can call spec_dispatch" do
15
+ #Compile the controller
16
+ ctx = flok_new_user File.read('./spec/kern/assets/blank.rb')
17
+
18
+ #Register callout
19
+ ctx.eval %{
20
+ spec_dispatch_q(main_q, 2);
21
+ }
22
+
23
+ main_q = ctx.dump "main_q"
24
+ expect(main_q).to eq [[0, "spec"], [0, "spec"]]
25
+ end
26
+
27
+ it "Does disptach an unlimited number of items from the main queue" do
28
+ #Compile the controller
29
+ ctx = flok_new_user File.read('./spec/kern/assets/blank.rb')
30
+
31
+ #Register callout
32
+ ctx.eval %{
33
+ spec_dispatch_q(main_q, 10);
34
+ }
35
+
36
+ ctx.eval("int_dispatch([])")
37
+ q = @driver.dump_q
38
+
39
+ expect(q).to eq([[0, [0, "spec"]*10].flatten])
40
+ end
41
+
42
+ queues = [
43
+ "main",
44
+ "net",
45
+ "disk",
46
+ "cpu",
47
+ "gpu"
48
+ ]
49
+
50
+ queues.each_with_index do |qname, qindex|
51
+ #Don't do main queue
52
+ next if qname == "main"
53
+
54
+ it "Does not disptach an unlimited number of items from the #{qname} queue" do
55
+ #Compile the controller
56
+ ctx = flok_new_user File.read('./spec/kern/assets/blank.rb')
57
+
58
+ #Register callout
59
+ ctx.eval %{
60
+ spec_dispatch_q(#{qname}_q, #{MAX_Q+1});
61
+ }
62
+
63
+ #Get partial queue, should have 'i' because we want more things than the max
64
+ ctx.eval("int_dispatch([])")
65
+ q = @driver.dump_q
66
+ expect(q).to eq(['i', [qindex, [0, "spec"]*MAX_Q].flatten])
67
+ end
68
+
69
+ it "Does dispatch the rest of the items after the first two incomplete disptaches" do
70
+ #Compile the controller
71
+ ctx = flok_new_user File.read('./spec/kern/assets/blank.rb')
72
+
73
+ #Register callout
74
+ ctx.eval %{
75
+ spec_dispatch_q(#{qname}_q, #{MAX_Q*3});
76
+ }
77
+
78
+ #Get partial queue, should have 'i' because we want more things than the max
79
+ ctx.eval("int_dispatch([])")
80
+ q = @driver.dump_q
81
+ expect(q).to eq(['i', [qindex, [0, "spec"]*MAX_Q].flatten])
82
+
83
+ #Get partial queue, should have 'i' because we want more things than the max
84
+ ctx.eval("int_dispatch([])")
85
+ q = @driver.dump_q
86
+ expect(q).to eq(['i', [qindex, [0, "spec"]*MAX_Q].flatten])
87
+
88
+ #Last piece, should not have an 'i'
89
+ ctx.eval("int_dispatch([])")
90
+ q = @driver.dump_q
91
+ expect(q).to eq([[qindex, [0, "spec"]*MAX_Q].flatten])
92
+ end
93
+
94
+
95
+ it "Does disptach at MAX_Q number of items from the #{qname} queue" do
96
+ #Compile the controller
97
+ ctx = flok_new_user File.read('./spec/kern/assets/blank.rb')
98
+
99
+ #Register callout
100
+ ctx.eval %{
101
+ spec_dispatch_q(#{qname}_q, #{MAX_Q});
102
+ }
103
+
104
+ ctx.eval("int_dispatch([])")
105
+ q = @driver.dump_q
106
+
107
+ expect(q).to eq([[qindex, [0, "spec"]*MAX_Q].flatten])
108
+ end
109
+
110
+ it "Does disptach all at (MAX_Q-1) number of items from the #{qname} queue" do
111
+ #Compile the controller
112
+ ctx = flok_new_user File.read('./spec/kern/assets/blank.rb')
113
+
114
+ #Register callout
115
+ ctx.eval %{
116
+ spec_dispatch_q(#{qname}_q, #{MAX_Q}-1);
117
+ }
118
+
119
+ ctx.eval("int_dispatch([])")
120
+ q = @driver.dump_q
121
+
122
+ expect(q).to eq([[qindex, [0, "spec"]*(MAX_Q-1)].flatten])
123
+ end
124
+ end
125
+ end
@@ -26,4 +26,19 @@ RSpec.describe "kern:functions_spec" do
26
26
  expect(res).not_to eq(res2)
27
27
  end
28
28
 
29
+ it "can use gen_id" do
30
+ ctx = flok_new_user File.read('./spec/kern/assets/controller0.rb')
31
+
32
+ #Run the check
33
+ res = ctx.eval("gen_id()")
34
+ res2 = ctx.eval("gen_id()")
35
+ reset_for_ctx
36
+
37
+ ctx2 = flok_new_user File.read('./spec/kern/assets/controller0.rb')
38
+
39
+ res3 = ctx2.eval("gen_id()")
40
+ expect(res.class).to eq(String)
41
+ expect(res).not_to eq(res2)
42
+ expect(res3).not_to eq(res)
43
+ end
29
44
  end
@@ -5,191 +5,892 @@ require './spec/env/kern.rb'
5
5
  require './spec/lib/helpers.rb'
6
6
  require './spec/lib/io_extensions.rb'
7
7
  require './spec/lib/rspec_extensions.rb'
8
+ require 'zlib'
8
9
 
9
10
  RSpec.describe "kern:vm_service" do
11
+ include Zlib
10
12
  include_context "kern"
11
13
 
12
- #it "Can be used inside a controller" do
13
- ##Compile the controller
14
- #ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config0.rb")
15
-
16
- ##Run the embed function
17
- #ctx.eval %{
18
- #//Call embed on main root view
19
- #base = _embed("my_controller", 0, {}, null);
20
-
21
- #//Drain queue
22
- #int_dispatch([]);
23
- #}
24
-
25
- #base = ctx.eval("base")
26
- #res = ctx.eval("vm_did_wakeup")
27
- #expect(res).to eq(true)
28
- #end
29
-
30
- #it "Does pass options to spec0 in init" do
31
- ##Compile the controller
32
- #ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config1.rb")
33
-
34
- ##Run the embed function
35
- #ctx.eval %{
36
- #//Call embed on main root view
37
- #base = _embed("my_controller", 0, {}, null);
38
-
39
- #//Drain queue
40
- #int_dispatch([]);
41
- #}
42
-
43
- #base = ctx.eval("base")
44
- #res = JSON.parse(ctx.eval("JSON.stringify(spec0_init_options)"))
45
- #expect(res).to eq({"hello" => "world"})
46
- #end
47
-
48
- #it "Can include the spec0 pager and call read_sync" do
49
- ##Compile the controller
50
- #ctx = flok_new_user File.read('./spec/kern/assets/vm/controller1.rb'), File.read("./spec/kern/assets/vm/config1.rb")
51
-
52
- ##Run the embed function
53
- #ctx.eval %{
54
- #//Call embed on main root view
55
- #base = _embed("my_controller", 0, {}, null);
56
-
57
- #//Drain queue
58
- #int_dispatch([]);
59
- #}
60
-
61
- ##Verify that the vm service is getting the read_sync request
62
- #res = ctx.eval("vm_read_sync_called")
63
- #expect(res).to eq(true)
64
-
65
- ##Verify that the vm service is disptaching the request
66
- #res = ctx.eval("spec0_read_sync_called")
67
- #expect(res).to eq(true)
68
- #end
69
-
70
- #it "Can include the spec0 pager and call read_sync and then get a reply" do
71
- ##Compile the controller
72
- #ctx = flok_new_user File.read('./spec/kern/assets/vm/controller1.rb'), File.read("./spec/kern/assets/vm/config1.rb")
73
-
74
- ##Run the embed function
75
- #ctx.eval %{
76
- #//Call embed on main root view
77
- #base = _embed("my_controller", 0, {}, null);
78
-
79
- #//Drain queue
80
- #int_dispatch([]);
81
- #}
82
-
83
- ##Verify that the read did return from the spec0 pager
84
- #res = ctx.eval("read_res_params")
85
- #expect(res).not_to eq(nil)
86
- #end
87
-
88
-
89
- #it "Can include the spec0 pager and call read and then get a reply" do
90
- ##Compile the controller
91
- #ctx = flok_new_user File.read('./spec/kern/assets/vm/controller2.rb'), File.read("./spec/kern/assets/vm/config1.rb")
92
-
93
- ##Run the embed function
94
- #ctx.eval %{
95
- #//Call embed on main root view
96
- #base = _embed("my_controller", 0, {}, null);
97
-
98
- #//Drain queue
99
- #int_dispatch([]);
100
- #}
101
-
102
- ##Verify that the read did return from the spec0 pager
103
- #res = ctx.eval("read_res_params")
104
- #expect(res).not_to eq(nil)
105
- #end
106
-
107
- #it "Can include the spec0 pager and call write and and then read to get a reply" do
108
- ##Compile the controller
109
- #ctx = flok_new_user File.read('./spec/kern/assets/vm/controller3.rb'), File.read("./spec/kern/assets/vm/config1.rb")
110
-
111
- ##Run the embed function
112
- #ctx.eval %{
113
- #//Call embed on main root view
114
- #base = _embed("my_controller", 0, {}, null);
115
-
116
- #//Drain queue
117
- #int_dispatch([]);
118
- #}
119
-
120
- ##Verify that the read did return from the spec0 pager
121
- #res = JSON.parse(ctx.eval("JSON.stringify(read_res_params)"))
122
- #expect(res).to eq({
123
- #"key" => 33,
124
- #"value" => 22
125
- #})
126
- #end
127
-
128
- # it "Write then read does will hit the pager for the read, a write is not guaranteed to be 1 to 1 but a read is, additionally, the reads only went through once" do
129
- ##Compile the controller
130
- #ctx = flok_new_user File.read('./spec/kern/assets/vm/controller4.rb'), File.read("./spec/kern/assets/vm/config1.rb")
131
-
132
- ##Run the embed function
133
- #ctx.eval %{
134
- #//Call embed on main root view
135
- #base = _embed("my_controller", 0, {}, null);
136
-
137
- #//Drain queue
138
- #int_dispatch([]);
139
- #}
140
-
141
- #expect(ctx.eval("spec0_read_count")).to eq(1)
142
- #end
143
-
144
- #it "Can read through and then send another read_res for a change on the page" do
145
- ##Compile the controller
146
- #ctx = flok_new_user File.read('./spec/kern/assets/vm/controller5.rb'), File.read("./spec/kern/assets/vm/config2.rb")
147
-
148
- ##Run the embed function
149
- #ctx.eval %{
150
- #//Call embed on main root view
151
- #base = _embed("my_controller", 0, {}, null);
152
-
153
- #//Drain queue
154
- #int_dispatch([]);
155
- #}
156
-
157
- ##read_res from spec is called multiple times and returns an array of the parms
158
- #res = JSON.parse(ctx.eval("JSON.stringify(read_res_called_with)"))
159
-
160
- ##Expect 2 responses, first is cache miss, second is cache hit, third is cache updated
161
- #expect(res).to eq [
162
- #{"key" => "my_key", "value" => "a"},
163
- #{"key" => "my_key", "value" => "a"},
164
- #{"key" => "my_key", "value" => "b"}
165
- #]
166
- #end
167
-
168
- it "Can watch a key and then be sent a read_res whenever that key changes" do
169
- #Compile the controller
170
- ctx = flok_new_user File.read('./spec/kern/assets/vm/controller6.rb'), File.read("./spec/kern/assets/vm/config3.rb")
171
-
172
- #Run the embed function
173
- ctx.eval %{
174
- //Call embed on main root view
14
+ it "vm_rehash_page can calculate the hash correctly" do
15
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config3.rb")
16
+
17
+ #Run the check
18
+ res = ctx.eval %{
19
+ //Manually construct a page
20
+ var page = {
21
+ _head: null,
22
+ _next: null,
23
+ _id: "hello",
24
+ entries: [
25
+ {_id: "hello2", _sig: "nohteunth"},
26
+ ]
27
+ }
28
+
29
+ vm_rehash_page(page);
30
+ }
31
+
32
+ #Calculate hash ourselves
33
+ hash = crc32("hello")
34
+ hash = crc32("nohteunth", hash)
35
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
36
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
37
+
38
+ #Expect the same hash
39
+ expect(page).to eq({
40
+ "_head" => nil,
41
+ "_next" => nil,
42
+ "_id" => "hello",
43
+ "entries" => [
44
+ {"_id" => "hello2", "_sig" => "nohteunth"}
45
+ ],
46
+ "_hash" => hash.to_s
47
+ })
48
+ end
49
+
50
+ it "vm_rehash_page can calculate the hash correctly with head and next" do
51
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config3.rb")
52
+
53
+ #Run the check
54
+ res = ctx.eval %{
55
+ //Manually construct a page
56
+ var page = {
57
+ _head: "a",
58
+ _next: "b",
59
+ _id: "hello",
60
+ entries: [
61
+ {_id: "hello2", _sig: "nohteunth"},
62
+ ]
63
+ }
64
+
65
+ vm_rehash_page(page);
66
+ }
67
+
68
+ #Calculate hash ourselves
69
+ hash = crc32("a")
70
+ hash = crc32("b", hash)
71
+ hash = crc32("hello", hash)
72
+ hash = crc32("nohteunth", hash)
73
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
74
+
75
+ #Expect the same hash
76
+ expect(page).to eq({
77
+ "_head" => "a",
78
+ "_next" => "b",
79
+ "_id" => "hello",
80
+ "entries" => [
81
+ {"_id" => "hello2", "_sig" => "nohteunth"}
82
+ ],
83
+ "_hash" => hash.to_s
84
+ })
85
+ end
86
+
87
+ it "Can call vm_cache_write and save it to vm_cache[ns][id]" do
88
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config3.rb")
89
+
90
+ #Run the check
91
+ res = ctx.eval %{
92
+ //Manually construct a page
93
+ page = {
94
+ _head: "a",
95
+ _next: "b",
96
+ _id: "hello",
97
+ entries: [
98
+ {_id: "hello2", _sig: "nohteunth"},
99
+ ]
100
+ }
101
+
102
+ vm_rehash_page(page);
103
+
104
+ //Save page
105
+ vm_cache_write("user", page);
106
+ }
107
+
108
+ vm_cache = JSON.parse(ctx.eval("JSON.stringify(vm_cache)"))
109
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"));
110
+
111
+ #Expect the same hash
112
+ expect(vm_cache).to eq({
113
+ "user" => {
114
+ page["_id"] => page
115
+ }
116
+ })
117
+ end
118
+
119
+ it "Can create a copy of pg_spec0 and receive the correct things in it's initialization" do
120
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config4.rb")
121
+ ctx.eval %{
175
122
  base = _embed("my_controller", 0, {}, null);
176
123
 
177
124
  //Drain queue
178
125
  int_dispatch([]);
179
126
  }
180
127
 
181
- #Trigger notification
182
- ctx.eval("spec2_spec_trigger()")
128
+ pg_spec0_init_params = JSON.parse(ctx.eval("JSON.stringify(pg_spec0_init_params)"))
129
+
130
+ #Expect options and ns to match in config4
131
+ expect(pg_spec0_init_params).to eq({
132
+ "ns" => "spec",
133
+ "options" => {"hello" => "world"}
134
+ })
135
+ end
136
+
137
+ it "Does call pagers watch function with a undefined page when no page exists in cache" do
138
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller7.rb'), File.read("./spec/kern/assets/vm/config4.rb")
139
+
140
+ ctx.eval %{
141
+ base = _embed("my_controller", 0, {}, null);
142
+
143
+ //Drain queue
144
+ int_dispatch([]);
145
+ }
146
+
147
+ #We are watching a page that should have been stored in cache at this point
148
+ pg_spec0_watchlist = JSON.parse(ctx.eval("JSON.stringify(pg_spec0_watchlist)"))
149
+
150
+ #Expect options and ns to match in config4
151
+ expect(pg_spec0_watchlist).to eq([{
152
+ "id" => "my_key"
153
+ }])
154
+ end
155
+
156
+ it "Does call pagers watch function with a page when the page requested for a watch is stored in cache" do
157
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller7.rb'), File.read("./spec/kern/assets/vm/config4.rb")
158
+
159
+ #We are going to manually store a page in cache as this page should be retrieved
160
+ #for the watch attempt
161
+ res = ctx.eval %{
162
+ //Manually construct a page as we are going to test the watch function
163
+ //which receives a call to watch with the hash of this page so the
164
+ //watch function can tell if the page has changed (e.g. if you are connecting)
165
+ //to a remote server
166
+ page = {
167
+ _head: "a",
168
+ _next: "b",
169
+ _id: "my_key",
170
+ entries: [
171
+ {_id: "hello2", _sig: "nohteunth"},
172
+ ]
173
+ }
174
+
175
+ vm_rehash_page(page);
176
+
177
+ //Save page for the spec pager
178
+ vm_cache_write("spec", page);
179
+ }
180
+
181
+ #This hash was calculated during vm_rehash_page
182
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
183
+
184
+ ctx.eval %{
185
+ base = _embed("my_controller", 0, {}, null);
186
+
187
+ //Drain queue
188
+ int_dispatch([]);
189
+ }
190
+
191
+ #We are watching a page that should have been stored in cache at this point
192
+ pg_spec0_watchlist = JSON.parse(ctx.eval("JSON.stringify(pg_spec0_watchlist)"))
193
+
194
+ #Expect options and ns to match in config4
195
+ expect(pg_spec0_watchlist).to eq([{
196
+ "id" => "my_key",
197
+ "page" => page
198
+ }])
199
+ end
200
+
201
+ it "throws an exception if multiple watches are attempted" do
202
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller_exc_2watch.rb'), File.read("./spec/kern/assets/vm/config4.rb")
203
+
204
+ expect {
205
+ ctx.eval %{
206
+ base = _embed("my_controller", 1, {}, null);
207
+
208
+ //Drain queue
209
+ int_dispatch([]);
210
+ }
211
+ }.to raise_exception
212
+ end
213
+
214
+ it "throws an exception if unwatch is called before watch" do
215
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller_exc_ewatch.rb'), File.read("./spec/kern/assets/vm/config4.rb")
216
+
217
+ expect {
218
+ ctx.eval %{
219
+ base = _embed("my_controller", 1, {}, null);
220
+
221
+ //Drain queue
222
+ int_dispatch([]);
223
+ }
224
+ }.to raise_exception
225
+ end
226
+
227
+ it "multiple sequential watch requests from two controllers for a namespace do not hit the pager multiple times" do
228
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8.rb'), File.read("./spec/kern/assets/vm/config4.rb")
229
+
230
+ ctx.eval %{
231
+ base = _embed("my_controller", 1, {}, null);
232
+ base2 = _embed("my_controller", base+2, {}, null);
233
+
234
+ //Drain queue
235
+ int_dispatch([]);
236
+ }
237
+
238
+ #We are watching a page that should have been stored in cache at this point
239
+ pg_spec0_watchlist = JSON.parse(ctx.eval("JSON.stringify(pg_spec0_watchlist)"))
240
+
241
+ #Expect options and ns to match in config4
242
+ expect(pg_spec0_watchlist).to eq([{
243
+ "id" => "my_key"
244
+ }])
245
+ end
246
+
247
+ it "unwatch request to pager does call the pagers unwatch function" do
248
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller9.rb'), File.read("./spec/kern/assets/vm/config4.rb")
249
+
250
+ ctx.eval %{
251
+ base = _embed("my_controller", 1, {}, null);
252
+
253
+ //Drain queue
254
+ int_dispatch([]);
255
+ }
256
+
257
+ #We are watching a page that should have been stored in cache at this point
258
+ pg_spec0_unwatchlist = JSON.parse(ctx.eval("JSON.stringify(pg_spec0_unwatchlist)"))
259
+
260
+ expect(pg_spec0_unwatchlist).to eq(["my_key"])
261
+ end
262
+
263
+ it "watch unwatch and watch request for a namespace does hit the pager multiple times" do
264
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller9.rb'), File.read("./spec/kern/assets/vm/config4.rb")
265
+
266
+ ctx.eval %{
267
+ base = _embed("my_controller", 1, {}, null);
268
+
269
+ //Drain queue
270
+ int_dispatch([]);
271
+ }
272
+
273
+ #We are watching a page that should have been stored in cache at this point
274
+ pg_spec0_watchlist = JSON.parse(ctx.eval("JSON.stringify(pg_spec0_watchlist)"))
275
+
276
+ #Expect options and ns to match in config4
277
+ expect(pg_spec0_watchlist).to eq([{
278
+ "id" => "my_key"
279
+ }, {
280
+ "id" => "my_key"
281
+ }])
282
+ end
283
+
284
+ it "sends write requests to the pager" do
285
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller10.rb'), File.read("./spec/kern/assets/vm/config4.rb")
286
+
287
+ ctx.eval %{
288
+ base = _embed("my_controller", 1, {}, null);
289
+
290
+ //Drain queue
291
+ int_dispatch([]);
292
+ }
293
+
294
+ #Expect the page to be written to cache
295
+ vm_cache = JSON.parse(ctx.eval("JSON.stringify(vm_cache)"));
296
+ vm_write_list = JSON.parse(ctx.eval("JSON.stringify(vm_write_list[0])"));
297
+ expect(vm_cache["spec"]["test"]).to eq(vm_write_list)
298
+ end
299
+
300
+ it "sends watch callback to controller when cache is written to via read_res" do
301
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller11.rb'), File.read("./spec/kern/assets/vm/config4.rb")
302
+
303
+ ctx.eval %{
304
+ base = _embed("my_controller", 1, {}, null);
305
+
306
+ //Drain queue
307
+ int_dispatch([]);
308
+ }
309
+
310
+ read_res_params = JSON.parse(ctx.eval("JSON.stringify(read_res_params)"))
311
+ vm_write_list = JSON.parse(ctx.eval("JSON.stringify(vm_write_list[0])"));
312
+ expect(read_res_params).to eq(vm_write_list)
313
+ end
314
+
315
+ it "does send two watch callbacks to a controller if there is cached content" do
316
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller12.rb'), File.read("./spec/kern/assets/vm/config4.rb")
317
+
318
+ ctx.eval %{
319
+ base = _embed("my_controller", 1, {}, null);
320
+
321
+ //Drain queue
322
+ int_dispatch([]);
323
+ }
324
+
325
+ read_res_params = JSON.parse(ctx.eval("JSON.stringify(read_res_params)"))
326
+ vm_write_list = JSON.parse(ctx.eval("JSON.stringify(vm_write_list)"));
327
+ expect(read_res_params).to eq(vm_write_list)
328
+ end
329
+
330
+ it "vm_cache_write does not tell controllers an update has occurred if the page requested to cache was already cached" do
331
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller13.rb'), File.read("./spec/kern/assets/vm/config4.rb")
332
+
333
+ ctx.eval %{
334
+ base = _embed("my_controller", 1, {}, null);
335
+
336
+ //Drain queue
337
+ int_dispatch([]);
338
+ }
339
+
340
+ read_res_params = JSON.parse(ctx.eval("JSON.stringify(read_res_params)"))
341
+ vm_write_list = JSON.parse(ctx.eval("JSON.stringify(vm_write_list)"));
342
+ expect(read_res_params).to eq([vm_write_list[0]])
343
+ end
344
+
345
+ it "updates vm_notify_map when a watch takes place" do
346
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller14.rb'), File.read("./spec/kern/assets/vm/config4.rb")
347
+
348
+ ctx.eval %{
349
+ base = _embed("my_controller", 1, {}, null);
350
+
351
+ //Drain queue
352
+ int_dispatch([]);
353
+ }
354
+
355
+ base = ctx.eval("base")
356
+ vm_notify_map = JSON.parse(ctx.eval("JSON.stringify(vm_notify_map)"));
357
+ expect(vm_notify_map).to eq({
358
+ "spec" => {
359
+ "test" => [base]
360
+ }
361
+ })
362
+ end
363
+
364
+ it "updates vm_bp_to_nmap when a watch takes place" do
365
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller14.rb'), File.read("./spec/kern/assets/vm/config4.rb")
366
+
367
+ ctx.eval %{
368
+ base = _embed("my_controller", 1, {}, null);
369
+
370
+ //Drain queue
371
+ int_dispatch([]);
372
+ }
373
+
374
+ base = ctx.eval("base")
375
+ vm_bp_to_nmap = JSON.parse(ctx.eval("JSON.stringify(vm_bp_to_nmap)"));
376
+ expect(vm_bp_to_nmap).to eq({
377
+ base.to_s => {
378
+ "spec" => {
379
+ "test" => [[3], 0]
380
+ }
381
+ }
382
+ })
383
+
384
+ #Removing the element from the given pointer in vm_bp_to_nmap to the array will also alter vm_notify_map's array
385
+ #if it is a reference
386
+ ctx.eval %{
387
+ //Grab the array that contains [node, index] where node is a reference to an array of vm_notify_map[ns][key]
388
+ var e = vm_bp_to_nmap[base]["spec"]["test"];
389
+ var node = e[0];
390
+ var index = e[1];
391
+
392
+ //Remove an element from the node
393
+ node.splice(index, 1);
394
+ }
395
+
396
+ vm_notify_map_after = JSON.parse(ctx.eval("JSON.stringify(vm_notify_map)"))
397
+ expect(vm_notify_map_after).to eq({
398
+ "spec" => {
399
+ "test" => []
400
+ }
401
+ })
402
+ end
183
403
 
184
- #read_res from spec is called multiple times and returns an array of the parms
185
- res = JSON.parse(ctx.eval("JSON.stringify(read_res_called_with)"))
404
+ it "updates vm_notify_map when an unwatch takes place" do
405
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller15.rb'), File.read("./spec/kern/assets/vm/config4.rb")
186
406
 
187
- #Expect 2 responses, first is cache miss, second is cache hit, third is cache updated
188
- expect(res).to eq [
189
- {"key" => "my_key", "value" => "a"},
190
- {"key" => "my_key", "value" => "a"},
191
- {"key" => "my_key", "value" => "b"}
192
- ]
407
+ ctx.eval %{
408
+ base = _embed("my_controller", 1, {}, null);
409
+
410
+ //Drain queue
411
+ int_dispatch([]);
412
+ }
413
+
414
+ base = ctx.eval("base")
415
+ vm_notify_map = JSON.parse(ctx.eval("JSON.stringify(vm_notify_map)"));
416
+ expect(vm_notify_map).to eq({
417
+ "spec" => {
418
+ "test" => []
419
+ }
420
+ })
193
421
  end
194
422
 
423
+ it "updates vm_bp_to_nmap when an unwatch takes place" do
424
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller15.rb'), File.read("./spec/kern/assets/vm/config4.rb")
425
+
426
+ ctx.eval %{
427
+ base = _embed("my_controller", 1, {}, null);
428
+
429
+ //Drain queue
430
+ int_dispatch([]);
431
+ }
432
+
433
+ base = ctx.eval("base")
434
+ vm_bp_to_nmap = JSON.parse(ctx.eval("JSON.stringify(vm_bp_to_nmap)"));
435
+ expect(vm_bp_to_nmap).to eq({
436
+ base.to_s => {
437
+ "spec" => {}
438
+ }
439
+ })
440
+ end
441
+
442
+ it "Erases entries in vm_bp_to_nmap and vm_notify_map for a controller that disconnects" do
443
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller16.rb'), File.read("./spec/kern/assets/vm/config4.rb")
444
+
445
+ ctx.eval %{
446
+ base = _embed("my_controller", 1, {}, null);
447
+
448
+ //Drain queue
449
+ int_dispatch([3, "int_event", base, "next", {}]);
450
+ }
451
+
452
+ #vm_bp_To_nmap should be blank
453
+ base = ctx.eval("base")
454
+ vm_bp_to_nmap = JSON.parse(ctx.eval("JSON.stringify(vm_bp_to_nmap)"));
455
+ expect(vm_bp_to_nmap).to eq({})
456
+
457
+ #vm_notify_map should not contain the entries for the base address anymore
458
+ base = ctx.eval("base")
459
+ vm_notify_map = JSON.parse(ctx.eval("JSON.stringify(vm_notify_map)"));
460
+ expect(vm_notify_map).to eq({
461
+ "spec" => {
462
+ "test" => []
463
+ }
464
+ })
465
+ end
466
+
467
+ it "Erases entries in vm_bp_to_nmap and vm_notify_map for a controller that disconnects with two controllers maintaining correct" do
468
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller16.rb'), File.read("./spec/kern/assets/vm/config4.rb")
469
+
470
+ ctx.eval %{
471
+ base = _embed("my_controller", 1, {}, null);
472
+
473
+ //Drain queue
474
+ int_dispatch([3, "int_event", base, "next", {}]);
475
+ }
476
+
477
+ #vm_bp_To_nmap should be blank
478
+ base = ctx.eval("base")
479
+ vm_bp_to_nmap = JSON.parse(ctx.eval("JSON.stringify(vm_bp_to_nmap)"));
480
+ expect(vm_bp_to_nmap).to eq({})
481
+
482
+ #vm_notify_map should not contain the entries for the base address anymore
483
+ base = ctx.eval("base")
484
+ vm_notify_map = JSON.parse(ctx.eval("JSON.stringify(vm_notify_map)"));
485
+ expect(vm_notify_map).to eq({
486
+ "spec" => {
487
+ "test" => []
488
+ }
489
+ })
490
+ end
491
+
492
+ it "Stores dirty pages written via vm_cache_write in vm_dirty" do
493
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config3.rb")
494
+
495
+ #Run the check
496
+ res = ctx.eval %{
497
+ //Manually construct a page
498
+ page = {
499
+ _head: "a",
500
+ _next: "b",
501
+ _id: "hello",
502
+ entries: [
503
+ {_id: "hello2", _sig: "nohteunth"},
504
+ ]
505
+ }
506
+
507
+ vm_rehash_page(page);
508
+
509
+ //Save page
510
+ vm_cache_write("user", page);
511
+ }
512
+
513
+ vm_dirty = JSON.parse(ctx.eval("JSON.stringify(vm_dirty)"))
514
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"));
515
+
516
+ #Expect the same hash
517
+ expect(vm_dirty).to eq({
518
+ "user" => {
519
+ page["_id"] => page
520
+ }
521
+ })
522
+ end
523
+
524
+ it "Tries to write to disk when the pageout runs" do
525
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller18.rb'), File.read("./spec/kern/assets/vm/config4.rb")
526
+
527
+ ctx.eval %{
528
+ base = _embed("my_controller", 1, {}, null);
529
+
530
+ //Call pageout *now*
531
+ vm_pageout();
532
+
533
+ //Drain queue
534
+ int_dispatch([]);
535
+ }
536
+
537
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
538
+
539
+ @driver.ignore_up_to "if_per_set", 0
540
+ @driver.mexpect("if_per_set", ["spec", page["_id"], page])
541
+ end
542
+
543
+ it "Does send a read request from disk cache when watching a key for the first time" do
544
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller19.rb'), File.read("./spec/kern/assets/vm/config4.rb")
545
+
546
+ ctx.eval %{
547
+ base = _embed("my_controller", 1, {}, null);
548
+
549
+ //Call pageout *now*
550
+ vm_pageout();
551
+
552
+ //Drain queue
553
+ int_dispatch([]);
554
+ }
555
+
556
+ @driver.ignore_up_to "if_per_get", 2
557
+ @driver.mexpect("if_per_get", ["vm", "spec", "test"], 2)
558
+ end
559
+
560
+ it "Does send a sync read request from disk cache when watching a key for the first time with sync: true" do
561
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller19b.rb'), File.read("./spec/kern/assets/vm/config4.rb")
562
+
563
+ ctx.eval %{
564
+ base = _embed("my_controller", 1, {}, null);
565
+
566
+ //Call pageout *now*
567
+ vm_pageout();
568
+
569
+ //Drain queue
570
+ int_dispatch([]);
571
+ }
572
+
573
+ @driver.ignore_up_to "if_per_get", 0
574
+ @driver.mexpect("if_per_get", ["vm", "spec", "test"], 0)
575
+ end
576
+
577
+ it "Only sends one disk read request when multiple non-sync watches are attempted" do
578
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8.rb'), File.read("./spec/kern/assets/vm/config4.rb")
579
+
580
+ ctx.eval %{
581
+ base = _embed("my_controller", 1, {}, null);
582
+ base2 = _embed("my_controller", base+2, {}, null);
583
+
584
+ //Drain queue
585
+ int_dispatch([]);
586
+ }
587
+
588
+ @driver.ignore_up_to "if_per_get", 2
589
+ @driver.get "if_per_get", 2
590
+
591
+ #There should not be another request for the drive
592
+ expect {
593
+ @driver.ignore_up_to "if_per_get"
594
+ }.to raise_exception
595
+ end
596
+
597
+ it "Only sends one disk read request when multiple watches are attempted, and the first watch is sync: true" do
598
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8.rb'), File.read("./spec/kern/assets/vm/config4.rb")
599
+
600
+ ctx.eval %{
601
+ base = _embed("my_controller_sync", 1, {}, null);
602
+ base2 = _embed("my_controller", base+2, {}, null);
603
+
604
+ //Drain queue
605
+ int_dispatch([]);
606
+ }
607
+
608
+ @driver.ignore_up_to "if_per_get", 0
609
+ @driver.get "if_per_get", 0
610
+
611
+ #There should not be another request for the drive
612
+ expect {
613
+ @driver.ignore_up_to "if_per_get"
614
+ }.to raise_exception
615
+ end
616
+
617
+ it "Sends two disk read request when multiple watches are attempted, and the second watch is sync: true but the disk does not read back before it is requested" do
618
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8.rb'), File.read("./spec/kern/assets/vm/config4.rb")
619
+
620
+ ctx.eval %{
621
+ base = _embed("my_controller", 1, {}, null);
622
+ base2 = _embed("my_controller_sync", base+2, {}, null);
623
+
624
+ //Drain queue
625
+ int_dispatch([]);
626
+ }
627
+
628
+ #The inner controller's on_entry is called before, so it's in reverse order
629
+ @driver.ignore_up_to "if_per_get", 0
630
+ @driver.get "if_per_get", 0
631
+ @driver.ignore_up_to "if_per_get", 2
632
+ end
633
+
634
+ it "Sends one disk read request when multiple watches are attempted, and the second watch is sync: true and the disk *does* read back before it is requested" do
635
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8.rb'), File.read("./spec/kern/assets/vm/config4.rb");
636
+
637
+ ctx.eval %{
638
+ base = _embed("my_controller", 1, {}, null);
639
+
640
+ //Drain queue
641
+ int_dispatch([]);
642
+ }
643
+
644
+ page0 = JSON.parse(ctx.eval("JSON.stringify(page0)"))
645
+ @driver.int "int_per_get_res", ["vm", "spec", page0]
646
+
647
+ ctx.eval %{
648
+ base2 = _embed("my_controller_sync", base+2, {}, null);
649
+ }
650
+
651
+ #The inner controller's on_entry is called before, so it's in reverse order
652
+ @driver.ignore_up_to "if_per_get", 2
653
+ @driver.get "if_per_get", 2
654
+
655
+ #There should not be another request for the drive
656
+ expect {
657
+ @driver.ignore_up_to "if_per_get"
658
+ }.to raise_exception
659
+ end
660
+
661
+ it "Only sends one disk read request when multiple sync watches are attempted" do
662
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8.rb'), File.read("./spec/kern/assets/vm/config4.rb")
663
+
664
+ ctx.eval %{
665
+ base = _embed("my_controller_sync", 1, {}, null);
666
+
667
+ //Drain queue
668
+ int_dispatch([]);
669
+ }
670
+
671
+ @driver.ignore_up_to "if_per_get", 0
672
+ @driver.get "if_per_get", 0
673
+
674
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
675
+ @driver.int "int_per_get_res", ["vm", "spec", page]
676
+
677
+ ctx.eval %{
678
+ base2 = _embed("my_controller_sync", base+2, {}, null);
679
+ }
680
+
681
+ #There should not be another request for the drive
682
+ expect {
683
+ @driver.ignore_up_to "if_per_get"
684
+ }.to raise_exception
685
+ end
686
+
687
+
688
+ it "Clears the dirty page when pageout runs" do
689
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller18.rb'), File.read("./spec/kern/assets/vm/config4.rb")
690
+
691
+ ctx.eval %{
692
+ base = _embed("my_controller", 1, {}, null);
693
+
694
+ //Drain queue
695
+ int_dispatch([3, "int_event", base, "next", {}]);
696
+ }
697
+
698
+ ctx.eval("vm_pageout()");
699
+
700
+ vm_dirty = JSON.parse(ctx.eval("JSON.stringify(vm_dirty)"))
701
+ expect(vm_dirty).to eq({
702
+ "spec" => {}
703
+ })
704
+ end
705
+
706
+ it "Responds twice to watch with a missing cache but where the disk has a copy and then the pager responds" do
707
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller20.rb'), File.read("./spec/kern/assets/vm/config4.rb")
708
+
709
+ ctx.eval %{
710
+ base = _embed("my_controller", 1, {}, null);
711
+
712
+ //Manually construct a page
713
+ page = {
714
+ _head: null,
715
+ _next: null,
716
+ _id: "hello",
717
+ entries: [
718
+ {_id: "hello2", _sig: "nohteunth"},
719
+ ]
720
+ }
721
+
722
+ //Manually construct another page that would normally be written
723
+ //by a 'pager' to the cache
724
+ page2 = {
725
+ _head: null,
726
+ _next: null,
727
+ _id: "hello",
728
+ entries: [
729
+ {_id: "hello2", _sig: "nohteunth"},
730
+ {_id: "hello3", _sig: "athoeuntz"}
731
+ ]
732
+ }
733
+
734
+ //Recalculate hashes
735
+ vm_rehash_page(page);
736
+ vm_rehash_page(page2);
737
+
738
+ //Drain queue
739
+ int_dispatch([]);
740
+ }
741
+
742
+ #Copies of JS pages in ruby dictionary format
743
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
744
+ page2 = JSON.parse(ctx.eval("JSON.stringify(page2)"))
745
+
746
+ #At this point, flok should have attempted to grab a page to fill
747
+ #the *now* blank cache. We are going to send it the first page.
748
+ @driver.ignore_up_to "if_per_get", 2
749
+ @driver.get "if_per_get", 2
750
+ @driver.int "int_per_get_res", ["vm", "spec", page]
751
+
752
+ #Now, we pretend that a pager has written to the cache because it has
753
+ #received data back
754
+ ctx.eval(%{vm_cache_write("spec", page2)})
755
+
756
+ res = JSON.parse(ctx.eval("JSON.stringify(read_res)"))
757
+ expect(res).to eq([
758
+ page, page2
759
+ ])
760
+ end
761
+
762
+ it "Responds once to watch with a missing cache but where the pager responds before the disk" do
763
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller20.rb'), File.read("./spec/kern/assets/vm/config4.rb")
764
+
765
+ ctx.eval %{
766
+ base = _embed("my_controller", 1, {}, null);
767
+
768
+ //Manually construct a page
769
+ page = {
770
+ _head: null,
771
+ _next: null,
772
+ _id: "hello",
773
+ entries: [
774
+ {_id: "hello2", _sig: "nohteunth"},
775
+ ]
776
+ }
777
+
778
+ //Manually construct another page that would normally be written
779
+ //by a 'pager' to the cache
780
+ page2 = {
781
+ _head: null,
782
+ _next: null,
783
+ _id: "hello",
784
+ entries: [
785
+ {_id: "hello2", _sig: "nohteunth"},
786
+ {_id: "hello3", _sig: "athoeuntz"}
787
+ ]
788
+ }
789
+
790
+ //Recalculate hashes
791
+ vm_rehash_page(page);
792
+ vm_rehash_page(page2);
793
+
794
+ //Drain queue
795
+ int_dispatch([]);
796
+ }
797
+
798
+ #Copies of JS pages in ruby dictionary format
799
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
800
+ page2 = JSON.parse(ctx.eval("JSON.stringify(page2)"))
801
+
802
+ #At this point, flok should have attempted to grab a page to fill
803
+ #the *now* blank cache. We are going to send it the first page.
804
+ @driver.ignore_up_to "if_per_get", 2
805
+ @driver.get "if_per_get", 2
806
+
807
+ #Now, we pretend that a pager has written to the cache because it has
808
+ #received data back
809
+ ctx.eval(%{vm_cache_write("spec", page2)})
810
+
811
+ #And then we let the cache from disk reply, which should be ignored
812
+ #because the cache is already there from the pager
813
+ @driver.int "int_per_get_res", ["vm", "spec", page]
814
+
815
+ res = JSON.parse(ctx.eval("JSON.stringify(read_res)"))
816
+ expect(res).to eq([
817
+ page2
818
+ ])
819
+ end
820
+
821
+ it "Does within 21 seconds of a write on bootup, write to disk" do
822
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller18.rb'), File.read("./spec/kern/assets/vm/config4.rb")
823
+
824
+ ctx.eval %{
825
+ base = _embed("my_controller", 1, {}, null);
826
+
827
+ //Drain queue
828
+ int_dispatch([]);
829
+ }
830
+
831
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
832
+
833
+ (4*21).times do
834
+ @driver.int "int_timer", []
835
+ end
836
+
837
+ @driver.ignore_up_to "if_per_set", 0
838
+ @driver.mexpect("if_per_set", ["spec", page["_id"], page])
839
+ end
840
+
841
+ it "Does not attempt to write twice to disk after 41 seconds if there is no pending data to write" do
842
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller21.rb'), File.read("./spec/kern/assets/vm/config4.rb")
843
+
844
+ ctx.eval %{
845
+ base = _embed("my_controller", 1, {}, null);
846
+
847
+ //Drain queue
848
+ int_dispatch([]);
849
+ }
850
+
851
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
852
+
853
+ (4*41).times do
854
+ @driver.int "int_timer", []
855
+ end
856
+
857
+ @driver.ignore_up_to "if_per_set", 0
858
+ @driver.mexpect("if_per_set", ["spec", page["_id"], page])
859
+
860
+ expect {
861
+ @driver.ignore_up_to "if_per_set"
862
+ }.to raise_exception
863
+ end
864
+
865
+ it "Does attempt to write twice to disk after 41 seconds if there is pending data to write" do
866
+ ctx = flok_new_user File.read('./spec/kern/assets/vm/controller21.rb'), File.read("./spec/kern/assets/vm/config4.rb")
867
+
868
+ ctx.eval %{
869
+ base = _embed("my_controller", 1, {}, null);
870
+
871
+ //Drain queue
872
+ int_dispatch([]);
873
+ }
874
+
875
+ base = ctx.eval("base")
876
+ page = JSON.parse(ctx.eval("JSON.stringify(page)"))
877
+
878
+ (4*21).times do
879
+ @driver.int "int_timer", []
880
+ end
881
+
882
+ @driver.ignore_up_to "if_per_set", 0
883
+ @driver.mexpect("if_per_set", ["spec", page["_id"], page])
884
+
885
+ #Call next on controller which will write an new page
886
+ ctx.eval %{ int_dispatch([3, "int_event", base, "next", {}]); }
887
+
888
+ page2 = JSON.parse(ctx.eval("JSON.stringify(page2)"))
889
+ (4*21).times do
890
+ @driver.int "int_timer", []
891
+ end
892
+
893
+ @driver.ignore_up_to "if_per_set", 0
894
+ @driver.mexpect("if_per_set", ["spec", page2["_id"], page2])
895
+ end
195
896
  end