syntropy 0.33.0 → 0.34.0
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/CHANGELOG.md +7 -0
- data/cmd/console.rb +18 -7
- data/cmd/serve.rb +26 -18
- data/cmd/test.rb +37 -24
- data/examples/blog/.gitignore +1 -0
- data/examples/blog/app/_lib/database.rb +13 -0
- data/examples/blog/app/_lib/{post_store.rb → posts.rb} +3 -1
- data/examples/blog/app/posts/[id]/edit.rb +2 -2
- data/examples/blog/app/posts/[id]/index.rb +4 -4
- data/examples/blog/app/posts/index.rb +4 -4
- data/examples/blog/app/posts/new.rb +1 -1
- data/examples/blog/config/development.rb +5 -0
- data/examples/blog/config/production.rb +4 -0
- data/examples/blog/config/test.rb +5 -0
- data/examples/blog/test/test_posts.rb +65 -0
- data/examples/mcp-oauth/app/oauth/token.rb +1 -1
- data/lib/syntropy/app.rb +48 -40
- data/lib/syntropy/applets/builtin/auto_refresh/watch.sse.rb +1 -1
- data/lib/syntropy/db/schema.rb +1 -1
- data/lib/syntropy/db/store.rb +2 -0
- data/lib/syntropy/errors.rb +6 -2
- data/lib/syntropy/http/client.rb +1 -0
- data/lib/syntropy/http/server_connection.rb +0 -4
- data/lib/syntropy/json_api.rb +27 -1
- data/lib/syntropy/logger.rb +81 -27
- data/lib/syntropy/markdown.rb +61 -32
- data/lib/syntropy/mime_types.rb +9 -5
- data/lib/syntropy/module_loader.rb +20 -9
- data/lib/syntropy/papercraft_extensions.rb +2 -2
- data/lib/syntropy/request/mock_adapter.rb +10 -8
- data/lib/syntropy/request/request_info.rb +91 -0
- data/lib/syntropy/request/response.rb +1 -12
- data/lib/syntropy/request/validation.rb +1 -0
- data/lib/syntropy/request.rb +51 -19
- data/lib/syntropy/routing_tree.rb +27 -28
- data/lib/syntropy/session.rb +198 -0
- data/lib/syntropy/side_run.rb +25 -2
- data/lib/syntropy/test.rb +105 -10
- data/lib/syntropy/utils.rb +53 -18
- data/lib/syntropy/version.rb +1 -1
- data/lib/syntropy.rb +44 -10
- data/test/bm_router_proc.rb +4 -4
- data/test/fixtures/app/class_instance.rb +5 -0
- data/test/fixtures/app/http.rb +5 -0
- data/test/fixtures/app/post_ct.rb +5 -0
- data/test/fixtures/app/singleton.rb +3 -0
- data/test/test_app.rb +13 -52
- data/test/test_caching.rb +2 -2
- data/test/test_db_schema.rb +1 -1
- data/test/test_http_server_connection.rb +3 -3
- data/test/test_module_loader.rb +5 -2
- data/test/test_response.rb +0 -19
- data/test/test_routing_tree.rb +69 -69
- data/test/test_server.rb +5 -9
- data/test/test_test.rb +70 -0
- metadata +52 -42
- data/examples/blog/app/_setup.rb +0 -4
- data/lib/syntropy/request/session.rb +0 -113
- /data/test/{app → fixtures/app}/.well-known/foo.rb +0 -0
- /data/test/{app → fixtures/app}/_hook.rb +0 -0
- /data/test/{app → fixtures/app}/_layout/default.rb +0 -0
- /data/test/{app → fixtures/app}/_lib/callable.rb +0 -0
- /data/test/{app → fixtures/app}/_lib/dep.rb +0 -0
- /data/test/{app → fixtures/app}/_lib/env.rb +0 -0
- /data/test/{app → fixtures/app}/_lib/klass.rb +0 -0
- /data/test/{app → fixtures/app}/_lib/missing-export.rb +0 -0
- /data/test/{app → fixtures/app}/_lib/self.rb +0 -0
- /data/test/{app → fixtures/app}/about/_error.rb +0 -0
- /data/test/{app → fixtures/app}/about/foo.md +0 -0
- /data/test/{app → fixtures/app}/about/index.rb +0 -0
- /data/test/{app → fixtures/app}/about/raise.rb +0 -0
- /data/test/{app → fixtures/app}/api+.rb +0 -0
- /data/test/{app → fixtures/app}/assets/style.css +0 -0
- /data/test/{app → fixtures/app}/bad_mod.rb +0 -0
- /data/test/{app → fixtures/app}/bar.rb +0 -0
- /data/test/{app → fixtures/app}/baz.rb +0 -0
- /data/test/{app → fixtures/app}/by_method.rb +0 -0
- /data/test/{app → fixtures/app}/deps.rb +0 -0
- /data/test/{app → fixtures/app}/index.html +0 -0
- /data/test/{app → fixtures/app}/mod/bar/index+.rb +0 -0
- /data/test/{app → fixtures/app}/mod/foo/index.rb +0 -0
- /data/test/{app → fixtures/app}/mod/path/a.rb +0 -0
- /data/test/{app → fixtures/app}/mod/path/b.rb +0 -0
- /data/test/{app → fixtures/app}/params/[foo].rb +0 -0
- /data/test/{app → fixtures/app}/rss.rb +0 -0
- /data/test/{app → fixtures/app}/tmp.rb +0 -0
- /data/test/{app_custom → fixtures/app_custom}/_site.rb +0 -0
- /data/test/{app_multi_site → fixtures/app_multi_site}/_site.rb +0 -0
- /data/test/{app_multi_site → fixtures/app_multi_site}/bar.baz/index.html +0 -0
- /data/test/{app_multi_site → fixtures/app_multi_site}/foo.bar/index.html +0 -0
- /data/test/{app_setup → fixtures/app_setup}/_setup.rb +0 -0
- /data/test/{app_setup → fixtures/app_setup}/index.rb +0 -0
- /data/test/{app_with_schema → fixtures/app_with_schema}/_schema/2026-01-02-foo.rb +0 -0
- /data/test/{app_with_schema → fixtures/app_with_schema}/_schema/2026-05-30-bar.rb +0 -0
- /data/test/{schema → fixtures/schema}/2026-01-02-foo.rb +0 -0
- /data/test/{schema → fixtures/schema}/2026-05-30-bar.rb +0 -0
data/lib/syntropy/utils.rb
CHANGED
|
@@ -1,52 +1,87 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
3
5
|
module Syntropy
|
|
4
6
|
# Utilities for use in modules
|
|
5
7
|
module Utilities
|
|
6
|
-
|
|
8
|
+
def tmp_path(prefix = 'syntropy')
|
|
9
|
+
"/tmp/#{prefix}-#{SecureRandom.hex(16)}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Returns a request handler that routes request according to the host
|
|
13
|
+
# header. Looks for site directories (named by host name) in the app's root
|
|
14
|
+
# directory. A map may be given in order to provide additional hostnames to
|
|
15
|
+
# site directories.
|
|
16
|
+
#
|
|
17
|
+
# @param env [Hash] app environment hash
|
|
18
|
+
# @param map [Hash, nil] additional hostname map
|
|
19
|
+
# @return [Proc] router proc
|
|
7
20
|
def route_by_host(env, map = nil)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
.select { File.directory?(it) }
|
|
12
|
-
.each_with_object({}) { |fn, h|
|
|
13
|
-
name = File.basename(fn)
|
|
14
|
-
h[name] = Syntropy::App.new(**env.merge(root_dir: fn))
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
# copy over map refs
|
|
21
|
+
sites = find_hostname_sites(env)
|
|
22
|
+
|
|
23
|
+
# add map refs
|
|
18
24
|
map&.each { |k, v| sites[k] = sites[v] }
|
|
19
25
|
|
|
20
|
-
#
|
|
21
26
|
lambda { |req|
|
|
22
27
|
site = sites[req.host]
|
|
23
28
|
site ? site.call(req) : req.respond(nil, ':status' => HTTP::BAD_REQUEST)
|
|
24
29
|
}
|
|
25
30
|
end
|
|
26
31
|
|
|
32
|
+
# Returns a list of parsed markdown pages at the given path.
|
|
33
|
+
#
|
|
34
|
+
# @param env [Hash] app environment hash
|
|
35
|
+
# @param ref [String] directory path
|
|
36
|
+
# @return [Array<Hash>] array of page entries
|
|
27
37
|
def page_list(env, ref)
|
|
28
|
-
full_path = File.join(env[:
|
|
38
|
+
full_path = File.join(env[:app_root], ref)
|
|
29
39
|
raise 'Not a directory' if !File.directory?(full_path)
|
|
30
40
|
|
|
31
41
|
Dir[File.join(full_path, '*.md')].sort.map {
|
|
32
|
-
atts, markdown = Syntropy.
|
|
42
|
+
atts, markdown = Syntropy::Markdown.parse(it, env)
|
|
33
43
|
{ atts:, markdown: }
|
|
34
44
|
}
|
|
35
45
|
end
|
|
36
46
|
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
# Instantiates a Syntropy app for the given environment hash.
|
|
48
|
+
#
|
|
49
|
+
# @return [Syntropy::App]
|
|
50
|
+
def app(**)
|
|
51
|
+
Syntropy::App.new(**)
|
|
39
52
|
end
|
|
40
53
|
|
|
41
|
-
|
|
54
|
+
BUILTIN_APPLET_app_root = File.expand_path(File.join(__dir__, 'applets/builtin'))
|
|
55
|
+
|
|
56
|
+
# Creates a builtin applet with the given environment hash. By default the
|
|
57
|
+
# builtin applet is mounted at /.syntropy.
|
|
58
|
+
#
|
|
59
|
+
# @param env [Hash] app environment
|
|
60
|
+
# @param mount_path [String] mount path for the builtin applet
|
|
61
|
+
# @return [Syntropy::App] applet
|
|
42
62
|
def builtin_applet(env, mount_path: '/.syntropy')
|
|
43
63
|
app(
|
|
44
64
|
machine: env[:machine],
|
|
45
|
-
|
|
65
|
+
app_root: BUILTIN_APPLET_app_root,
|
|
46
66
|
mount_path: mount_path,
|
|
47
67
|
builtin_applet_path: nil,
|
|
48
68
|
watch_files: nil
|
|
49
69
|
)
|
|
50
70
|
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# Finds sites in the root directory for the given environment hash.
|
|
75
|
+
#
|
|
76
|
+
# @param env [Hash] app environment hash
|
|
77
|
+
# @return [Hash] hash mapping hostname to app
|
|
78
|
+
def find_hostname_sites(env)
|
|
79
|
+
Dir[File.join(env[:app_root], '*')]
|
|
80
|
+
.select { File.directory?(it) && File.basename(it) !~ /^_/ }
|
|
81
|
+
.each_with_object({}) { |fn, h|
|
|
82
|
+
name = File.basename(fn)
|
|
83
|
+
h[name] = Syntropy::App.new(**env.merge(app_root: fn))
|
|
84
|
+
}
|
|
85
|
+
end
|
|
51
86
|
end
|
|
52
87
|
end
|
data/lib/syntropy/version.rb
CHANGED
data/lib/syntropy.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'uringmachine'
|
|
4
4
|
require 'papercraft'
|
|
5
|
+
require 'yaml'
|
|
5
6
|
|
|
6
7
|
require 'syntropy/request'
|
|
7
8
|
require 'syntropy/logger'
|
|
@@ -21,20 +22,31 @@ require 'syntropy/side_run'
|
|
|
21
22
|
require 'syntropy/utils'
|
|
22
23
|
require 'syntropy/version'
|
|
23
24
|
|
|
25
|
+
# Syntropy is a web framework for building web apps in Ruby. Syntropy uses
|
|
26
|
+
# UringMachine for I/O and concurrency, and provides a comprehensive and
|
|
27
|
+
# flexible solution for writing web apps with minimal boilerplate.
|
|
24
28
|
module Syntropy
|
|
25
29
|
extend Utilities
|
|
26
30
|
|
|
27
31
|
class << self
|
|
28
|
-
attr_accessor :machine
|
|
32
|
+
attr_accessor :machine, :dev_mode
|
|
29
33
|
|
|
34
|
+
# Runs the given block on a separate thread. Use this method for running
|
|
35
|
+
# code that is not fiber-aware (i.e. does not use UringMachine).
|
|
36
|
+
#
|
|
37
|
+
# @return [any] operation return value
|
|
30
38
|
def side_run(&block)
|
|
31
39
|
raise 'Syntropy.machine not set' if !@machine
|
|
32
40
|
|
|
33
41
|
SideRun.call(@machine, &block)
|
|
34
42
|
end
|
|
35
|
-
end
|
|
36
43
|
|
|
37
|
-
|
|
44
|
+
# Runs a web app with the given environment hash. The given block is either
|
|
45
|
+
# an instance of Syntropy::App, or a Proc/callable that takes a request as
|
|
46
|
+
# argument.
|
|
47
|
+
#
|
|
48
|
+
# @param env [Hash] environment
|
|
49
|
+
# @return [void]
|
|
38
50
|
def run(env = {}, &app)
|
|
39
51
|
if @in_run
|
|
40
52
|
@env = env
|
|
@@ -47,7 +59,14 @@ module Syntropy
|
|
|
47
59
|
@in_run = true
|
|
48
60
|
machine = env[:machine] || UM.new
|
|
49
61
|
|
|
50
|
-
env[:logger]
|
|
62
|
+
if (logger = env[:logger])
|
|
63
|
+
logger.info(
|
|
64
|
+
message: "Syntropy #{Syntropy::VERSION}, UringMachine #{UM::VERSION}, Ruby #{RUBY_VERSION}"
|
|
65
|
+
)
|
|
66
|
+
logger.info(
|
|
67
|
+
message: "Running in #{env[:mode]} mode"
|
|
68
|
+
)
|
|
69
|
+
end
|
|
51
70
|
|
|
52
71
|
server = HTTP::Server.new(machine, env, &app)
|
|
53
72
|
|
|
@@ -58,23 +77,38 @@ module Syntropy
|
|
|
58
77
|
end
|
|
59
78
|
end
|
|
60
79
|
|
|
61
|
-
def
|
|
62
|
-
return
|
|
80
|
+
def load_config(env)
|
|
81
|
+
return if !env[:config_root]
|
|
82
|
+
|
|
83
|
+
loader_env = env.merge(
|
|
84
|
+
app_root: env[:config_root],
|
|
85
|
+
logger: nil
|
|
86
|
+
)
|
|
87
|
+
loader = ModuleLoader.new(loader_env)
|
|
88
|
+
config = loader.load(env[:mode])
|
|
63
89
|
|
|
64
|
-
|
|
65
|
-
@env[:app] = app if app
|
|
90
|
+
env[:config] = config
|
|
66
91
|
end
|
|
67
92
|
|
|
68
93
|
private
|
|
69
94
|
|
|
95
|
+
# Sets up asynchronous SIGINT handling.
|
|
96
|
+
#
|
|
97
|
+
# @param machine [UringMachine] machine instance
|
|
98
|
+
# @param fiber [Fiber] fiber to terminate on SIGINT
|
|
99
|
+
# @return [void]
|
|
70
100
|
def setup_signal_handling(machine, fiber)
|
|
71
101
|
queue = UM::Queue.new
|
|
72
102
|
trap('SIGINT') { machine.push(queue, :SIGINT) }
|
|
73
103
|
machine.spin { watch_for_int_signal(machine, queue, fiber) }
|
|
74
104
|
end
|
|
75
105
|
|
|
76
|
-
#
|
|
77
|
-
#
|
|
106
|
+
# Waits for signal from queue, then terminates the given fiber.
|
|
107
|
+
#
|
|
108
|
+
# @param machine [UringMachine] machine instance
|
|
109
|
+
# @param queue [UringMachine::Queue] queue to wait on
|
|
110
|
+
# @param fiber [Fiber] fiber to terminate
|
|
111
|
+
# @return [void]
|
|
78
112
|
def watch_for_int_signal(machine, queue, fiber)
|
|
79
113
|
machine.shift(queue)
|
|
80
114
|
machine.schedule(fiber, UM::Terminate.new)
|
data/test/bm_router_proc.rb
CHANGED
|
@@ -138,8 +138,8 @@ def make_tmp_file_tree(dir, spec)
|
|
|
138
138
|
dir
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
make_tmp_file_tree(
|
|
141
|
+
app_root = "/tmp/#{__FILE__.gsub('/', '-')}-#{SecureRandom.hex}"
|
|
142
|
+
make_tmp_file_tree(app_root, {
|
|
143
143
|
'index.rb': "export ->(req) { req.redirect('/hello') }",
|
|
144
144
|
'hello': {
|
|
145
145
|
'index.rb': "export ->(req) { req.respond('Hello!', 'Content-Type' => 'text/html') }",
|
|
@@ -149,7 +149,7 @@ make_tmp_file_tree(ROOT_DIR, {
|
|
|
149
149
|
|
|
150
150
|
machine = UM.new
|
|
151
151
|
syntropy_app = Syntropy::App.new(
|
|
152
|
-
|
|
152
|
+
app_root: app_root,
|
|
153
153
|
mount_path: '/',
|
|
154
154
|
machine: machine
|
|
155
155
|
)
|
|
@@ -185,7 +185,7 @@ BM.run do
|
|
|
185
185
|
def setup
|
|
186
186
|
machine = UM.new
|
|
187
187
|
syntropy_app = Syntropy::App.new(
|
|
188
|
-
|
|
188
|
+
app_root: app_root,
|
|
189
189
|
mount_path: '/',
|
|
190
190
|
# watch_files: 0.05,
|
|
191
191
|
machine: machine
|
data/test/test_app.rb
CHANGED
|
@@ -5,7 +5,7 @@ require_relative 'helper'
|
|
|
5
5
|
class AppTest < Minitest::Test
|
|
6
6
|
HTTP = Syntropy::HTTP
|
|
7
7
|
|
|
8
|
-
APP_ROOT = File.join(__dir__, 'app')
|
|
8
|
+
APP_ROOT = File.join(__dir__, 'fixtures/app')
|
|
9
9
|
|
|
10
10
|
def setup
|
|
11
11
|
@machine = UM.new
|
|
@@ -14,7 +14,7 @@ class AppTest < Minitest::Test
|
|
|
14
14
|
@tmp_fn = File.join(APP_ROOT, 'tmp.rb')
|
|
15
15
|
|
|
16
16
|
@app = Syntropy::App.new(
|
|
17
|
-
|
|
17
|
+
app_root: APP_ROOT,
|
|
18
18
|
mount_path: '/test',
|
|
19
19
|
watch_files: 0.05,
|
|
20
20
|
machine: @machine
|
|
@@ -133,6 +133,9 @@ class AppTest < Minitest::Test
|
|
|
133
133
|
|
|
134
134
|
req = @test_harness.request(':method' => 'DELETE', ':path' => '/test/by_method')
|
|
135
135
|
assert_equal HTTP::METHOD_NOT_ALLOWED, req.response_status
|
|
136
|
+
|
|
137
|
+
req = @test_harness.request(':method' => 'GET', ':path' => '/test/http')
|
|
138
|
+
assert_equal HTTP::TEAPOT, req.response_status
|
|
136
139
|
end
|
|
137
140
|
|
|
138
141
|
def test_automatic_redirect_on_trailing_slash
|
|
@@ -183,13 +186,13 @@ end
|
|
|
183
186
|
class CustomAppTest < Minitest::Test
|
|
184
187
|
HTTP = Syntropy::HTTP
|
|
185
188
|
|
|
186
|
-
APP_ROOT = File.join(__dir__, 'app_custom')
|
|
189
|
+
APP_ROOT = File.join(__dir__, 'fixtures/app_custom')
|
|
187
190
|
|
|
188
191
|
def setup
|
|
189
192
|
@machine = UM.new
|
|
190
193
|
@app = Syntropy::App.load(
|
|
191
194
|
machine: @machine,
|
|
192
|
-
|
|
195
|
+
app_root: APP_ROOT,
|
|
193
196
|
mount_path: '/'
|
|
194
197
|
)
|
|
195
198
|
@test_harness = Syntropy::TestHarness.new(@app)
|
|
@@ -205,13 +208,13 @@ end
|
|
|
205
208
|
class MultiSiteAppTest < Minitest::Test
|
|
206
209
|
HTTP = Syntropy::HTTP
|
|
207
210
|
|
|
208
|
-
APP_ROOT = File.join(__dir__, 'app_multi_site')
|
|
211
|
+
APP_ROOT = File.join(__dir__, 'fixtures/app_multi_site')
|
|
209
212
|
|
|
210
213
|
def setup
|
|
211
214
|
@machine = UM.new
|
|
212
215
|
@app = Syntropy::App.load(
|
|
213
216
|
machine: @machine,
|
|
214
|
-
|
|
217
|
+
app_root: APP_ROOT,
|
|
215
218
|
mount_path: '/'
|
|
216
219
|
)
|
|
217
220
|
@test_harness = Syntropy::TestHarness.new(@app)
|
|
@@ -233,7 +236,7 @@ end
|
|
|
233
236
|
class AppAPITest < Minitest::Test
|
|
234
237
|
HTTP = Syntropy::HTTP
|
|
235
238
|
|
|
236
|
-
APP_ROOT = File.join(__dir__, 'app')
|
|
239
|
+
APP_ROOT = File.join(__dir__, 'fixtures/app')
|
|
237
240
|
|
|
238
241
|
def setup
|
|
239
242
|
@machine = UM.new
|
|
@@ -242,7 +245,7 @@ class AppAPITest < Minitest::Test
|
|
|
242
245
|
@tmp_fn = File.join(APP_ROOT, 'tmp.rb')
|
|
243
246
|
|
|
244
247
|
@app = Syntropy::App.new(
|
|
245
|
-
|
|
248
|
+
app_root: APP_ROOT,
|
|
246
249
|
mount_path: '/test',
|
|
247
250
|
watch_files: 0.05,
|
|
248
251
|
machine: @machine
|
|
@@ -297,7 +300,7 @@ end
|
|
|
297
300
|
class AppDependenciesTest < Minitest::Test
|
|
298
301
|
HTTP = Syntropy::HTTP
|
|
299
302
|
|
|
300
|
-
APP_ROOT = File.join(__dir__, 'app')
|
|
303
|
+
APP_ROOT = File.join(__dir__, 'fixtures/app')
|
|
301
304
|
|
|
302
305
|
def test_app_dependencies
|
|
303
306
|
foo = { foo: 'foo' }
|
|
@@ -309,7 +312,7 @@ class AppDependenciesTest < Minitest::Test
|
|
|
309
312
|
@tmp_fn = File.join(APP_ROOT, 'tmp.rb')
|
|
310
313
|
|
|
311
314
|
@app = Syntropy::App.new(
|
|
312
|
-
|
|
315
|
+
app_root: APP_ROOT,
|
|
313
316
|
mount_path: '/test',
|
|
314
317
|
machine: @machine,
|
|
315
318
|
foo: foo,
|
|
@@ -322,45 +325,3 @@ class AppDependenciesTest < Minitest::Test
|
|
|
322
325
|
assert_equal HTTP::OK, req.response_status
|
|
323
326
|
end
|
|
324
327
|
end
|
|
325
|
-
|
|
326
|
-
class AppDBSetupDBTest < Minitest::Test
|
|
327
|
-
HTTP = Syntropy::HTTP
|
|
328
|
-
|
|
329
|
-
APP_ROOT = File.join(__dir__, 'app_with_schema')
|
|
330
|
-
|
|
331
|
-
def test_app_setup_db
|
|
332
|
-
machine = UM.new
|
|
333
|
-
|
|
334
|
-
app = Syntropy::App.new(
|
|
335
|
-
root_dir: APP_ROOT,
|
|
336
|
-
mount_path: '/test',
|
|
337
|
-
machine: machine
|
|
338
|
-
)
|
|
339
|
-
|
|
340
|
-
assert_equal false, app.respond_to?(:connection_pool)
|
|
341
|
-
assert_equal false, app.respond_to?(:schema)
|
|
342
|
-
|
|
343
|
-
fn = "/tmp/#{rand(100000)}.db"
|
|
344
|
-
|
|
345
|
-
app.setup_db(
|
|
346
|
-
db_path: fn,
|
|
347
|
-
schema_root: '_schema'
|
|
348
|
-
)
|
|
349
|
-
|
|
350
|
-
assert_equal true, app.respond_to?(:connection_pool)
|
|
351
|
-
assert_equal fn, app.connection_pool.with_db { it.filename }
|
|
352
|
-
|
|
353
|
-
assert_equal true, app.respond_to?(:schema)
|
|
354
|
-
app.schema.apply(app.connection_pool)
|
|
355
|
-
assert_equal '2026-05-30-bar', app.schema.current_version(app.connection_pool)
|
|
356
|
-
|
|
357
|
-
assert_equal [
|
|
358
|
-
{
|
|
359
|
-
id: 1,
|
|
360
|
-
title: 'foo',
|
|
361
|
-
body: 'baz'
|
|
362
|
-
}
|
|
363
|
-
], app.connection_pool.query('select id, title, body from posts')
|
|
364
|
-
|
|
365
|
-
end
|
|
366
|
-
end
|
data/test/test_caching.rb
CHANGED
|
@@ -6,7 +6,7 @@ require 'digest/sha1'
|
|
|
6
6
|
class CachingTest < Minitest::Test
|
|
7
7
|
HTTP = Syntropy::HTTP
|
|
8
8
|
|
|
9
|
-
APP_ROOT = File.join(__dir__, 'app')
|
|
9
|
+
APP_ROOT = File.join(__dir__, 'fixtures/app')
|
|
10
10
|
|
|
11
11
|
def make_socket_pair
|
|
12
12
|
port = SecureRandom.random_number(10000..40000)
|
|
@@ -32,7 +32,7 @@ class CachingTest < Minitest::Test
|
|
|
32
32
|
|
|
33
33
|
@env = {
|
|
34
34
|
machine: @machine,
|
|
35
|
-
|
|
35
|
+
app_root: APP_ROOT,
|
|
36
36
|
mount_path: '/test',
|
|
37
37
|
watch_files: 0.05
|
|
38
38
|
}
|
data/test/test_db_schema.rb
CHANGED
|
@@ -77,7 +77,7 @@ class DBSchemaTest < Minitest::Test
|
|
|
77
77
|
|
|
78
78
|
def test_schema_from_module_files
|
|
79
79
|
module_loader = Syntropy::ModuleLoader.new({
|
|
80
|
-
|
|
80
|
+
app_root: File.join(__dir__, 'fixtures/schema')
|
|
81
81
|
})
|
|
82
82
|
schema = Syntropy::DB::Schema.new(module_loader:, schema_root: '/')
|
|
83
83
|
|
|
@@ -454,7 +454,7 @@ class HTTPServerConnectionTest < Minitest::Test
|
|
|
454
454
|
write_client_side("GET / HTTP/1.1\r\n\r\n")
|
|
455
455
|
@machine.spin do
|
|
456
456
|
@connection.serve_request
|
|
457
|
-
rescue => e
|
|
457
|
+
rescue StandardError => e
|
|
458
458
|
p e
|
|
459
459
|
p e.backtrace
|
|
460
460
|
end
|
|
@@ -479,7 +479,7 @@ class HTTPServerConnectionTest < Minitest::Test
|
|
|
479
479
|
|
|
480
480
|
@hook = ->(req) do
|
|
481
481
|
req.respond_with_static_file(fn, nil, nil, nil)
|
|
482
|
-
rescue => e
|
|
482
|
+
rescue StandardError => e
|
|
483
483
|
p e
|
|
484
484
|
p e.backtrace
|
|
485
485
|
end
|
|
@@ -490,7 +490,7 @@ class HTTPServerConnectionTest < Minitest::Test
|
|
|
490
490
|
write_client_side("GET / HTTP/1.1\r\n\r\n")
|
|
491
491
|
@machine.spin do
|
|
492
492
|
@connection.serve_request
|
|
493
|
-
rescue => e
|
|
493
|
+
rescue StandardError => e
|
|
494
494
|
p e
|
|
495
495
|
p e.backtrace
|
|
496
496
|
end
|
data/test/test_module_loader.rb
CHANGED
|
@@ -5,8 +5,8 @@ require_relative 'helper'
|
|
|
5
5
|
class ModuleTest < Minitest::Test
|
|
6
6
|
def setup
|
|
7
7
|
@machine = UM.new
|
|
8
|
-
@root = File.join(__dir__, 'app')
|
|
9
|
-
@env = {
|
|
8
|
+
@root = File.join(__dir__, 'fixtures/app')
|
|
9
|
+
@env = { app_root: @root, baz: 42, machine: @machine, app: 42 }
|
|
10
10
|
@loader = Syntropy::ModuleLoader.new(@env)
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -109,5 +109,8 @@ class ModuleTest < Minitest::Test
|
|
|
109
109
|
|
|
110
110
|
list = @loader.list('mod/bar')
|
|
111
111
|
assert_equal ['mod/bar/index+'], list
|
|
112
|
+
|
|
113
|
+
list = @loader.list('non-existent')
|
|
114
|
+
assert_equal [], list
|
|
112
115
|
end
|
|
113
116
|
end
|
data/test/test_response.rb
CHANGED
|
@@ -22,25 +22,6 @@ class RedirectTest < Minitest::Test
|
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
class StaticFileResponeTest < Minitest::Test
|
|
26
|
-
def setup
|
|
27
|
-
@path = File.join(__dir__, 'helper.rb')
|
|
28
|
-
@stat = File.stat(@path)
|
|
29
|
-
|
|
30
|
-
@etag = Syntropy::StaticFileCaching.file_stat_to_etag(@stat)
|
|
31
|
-
@last_modified = Syntropy::StaticFileCaching.file_stat_to_last_modified(@stat)
|
|
32
|
-
@content = IO.read(@path)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def test_serve_file_non_existent
|
|
36
|
-
r = Syntropy::MockAdapter.mock
|
|
37
|
-
r.serve_file('foo.rb', base_path: __dir__)
|
|
38
|
-
assert_equal [
|
|
39
|
-
[:respond, r, nil, { ':status' => Syntropy::HTTP::NOT_FOUND }]
|
|
40
|
-
], r.adapter.calls
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
25
|
class UpgradeTest < Minitest::Test
|
|
45
26
|
def test_upgrade
|
|
46
27
|
r = Syntropy::MockAdapter.mock
|