wabur 0.2.0d1 → 0.4.0d1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -14
  3. data/bin/wabur +103 -0
  4. data/lib/wab/controller.rb +133 -90
  5. data/lib/wab/data.rb +14 -27
  6. data/lib/wab/errors.rb +14 -8
  7. data/lib/wab/impl/bool_expr.rb +25 -0
  8. data/lib/wab/impl/configuration.rb +166 -0
  9. data/lib/wab/impl/data.rb +155 -232
  10. data/lib/wab/impl/expr.rb +26 -0
  11. data/lib/wab/impl/expr_parser.rb +55 -0
  12. data/lib/wab/impl/exprs/and.rb +29 -0
  13. data/lib/wab/impl/exprs/between.rb +41 -0
  14. data/lib/wab/impl/exprs/eq.rb +28 -0
  15. data/lib/wab/impl/exprs/gt.rb +30 -0
  16. data/lib/wab/impl/exprs/gte.rb +30 -0
  17. data/lib/wab/impl/exprs/has.rb +26 -0
  18. data/lib/wab/impl/exprs/in.rb +28 -0
  19. data/lib/wab/impl/exprs/lt.rb +30 -0
  20. data/lib/wab/impl/exprs/lte.rb +30 -0
  21. data/lib/wab/impl/exprs/not.rb +27 -0
  22. data/lib/wab/impl/exprs/or.rb +29 -0
  23. data/lib/wab/impl/exprs/regex.rb +28 -0
  24. data/lib/wab/impl/handler.rb +95 -0
  25. data/lib/wab/impl/model.rb +197 -0
  26. data/lib/wab/impl/path_expr.rb +14 -0
  27. data/lib/wab/impl/shell.rb +92 -7
  28. data/lib/wab/impl/utils.rb +110 -0
  29. data/lib/wab/impl.rb +24 -0
  30. data/lib/wab/io/call.rb +4 -7
  31. data/lib/wab/io/engine.rb +128 -51
  32. data/lib/wab/io/shell.rb +61 -64
  33. data/lib/wab/io.rb +0 -2
  34. data/lib/wab/open_controller.rb +43 -0
  35. data/lib/wab/shell.rb +46 -61
  36. data/lib/wab/shell_logger.rb +13 -0
  37. data/lib/wab/utils.rb +36 -0
  38. data/lib/wab/uuid.rb +3 -6
  39. data/lib/wab/version.rb +2 -2
  40. data/lib/wab.rb +3 -0
  41. data/pages/Plan.md +20 -14
  42. data/test/bench_io_shell.rb +49 -0
  43. data/test/{impl_test.rb → helper.rb} +2 -4
  44. data/test/mirror_controller.rb +16 -0
  45. data/test/test_configuration.rb +38 -0
  46. data/test/test_data.rb +207 -0
  47. data/test/test_expr.rb +35 -0
  48. data/test/test_expr_and.rb +24 -0
  49. data/test/test_expr_between.rb +43 -0
  50. data/test/test_expr_eq.rb +24 -0
  51. data/test/test_expr_gt.rb +24 -0
  52. data/test/test_expr_gte.rb +24 -0
  53. data/test/test_expr_has.rb +19 -0
  54. data/test/test_expr_in.rb +24 -0
  55. data/test/test_expr_lt.rb +24 -0
  56. data/test/test_expr_lte.rb +24 -0
  57. data/test/test_expr_not.rb +22 -0
  58. data/test/test_expr_or.rb +24 -0
  59. data/test/test_expr_regex.rb +30 -0
  60. data/test/test_impl.rb +38 -0
  61. data/test/test_io_shell.rb +189 -0
  62. data/test/test_model.rb +31 -0
  63. data/test/test_runner.rb +177 -0
  64. data/test/tests.rb +3 -8
  65. metadata +91 -18
  66. data/lib/wab/model.rb +0 -136
  67. data/lib/wab/view.rb +0 -21
  68. data/test/data_test.rb +0 -253
  69. data/test/ioshell_test.rb +0 -461
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative 'helper'
5
+
6
+ class TestExprNot < TestImpl
7
+
8
+ def test_not_native
9
+ x = WAB::Impl::Not.new(WAB::Impl::Eq.new('num', 7))
10
+ assert_equal(['NOT', ['EQ', 'num', 7]], x.native, 'NOT native mismatch')
11
+ end
12
+
13
+ def test_not
14
+ d = make_sample_data
15
+ x = WAB::Impl::Not.new(WAB::Impl::Eq.new('num', 8))
16
+ assert(x.eval(d), 'checking NOT match')
17
+
18
+ x = WAB::Impl::Not.new(WAB::Impl::Eq.new('num', 7))
19
+ refute(x.eval(d), 'checking NOT mismatch')
20
+ end
21
+
22
+ end # TestExprNot
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative 'helper'
5
+
6
+ class TestExprOr < TestImpl
7
+
8
+ def test_or_native
9
+ x = WAB::Impl::Or.new(WAB::Impl::Has.new('num'), WAB::Impl::Eq.new('num', 7))
10
+ assert_equal(['OR', ['HAS', 'num'], ['EQ', 'num', 7]], x.native, 'OR native mismatch')
11
+ end
12
+
13
+ def test_or
14
+ d = make_sample_data
15
+ x = WAB::Impl::Or.new(WAB::Impl::Has.new('str'), WAB::Impl::Eq.new('num', 8))
16
+ assert(x.eval(d), 'checking OR match')
17
+
18
+ x = WAB::Impl::Or.new(WAB::Impl::Has.new('none'), WAB::Impl::Eq.new('num', 8))
19
+ refute(x.eval(d), 'checking OR mismatch')
20
+ end
21
+
22
+ # TBD tests with no args, with one, with more than 2, test using append_arg
23
+
24
+ end # TestExprOr
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative 'helper'
5
+
6
+ require 'wab'
7
+ require 'wab/impl'
8
+
9
+ class TestExprRegex < TestImpl
10
+
11
+ def test_regex_native
12
+ x = WAB::Impl::Regex.new('str', '^a *.')
13
+ assert_equal(['REGEX', 'str', '^a *.'], x.native, 'REGEX native mismatch')
14
+ end
15
+
16
+ def test_regex_int
17
+ d = make_sample_data
18
+ x = WAB::Impl::Regex.new('str', '^a .*')
19
+ assert(x.eval(d), 'checking REGEX match with string arg')
20
+
21
+ x = WAB::Impl::Regex.new('str', '^x .*')
22
+ refute(x.eval(d), 'checking REGEX mismatch with string arg')
23
+
24
+ x = WAB::Impl::Regex.new('num', 8)
25
+ refute(x.eval(d), 'checking REGEX mismatch with an integer arg')
26
+ end
27
+
28
+ # TBD more tests for each type, Float, boolean, String, URI, UUID, Time, BigDecimal, nil
29
+
30
+ end # TestExprRegex
data/test/test_impl.rb ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative 'helper'
5
+
6
+ require 'wab/impl'
7
+
8
+ class TestImpl < Minitest::Test
9
+
10
+ def setup
11
+ @shell = WAB::Impl::Shell.new(
12
+ WAB::Impl::Configuration.new('',
13
+ 'base' => File.join(__dir__, 'tmp')
14
+ )
15
+ )
16
+ end
17
+
18
+ def make_sample_data()
19
+ @shell.data({
20
+ boo: true,
21
+ n: nil,
22
+ num: 7,
23
+ float: 7.654,
24
+ str: 'a string',
25
+ t: Time.gm(2017, 1, 5, 15, 4, 33.123456789),
26
+ big: BigDecimal('63.21'),
27
+ uri: URI('http://opo.technology/sample'),
28
+ uuid: WAB::UUID.new('b0ca922d-372e-41f4-8fea-47d880188ba3'),
29
+ a: [],
30
+ h: {},
31
+ })
32
+ end
33
+ end # TestImpl
34
+
35
+ require 'test_configuration'
36
+ require 'test_data'
37
+ require 'test_expr'
38
+ require 'test_model'
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative 'helper'
5
+
6
+ require 'wab/impl'
7
+ require 'wab/io'
8
+ require 'mirror_controller'
9
+
10
+ class TestIoShell < Minitest::Test
11
+
12
+ def test_default_controller
13
+ run_fork_test([
14
+ [{rid: 'rid-mirror', api: 1, body: {kind: 'sample', num: 7}},
15
+ {rid: 'rid-mirror', api: 2, body: {kind: 'sample', num: 7}}]
16
+ ])
17
+ end
18
+
19
+ def test_create
20
+ run_fork_test([
21
+ [{rid: 'rid-create', api: 1, body: {op: 'NEW', path: ['sample'], content: {kind: 'sample', num: 7}}},
22
+ {rid: '1', api: 3, body: { insert:{ kind: 'sample', num: 7}}}],
23
+ [{rid: '1', api: 4, body: {ref: 123, code: 0}},
24
+ {rid: 'rid-create', api: 2, body: { ref: 123, code: 0}}]
25
+ ])
26
+ end
27
+
28
+ def test_create_with_where
29
+ run_fork_test([
30
+ [{rid: 'rid-create-where', api: 1, body: {op: 'NEW', path: ['sample'], query: {id: 12345}, content: {kind: 'sample', id: 12345, num: 7}}},
31
+ {rid: '1', api: 3, body: {where: ['AND', ['EQ', 'kind', "'sample"],['EQ', 'id', 12345]], insert:{ kind: 'sample', id: 12345, num: 7}}}],
32
+ [{rid: '1', api: 4, body: {ref: 123, code: 0}},
33
+ {rid: 'rid-create-where', api: 2, body: { ref: 123, code: 0 }}]
34
+ ])
35
+ end
36
+
37
+ def test_create_error
38
+ run_fork_test([
39
+ [{rid: 'rid-create-error', api: 1, body: {op: 'NEW', path: ['sample'], content: {kind: 'sample', num: 7}}},
40
+ {rid: '1', api: 3, body: { insert:{ kind: 'sample', num: 7}}}],
41
+ [{rid: '1', api: 4, body: {ref: 123, code: -1, error: 'something went wrong'}},
42
+ {rid: 'rid-create-error', api: 2, body: { code: -1, error: 'WAB::Error: error on sample create. something went wrong'}}]
43
+ ])
44
+ end
45
+
46
+ def test_read_by_id
47
+ run_fork_test([
48
+ [{rid: 'rid-read-id', api: 1, body: {op: 'GET', path: ['sample', '12345']}},
49
+ {rid: '1', api: 3, body: {where: 12345, select: '$'}}],
50
+ [{rid: '1', api: 4, body: {code: 0, results:[{kind: 'sample', id: 12345, num: 7}]}},
51
+ {rid: 'rid-read-id', api: 2, body: { code: 0, results:[{ id: 12345, data: { kind: 'sample', id: 12345, num: 7}}]}}]
52
+ ])
53
+ end
54
+
55
+ def test_read_by_attrs
56
+ run_fork_test([
57
+ [{rid: 'rid-read-attrs', api: 1, body: {op: 'GET', path: ['sample'], query: {id: 12345}}},
58
+ {rid: '1', api: 3, body: {where: ['AND', ['EQ', 'kind', "'sample"], ['EQ', 'id', 12345]], select: {id: '$ref', data: '$' }}}],
59
+ [{rid: '1', api: 4, body: {code: 0, results: [{id: 12345, data: {kind: 'sample', id: 12345, num: 7}}]}},
60
+ {rid: 'rid-read-attrs', api: 2, body: {code: 0, results:[{id: 12345, data: {kind: 'sample', id: 12345, num: 7}}]}}]
61
+ ])
62
+ end
63
+
64
+ def test_read_list
65
+ run_fork_test([
66
+ [{rid: 'rid-read-list', api: 1, body: {op: 'GET', path: ['sample']}},
67
+ {rid: '1', api: 3, body: {where: ['EQ', 'kind', "'sample"], select: { id: '$ref', data: '$'}}}],
68
+ [{rid: '1', api: 4, body: {code: 0, results: [12345]}},
69
+ {rid: 'rid-read-list', api: 2, body: {code: 0, results:[12345]}}]
70
+ ])
71
+ end
72
+
73
+ def test_read_select
74
+ run_fork_test([
75
+ [{rid: 'rid-read-select', api: 1, body: {op: 'GET', path: ['sample', 'list'], query: { Age: 'num' }}},
76
+ {rid: '1', api: 3, body: {where: ['EQ', 'kind', "'sample"], select: { ref: '$ref', Age: 'num'}}}],
77
+ [{rid: '1', api: 4, body: {code: 0, results: [{ref: 12345, Age: 7 }]}},
78
+ {rid: 'rid-read-select', api: 2, body: {code: 0, results:[{ref: 12345, Age: 7 }]}}]
79
+ ])
80
+ end
81
+
82
+ def test_update_by_id
83
+ run_fork_test([
84
+ [{rid: 'rid-update-id', api: 1, body: {op: 'MOD', path: ['sample', '12345'], content: {kind: 'sample', id: 12345, num: 7}}},
85
+ {rid: '1', api: 3, body: {where: 12345, update: { kind: 'sample', id: 12345, num: 7}}}],
86
+ [{rid: '1', api: 4, body: {code: 0, updated: [12345]}},
87
+ {rid: 'rid-update-id', api: 2, body: { code: 0, updated: [12345]}}]
88
+ ])
89
+ end
90
+
91
+ def test_update_by_attrs
92
+ run_fork_test([
93
+ [{rid: 'rid-update-attrs', api: 1, body: {op: 'MOD', path: ['sample'], query: {id: 12345}, content: {kind: 'sample', id: 12345, num: 7}}},
94
+ {rid: '1', api: 3, body: {where: ['AND', ['EQ', 'kind', "'sample"],['EQ', 'id', 12345]], update: { kind: 'sample', id: 12345, num: 7}}}],
95
+ [{rid: '1', api: 4, body: {code: 0, updated: [12345]}},
96
+ {rid: 'rid-update-attrs', api: 2, body: { code: 0, updated: [12345]}}]
97
+ ])
98
+ end
99
+
100
+ def test_delete_by_id
101
+ run_fork_test([
102
+ [{rid: 'rid-delete-id', api: 1, body: {op: 'DEL', path: ['sample', '12345']}},
103
+ {rid: '1', api: 3, body: {where: 12345, delete: nil}}],
104
+ [{rid: '1', api: 4, body: {code: 0, deleted: [12345]}},
105
+ {rid: 'rid-delete-id', api: 2, body: { code: 0, deleted: [12345]}}]
106
+ ])
107
+ end
108
+
109
+ def test_delete_by_attrs
110
+ run_fork_test([
111
+ [{rid: 'rid-delete-attrs', api: 1, body: {op: 'DEL', path: ['sample'], query: {id: 12345}}},
112
+ {rid: '1', api: 3, body: {where: ['AND', ['EQ', 'kind', "'sample"],['EQ', 'id', 12345]], delete: nil}}],
113
+ [{rid: '1', api: 4, body: {code: 0, deleted: [12345]}},
114
+ {rid: 'rid-delete-attrs', api: 2, body: { code: 0, deleted: [12345]}}]
115
+ ])
116
+ end
117
+
118
+ def test_timeout
119
+ run_fork_test([
120
+ [{rid: 'rid-timeout', api: 1, body: {op: 'NEW', path: ['sample'], content: {kind: 'sample', num: 7}}},
121
+ {rid: '1', api: 3, body: { insert:{ kind: 'sample', num: 7}}}],
122
+ [nil,
123
+ {rid: 'rid-timeout', api: 2, body: { code: -1, error: 'WAB::Error: error on sample create. Timed out waiting for 1.'}}]
124
+ ])
125
+ end
126
+
127
+ # Fork and create a shell in the child. For each pair in the script send the
128
+ # first message and wait for the second. Compare second for test success of
129
+ # failure.
130
+ def run_fork_test(script)
131
+ # Windows does not support fork
132
+ return if RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/
133
+
134
+ to_r, to_w = IO.pipe
135
+ from_r, from_w = IO.pipe
136
+
137
+ if fork.nil? # child
138
+ $stdin = to_r
139
+ to_w.close
140
+ $stdout = from_w
141
+ from_r.close
142
+
143
+ shell = WAB::IO::Shell.new(2, 'kind', 0)
144
+ shell.timeout = 0.5
145
+ shell.logger.level = Logger::WARN # change to Logger::INFO for debugging
146
+ shell.register_controller(nil, MirrorController.new(shell))
147
+ shell.start
148
+
149
+ Process.exit(0)
150
+ else
151
+ to_r.close
152
+ from_w.close
153
+
154
+ # Shell#data should be called instead but for this test a shell is not
155
+ # desired.
156
+ script.each { |pair|
157
+ unless pair[0].nil?
158
+ to_w.puts(WAB::Impl::Data.new(pair[0], false).json)
159
+ to_w.flush
160
+ end
161
+
162
+ reply = nil
163
+ Oj.strict_load(from_r, symbol_keys: true) { |msg| reply = msg; break }
164
+
165
+ # remove backtrace if an error
166
+ bt = nil
167
+ if !reply.nil? && !reply[:body].nil?
168
+ bt = reply[:body].delete(:backtrace)
169
+ end
170
+ begin
171
+ assert_equal(pair[1], reply)
172
+ rescue Exception => e
173
+ puts ''
174
+ puts bt
175
+ raise e
176
+ end
177
+ }
178
+ # On error the pipe may be closed from the child side so the write will
179
+ # fail. Thats okay as the write is only to tell the child to shutdown
180
+ # and it already has.
181
+ begin
182
+ to_w.puts(WAB::Impl::Data.new({ api: -2 }, false).json)
183
+ to_w.flush
184
+ rescue Exception
185
+ end
186
+ end
187
+ end
188
+
189
+ end
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative 'helper'
5
+
6
+ require 'wab/impl/model'
7
+
8
+ class TestModel < TestImpl
9
+
10
+ def test_model_create
11
+ # nil arg indicates don't save to disk
12
+ model = WAB::Impl::Model.new(nil)
13
+ tql = {
14
+ rid: 12345,
15
+ insert: {
16
+ kind: 'Person',
17
+ name: 'Peter',
18
+ age: 63
19
+ }
20
+ }
21
+ result = model.query(tql)
22
+ assert_equal(0, result[:code], 'expected a 0 result code')
23
+ assert_equal(12345, result[:rid], 'expected correct rid')
24
+ ref = result[:ref]
25
+ # get and verify object was stored.
26
+ obj = model.get(ref)
27
+
28
+ assert_equal({kind: 'Person', name: 'Peter', age: 63}, obj.native, 'obj get mismatch')
29
+ end
30
+
31
+ end # TestModel
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative 'helper'
5
+
6
+ require 'net/http'
7
+ require 'oj'
8
+
9
+ require 'wab/impl'
10
+ require 'wab/io'
11
+
12
+ # -----------------------------------------------------------------------------
13
+ # This is to verify that WAB-Runners behave as expected.
14
+ #
15
+ # Requirements:
16
+ # - The Runner (e.g. OpO daemon) should be started with the MirrorController
17
+ # class.
18
+ # - The host and port must be the last argument on the command line when
19
+ # invoking the test.
20
+ #
21
+ # Example usage:
22
+ # runner_test.rb localhost:6363
23
+ # -----------------------------------------------------------------------------
24
+
25
+ raise ArgumentError, 'Host and port not supplied.' if ARGV.empty?
26
+
27
+ $host, $port = ARGV[-1].split(':')
28
+ $port = $port.to_i
29
+
30
+ class TestRunner < Minitest::Test
31
+
32
+ # The Runner or rather it's storage is stateful so all steps in the test
33
+ # must be made in order to keep the test self contained. Each step is a
34
+ # separate function though.
35
+ def test_runner_basics
36
+ http = Net::HTTP.new($host, $port)
37
+
38
+ # Delete all records to start with a clean database
39
+ clear_records(http)
40
+ ref = create_record(http)
41
+ read_record(http, ref)
42
+ list_records(http, ref)
43
+
44
+ ref = update_record(http, ref)
45
+ read_after_update(http, ref)
46
+
47
+ delete_record(http, ref)
48
+ read_after_delete(http, ref)
49
+ end
50
+
51
+ def clear_records(http)
52
+ resp = http.send_request('DELETE', '/v1/Article')
53
+ # Response should be an OK with a JSON body.
54
+ assert_equal(Net::HTTPOK, resp.class, 'response not an OK')
55
+ reply = Oj.strict_load(resp.body, symbol_keys: true)
56
+ end
57
+
58
+ # Returns the reference of the created record.
59
+ def create_record(http)
60
+ json = %|{
61
+ "kind": "Article",
62
+ "title": "Sample",
63
+ "text": "Just some random text."
64
+ }|
65
+ resp = http.send_request('PUT', '/v1/Article', json, { 'Content-Type' => 'application/json' })
66
+ # Response should be an OK with a JSON body.
67
+ assert_equal(Net::HTTPOK, resp.class, 'response not an OK')
68
+ reply = Oj.strict_load(resp.body, symbol_keys: true)
69
+
70
+ # Make sure the message has the correct fields and values.
71
+ assert_equal(0, reply[:code], 'create reply.code should be 0 meaning no error')
72
+ ref = reply[:ref]
73
+ refute_equal(nil, ref, 'create reply record reference can not be nil')
74
+ refute_equal(0, ref, 'create reply record reference can not be 0')
75
+ ref
76
+ end
77
+
78
+ def read_record(http, ref)
79
+ resp = http.send_request('GET', "/v1/Article/#{ref}")
80
+ assert_equal(Net::HTTPOK, resp.class, 'response not an OK')
81
+ reply = Oj.strict_load(resp.body, symbol_keys: true)
82
+
83
+ # Make sure the message has the correct fields and values.
84
+ assert_equal(0, reply[:code], 'read reply.code should be 0 meaning no error')
85
+ results = reply[:results]
86
+ assert_equal(1, results.length, 'read reply.results should contain exactly one member')
87
+ record = results[0]
88
+ assert_equal(ref, record[:id], 'read reply.results[0].id should match the record reference')
89
+ obj = record[:data]
90
+ assert_equal('Article', obj[:kind], 'read reply obj.kind incorrect')
91
+ assert_equal('Sample', obj[:title], 'read reply obj.title incorrect')
92
+ end
93
+
94
+ def list_records(http, ref)
95
+ resp = http.send_request('GET', '/v1/Article')
96
+ assert_equal(Net::HTTPOK, resp.class, 'response not an OK')
97
+ reply = Oj.strict_load(resp.body, symbol_keys: true)
98
+
99
+ # Make sure the message has the correct fields and values.
100
+ assert_equal(0, reply[:code], 'read reply.code should be 0 meaning no error')
101
+ results = reply[:results]
102
+ assert_equal(1, results.length, 'read reply.results should contain exactly one member')
103
+ record = results[0]
104
+ assert_equal(ref, record[:id], 'read reply.results[0].id should match the record reference')
105
+ obj = record[:data]
106
+ assert_equal('Article', obj[:kind], 'read reply obj.kind incorrect')
107
+ assert_equal('Sample', obj[:title], 'read reply obj.title incorrect')
108
+ end
109
+
110
+ # Returns the reference of the updated record. There is no requirement that
111
+ # the reference will not change.
112
+ def update_record(http, ref)
113
+ json = %|{
114
+ "kind": "Article",
115
+ "title": "Sample",
116
+ "text": "Updated text."
117
+ }|
118
+ resp = http.send_request('POST', "/v1/Article/#{ref}", json, { 'Content-Type' => 'application/json' })
119
+ # Response should be an OK with a JSON body.
120
+ assert_equal(Net::HTTPOK, resp.class, 'response not an OK')
121
+ reply = Oj.strict_load(resp.body, symbol_keys: true)
122
+
123
+ # Make sure the message has the correct fields and values.
124
+ assert_equal(0, reply[:code], 'update reply.code should be 0 meaning no error')
125
+ updated = reply[:updated]
126
+ assert_equal(1, updated.length, 'update reply.updated should contain exactly one member')
127
+ ref = updated[0]
128
+ refute_equal(nil, ref, 'update reply record reference can not be nil')
129
+ refute_equal(0, ref, 'update reply record reference can not be 0')
130
+ ref
131
+ end
132
+
133
+ def read_after_update(http, ref)
134
+ resp = http.send_request('GET', "/v1/Article/#{ref}")
135
+ assert_equal(Net::HTTPOK, resp.class, 'response not an OK')
136
+ reply = Oj.strict_load(resp.body, symbol_keys: true)
137
+
138
+ assert_equal(0, reply[:code], 'read after update reply.code should be 0 meaning no error')
139
+ results = reply[:results]
140
+ assert_equal(1, results.length, 'read after update reply.results should contain exactly one member')
141
+ record = results[0]
142
+ assert_equal(ref, record[:id], 'read after update reply.results[0].id should match the record reference')
143
+ obj = record[:data]
144
+ assert_equal('Updated text.', obj[:text], 'read after update reply obj.text incorrect')
145
+ end
146
+
147
+ def delete_record(http, ref)
148
+ resp = http.send_request('DELETE', "/v1/Article/#{ref}")
149
+ # Response should be an OK with a JSON body.
150
+ assert_equal(Net::HTTPOK, resp.class, 'response not an OK')
151
+ reply = Oj.strict_load(resp.body, symbol_keys: true)
152
+
153
+ # Make sure the message has the correct fields and values.
154
+ assert_equal(0, reply[:code], 'delete reply.code should be 0 meaning no error')
155
+ deleted = reply[:deleted]
156
+ assert_equal(1, deleted.length, 'delete reply.deleted should contain exactly one member')
157
+ ref = deleted[0]
158
+ refute_equal(nil, ref, 'delete reply record reference can not be nil')
159
+ refute_equal(0, ref, 'delete reply record reference can not be 0')
160
+ end
161
+
162
+ def read_after_delete(http, ref)
163
+ resp = http.send_request('GET', "/v1/Article/#{ref}")
164
+ assert_equal(Net::HTTPOK, resp.class, 'response not an OK')
165
+ reply = Oj.strict_load(resp.body, symbol_keys: true)
166
+
167
+ assert_equal(0, reply[:code], 'read after delete reply.code should be 0 meaning no error')
168
+ results = reply[:results]
169
+ assert_equal(0, results.length, 'read after delete reply.results should contain no members')
170
+ end
171
+
172
+ # TBD test failure modes as well
173
+ # TBD test multiple matches on update and delete
174
+ # TBD test no matches on update and delete
175
+ # TBD test queries
176
+
177
+ end # TestRunner
data/test/tests.rb CHANGED
@@ -1,12 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: UTF-8
3
3
 
4
- $: << File.dirname(__FILE__)
5
- $: << File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'lib')
4
+ require_relative 'helper'
6
5
 
7
- require 'minitest'
8
- require 'minitest/autorun'
9
-
10
- require 'impl_test'
11
-
12
- require 'ioshell_test'
6
+ require 'test_impl'
7
+ require 'test_io_shell'