itsi 0.1.7 → 0.1.9

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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +21 -0
  3. data/crates/itsi_error/src/from.rs +26 -29
  4. data/crates/itsi_server/Cargo.lock +2956 -0
  5. data/crates/itsi_server/Cargo.toml +1 -1
  6. data/crates/itsi_server/src/lib.rs +5 -0
  7. data/crates/itsi_server/src/request/itsi_request.rs +37 -9
  8. data/crates/itsi_server/src/response/itsi_response.rs +12 -2
  9. data/crates/itsi_server/src/server/bind.rs +4 -3
  10. data/crates/itsi_server/src/server/itsi_server.rs +128 -78
  11. data/crates/itsi_server/src/server/listener.rs +98 -107
  12. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +40 -24
  13. data/crates/itsi_server/src/server/signal.rs +7 -0
  14. data/crates/itsi_server/src/server/thread_worker.rs +3 -4
  15. data/crates/itsi_server/src/server/tls.rs +20 -13
  16. data/crates/itsi_tracing/src/lib.rs +18 -1
  17. data/gems/scheduler/Cargo.lock +12 -12
  18. data/gems/scheduler/ext/itsi_error/src/from.rs +26 -29
  19. data/gems/scheduler/ext/itsi_server/Cargo.lock +2956 -0
  20. data/gems/scheduler/ext/itsi_server/Cargo.toml +1 -1
  21. data/gems/scheduler/ext/itsi_server/src/lib.rs +5 -0
  22. data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +37 -9
  23. data/gems/scheduler/ext/itsi_server/src/response/itsi_response.rs +12 -2
  24. data/gems/scheduler/ext/itsi_server/src/server/bind.rs +4 -3
  25. data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +128 -78
  26. data/gems/scheduler/ext/itsi_server/src/server/listener.rs +98 -107
  27. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +40 -24
  28. data/gems/scheduler/ext/itsi_server/src/server/signal.rs +7 -0
  29. data/gems/scheduler/ext/itsi_server/src/server/thread_worker.rs +3 -4
  30. data/gems/scheduler/ext/itsi_server/src/server/tls.rs +20 -13
  31. data/gems/scheduler/ext/itsi_tracing/src/lib.rs +18 -1
  32. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  33. data/gems/scheduler/test/test_address_resolve.rb +0 -1
  34. data/gems/scheduler/test/test_file_io.rb +0 -1
  35. data/gems/scheduler/test/test_kernel_sleep.rb +3 -4
  36. data/gems/server/Cargo.lock +2917 -0
  37. data/gems/server/Cargo.toml +7 -0
  38. data/gems/server/Rakefile +8 -1
  39. data/gems/server/ext/itsi_error/src/from.rs +26 -29
  40. data/gems/server/ext/itsi_server/Cargo.lock +2956 -0
  41. data/gems/server/ext/itsi_server/Cargo.toml +1 -1
  42. data/gems/server/ext/itsi_server/src/lib.rs +5 -0
  43. data/gems/server/ext/itsi_server/src/request/itsi_request.rs +37 -9
  44. data/gems/server/ext/itsi_server/src/response/itsi_response.rs +12 -2
  45. data/gems/server/ext/itsi_server/src/server/bind.rs +4 -3
  46. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +128 -78
  47. data/gems/server/ext/itsi_server/src/server/listener.rs +98 -107
  48. data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +40 -24
  49. data/gems/server/ext/itsi_server/src/server/signal.rs +7 -0
  50. data/gems/server/ext/itsi_server/src/server/thread_worker.rs +3 -4
  51. data/gems/server/ext/itsi_server/src/server/tls.rs +20 -13
  52. data/gems/server/ext/itsi_tracing/src/lib.rs +18 -1
  53. data/gems/server/lib/itsi/index.html +91 -0
  54. data/gems/server/lib/itsi/request.rb +29 -21
  55. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +3 -4
  56. data/gems/server/lib/itsi/server/rack_interface.rb +79 -0
  57. data/gems/server/lib/itsi/server/scheduler_interface.rb +21 -0
  58. data/gems/server/lib/itsi/server/scheduler_mode.rb +1 -1
  59. data/gems/server/lib/itsi/server/signal_trap.rb +24 -0
  60. data/gems/server/lib/itsi/server/version.rb +1 -1
  61. data/gems/server/lib/itsi/server.rb +68 -82
  62. data/gems/server/test/helpers/test_helper.rb +28 -0
  63. data/gems/server/test/test_itsi_server.rb +275 -3
  64. data/lib/itsi/version.rb +1 -1
  65. data/sandbox/deploy/main.tf +238 -0
  66. data/sandbox/deploy/outputs.tf +4 -0
  67. data/sandbox/deploy/vars.tf +11 -0
  68. data/sandbox/falcon_benchmark/Gemfile +10 -0
  69. data/sandbox/falcon_benchmark/Gemfile.lock +140 -0
  70. data/sandbox/falcon_benchmark/config.ru +54 -0
  71. data/sandbox/itsi_sandbox_async/Gemfile +10 -0
  72. data/sandbox/itsi_sandbox_async/Gemfile.lock +69 -0
  73. data/sandbox/itsi_sandbox_async/config.ru +10 -0
  74. data/sandbox/itsi_sandbox_hanami/.env +2 -0
  75. data/sandbox/itsi_sandbox_hanami/.gitignore +6 -0
  76. data/sandbox/itsi_sandbox_hanami/.rspec +1 -0
  77. data/sandbox/itsi_sandbox_hanami/Gemfile +49 -0
  78. data/sandbox/itsi_sandbox_hanami/Gemfile.lock +440 -0
  79. data/sandbox/itsi_sandbox_hanami/Guardfile +9 -0
  80. data/sandbox/itsi_sandbox_hanami/Procfile.dev +2 -0
  81. data/sandbox/itsi_sandbox_hanami/README.md +1 -0
  82. data/sandbox/itsi_sandbox_hanami/Rakefile +3 -0
  83. data/sandbox/itsi_sandbox_hanami/app/action.rb +12 -0
  84. data/sandbox/itsi_sandbox_hanami/app/actions/.keep +0 -0
  85. data/sandbox/itsi_sandbox_hanami/app/assets/css/app.css +5 -0
  86. data/sandbox/itsi_sandbox_hanami/app/assets/images/favicon.ico +0 -0
  87. data/sandbox/itsi_sandbox_hanami/app/assets/js/app.js +1 -0
  88. data/sandbox/itsi_sandbox_hanami/app/db/relation.rb +10 -0
  89. data/sandbox/itsi_sandbox_hanami/app/db/repo.rb +10 -0
  90. data/sandbox/itsi_sandbox_hanami/app/db/struct.rb +10 -0
  91. data/sandbox/itsi_sandbox_hanami/app/operation.rb +9 -0
  92. data/sandbox/itsi_sandbox_hanami/app/relations/.keep +0 -0
  93. data/sandbox/itsi_sandbox_hanami/app/repos/.keep +0 -0
  94. data/sandbox/itsi_sandbox_hanami/app/structs/.keep +0 -0
  95. data/sandbox/itsi_sandbox_hanami/app/templates/layouts/app.html.erb +14 -0
  96. data/sandbox/itsi_sandbox_hanami/app/view.rb +9 -0
  97. data/sandbox/itsi_sandbox_hanami/app/views/helpers.rb +10 -0
  98. data/sandbox/itsi_sandbox_hanami/bin/dev +8 -0
  99. data/sandbox/itsi_sandbox_hanami/config/app.rb +8 -0
  100. data/sandbox/itsi_sandbox_hanami/config/assets.js +16 -0
  101. data/sandbox/itsi_sandbox_hanami/config/db/migrate/.keep +0 -0
  102. data/sandbox/itsi_sandbox_hanami/config/db/seeds.rb +15 -0
  103. data/sandbox/itsi_sandbox_hanami/config/puma.rb +47 -0
  104. data/sandbox/itsi_sandbox_hanami/config/routes.rb +7 -0
  105. data/sandbox/itsi_sandbox_hanami/config/settings.rb +9 -0
  106. data/sandbox/itsi_sandbox_hanami/config.ru +5 -0
  107. data/sandbox/itsi_sandbox_hanami/db/.keep +0 -0
  108. data/sandbox/itsi_sandbox_hanami/lib/itsi_hanami/types.rb +11 -0
  109. data/sandbox/itsi_sandbox_hanami/lib/tasks/.keep +0 -0
  110. data/sandbox/itsi_sandbox_hanami/package-lock.json +946 -0
  111. data/sandbox/itsi_sandbox_hanami/package.json +8 -0
  112. data/sandbox/itsi_sandbox_hanami/spec/requests/root_spec.rb +11 -0
  113. data/sandbox/itsi_sandbox_hanami/spec/spec_helper.rb +9 -0
  114. data/sandbox/itsi_sandbox_hanami/spec/support/db/cleaning.rb +42 -0
  115. data/sandbox/itsi_sandbox_hanami/spec/support/db.rb +10 -0
  116. data/sandbox/itsi_sandbox_hanami/spec/support/features.rb +5 -0
  117. data/sandbox/itsi_sandbox_hanami/spec/support/operations.rb +8 -0
  118. data/sandbox/itsi_sandbox_hanami/spec/support/requests.rb +13 -0
  119. data/sandbox/itsi_sandbox_hanami/spec/support/rspec.rb +61 -0
  120. data/sandbox/itsi_sandbox_rack/Gemfile +17 -0
  121. data/sandbox/itsi_sandbox_rack/Gemfile.lock +153 -0
  122. data/sandbox/itsi_sandbox_rack/config.ru +18 -0
  123. data/sandbox/itsi_sandbox_rack_lint/Gemfile +7 -0
  124. data/sandbox/itsi_sandbox_rack_lint/Gemfile.lock +27 -0
  125. data/sandbox/itsi_sandbox_rack_lint/config.ru +3 -0
  126. data/sandbox/itsi_sandbox_rails/.dockerignore +51 -0
  127. data/sandbox/itsi_sandbox_rails/.gitattributes +9 -0
  128. data/sandbox/itsi_sandbox_rails/.github/dependabot.yml +12 -0
  129. data/sandbox/itsi_sandbox_rails/.github/workflows/ci.yml +90 -0
  130. data/sandbox/itsi_sandbox_rails/.gitignore +34 -0
  131. data/sandbox/itsi_sandbox_rails/.kamal/hooks/docker-setup.sample +3 -0
  132. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-app-boot.sample +3 -0
  133. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-deploy.sample +14 -0
  134. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-proxy-reboot.sample +3 -0
  135. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-app-boot.sample +3 -0
  136. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-build.sample +51 -0
  137. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-connect.sample +47 -0
  138. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-deploy.sample +109 -0
  139. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-proxy-reboot.sample +3 -0
  140. data/sandbox/itsi_sandbox_rails/.kamal/secrets +17 -0
  141. data/sandbox/itsi_sandbox_rails/.rubocop.yml +8 -0
  142. data/sandbox/itsi_sandbox_rails/.ruby-version +1 -0
  143. data/sandbox/itsi_sandbox_rails/Dockerfile +72 -0
  144. data/sandbox/itsi_sandbox_rails/Gemfile +72 -0
  145. data/sandbox/itsi_sandbox_rails/Gemfile.lock +480 -0
  146. data/sandbox/itsi_sandbox_rails/README.md +24 -0
  147. data/sandbox/itsi_sandbox_rails/Rakefile +6 -0
  148. data/sandbox/itsi_sandbox_rails/app/assets/images/.keep +0 -0
  149. data/sandbox/itsi_sandbox_rails/app/assets/stylesheets/application.css +10 -0
  150. data/sandbox/itsi_sandbox_rails/app/controllers/application_controller.rb +4 -0
  151. data/sandbox/itsi_sandbox_rails/app/controllers/concerns/.keep +0 -0
  152. data/sandbox/itsi_sandbox_rails/app/controllers/home_controller.rb +51 -0
  153. data/sandbox/itsi_sandbox_rails/app/controllers/live_controller.rb +41 -0
  154. data/sandbox/itsi_sandbox_rails/app/controllers/uploads_controller.rb +32 -0
  155. data/sandbox/itsi_sandbox_rails/app/helpers/application_helper.rb +2 -0
  156. data/sandbox/itsi_sandbox_rails/app/javascript/application.js +3 -0
  157. data/sandbox/itsi_sandbox_rails/app/javascript/controllers/application.js +9 -0
  158. data/sandbox/itsi_sandbox_rails/app/javascript/controllers/hello_controller.js +7 -0
  159. data/sandbox/itsi_sandbox_rails/app/javascript/controllers/index.js +4 -0
  160. data/sandbox/itsi_sandbox_rails/app/jobs/application_job.rb +7 -0
  161. data/sandbox/itsi_sandbox_rails/app/mailers/application_mailer.rb +4 -0
  162. data/sandbox/itsi_sandbox_rails/app/models/application_record.rb +3 -0
  163. data/sandbox/itsi_sandbox_rails/app/models/concerns/.keep +0 -0
  164. data/sandbox/itsi_sandbox_rails/app/models/post.rb +2 -0
  165. data/sandbox/itsi_sandbox_rails/app/views/layouts/application.html.erb +28 -0
  166. data/sandbox/itsi_sandbox_rails/app/views/layouts/mailer.html.erb +13 -0
  167. data/sandbox/itsi_sandbox_rails/app/views/layouts/mailer.text.erb +1 -0
  168. data/sandbox/itsi_sandbox_rails/app/views/pwa/manifest.json.erb +22 -0
  169. data/sandbox/itsi_sandbox_rails/app/views/pwa/service-worker.js +26 -0
  170. data/sandbox/itsi_sandbox_rails/bin/brakeman +7 -0
  171. data/sandbox/itsi_sandbox_rails/bin/bundle +109 -0
  172. data/sandbox/itsi_sandbox_rails/bin/dev +2 -0
  173. data/sandbox/itsi_sandbox_rails/bin/docker-entrypoint +14 -0
  174. data/sandbox/itsi_sandbox_rails/bin/importmap +4 -0
  175. data/sandbox/itsi_sandbox_rails/bin/jobs +6 -0
  176. data/sandbox/itsi_sandbox_rails/bin/kamal +27 -0
  177. data/sandbox/itsi_sandbox_rails/bin/rails +4 -0
  178. data/sandbox/itsi_sandbox_rails/bin/rake +4 -0
  179. data/sandbox/itsi_sandbox_rails/bin/rubocop +8 -0
  180. data/sandbox/itsi_sandbox_rails/bin/setup +34 -0
  181. data/sandbox/itsi_sandbox_rails/bin/thrust +5 -0
  182. data/sandbox/itsi_sandbox_rails/config/application.rb +61 -0
  183. data/sandbox/itsi_sandbox_rails/config/boot.rb +4 -0
  184. data/sandbox/itsi_sandbox_rails/config/cable.yml +17 -0
  185. data/sandbox/itsi_sandbox_rails/config/cache.yml +16 -0
  186. data/sandbox/itsi_sandbox_rails/config/credentials.yml.enc +1 -0
  187. data/sandbox/itsi_sandbox_rails/config/database.yml +40 -0
  188. data/sandbox/itsi_sandbox_rails/config/deploy.yml +116 -0
  189. data/sandbox/itsi_sandbox_rails/config/environment.rb +5 -0
  190. data/sandbox/itsi_sandbox_rails/config/environments/development.rb +72 -0
  191. data/sandbox/itsi_sandbox_rails/config/environments/production.rb +90 -0
  192. data/sandbox/itsi_sandbox_rails/config/environments/test.rb +53 -0
  193. data/sandbox/itsi_sandbox_rails/config/importmap.rb +7 -0
  194. data/sandbox/itsi_sandbox_rails/config/initializers/assets.rb +7 -0
  195. data/sandbox/itsi_sandbox_rails/config/initializers/content_security_policy.rb +25 -0
  196. data/sandbox/itsi_sandbox_rails/config/initializers/filter_parameter_logging.rb +8 -0
  197. data/sandbox/itsi_sandbox_rails/config/initializers/inflections.rb +16 -0
  198. data/sandbox/itsi_sandbox_rails/config/locales/en.yml +31 -0
  199. data/sandbox/itsi_sandbox_rails/config/puma.rb +41 -0
  200. data/sandbox/itsi_sandbox_rails/config/queue.yml +18 -0
  201. data/sandbox/itsi_sandbox_rails/config/recurring.yml +10 -0
  202. data/sandbox/itsi_sandbox_rails/config/routes.rb +21 -0
  203. data/sandbox/itsi_sandbox_rails/config/storage.yml +34 -0
  204. data/sandbox/itsi_sandbox_rails/config.ru +7 -0
  205. data/sandbox/itsi_sandbox_rails/db/cable_schema.rb +11 -0
  206. data/sandbox/itsi_sandbox_rails/db/cache_schema.rb +14 -0
  207. data/sandbox/itsi_sandbox_rails/db/migrate/20250301041554_create_posts.rb +10 -0
  208. data/sandbox/itsi_sandbox_rails/db/queue_schema.rb +129 -0
  209. data/sandbox/itsi_sandbox_rails/db/schema.rb +23 -0
  210. data/sandbox/itsi_sandbox_rails/db/seeds.rb +9 -0
  211. data/sandbox/itsi_sandbox_rails/lib/tasks/.keep +0 -0
  212. data/sandbox/itsi_sandbox_rails/log/.keep +0 -0
  213. data/sandbox/itsi_sandbox_rails/public/400.html +114 -0
  214. data/sandbox/itsi_sandbox_rails/public/404.html +114 -0
  215. data/sandbox/itsi_sandbox_rails/public/406-unsupported-browser.html +114 -0
  216. data/sandbox/itsi_sandbox_rails/public/422.html +114 -0
  217. data/sandbox/itsi_sandbox_rails/public/500.html +114 -0
  218. data/sandbox/itsi_sandbox_rails/public/icon.png +0 -0
  219. data/sandbox/itsi_sandbox_rails/public/icon.svg +3 -0
  220. data/sandbox/itsi_sandbox_rails/public/robots.txt +1 -0
  221. data/sandbox/itsi_sandbox_rails/script/.keep +0 -0
  222. data/sandbox/itsi_sandbox_rails/storage/.keep +0 -0
  223. data/sandbox/itsi_sandbox_rails/test/application_system_test_case.rb +5 -0
  224. data/sandbox/itsi_sandbox_rails/test/controllers/.keep +0 -0
  225. data/sandbox/itsi_sandbox_rails/test/fixtures/files/.keep +0 -0
  226. data/sandbox/itsi_sandbox_rails/test/fixtures/posts.yml +9 -0
  227. data/sandbox/itsi_sandbox_rails/test/helpers/.keep +0 -0
  228. data/sandbox/itsi_sandbox_rails/test/integration/.keep +0 -0
  229. data/sandbox/itsi_sandbox_rails/test/mailers/.keep +0 -0
  230. data/sandbox/itsi_sandbox_rails/test/models/.keep +0 -0
  231. data/sandbox/itsi_sandbox_rails/test/models/post_test.rb +7 -0
  232. data/sandbox/itsi_sandbox_rails/test/system/.keep +0 -0
  233. data/sandbox/itsi_sandbox_rails/test/test_helper.rb +15 -0
  234. data/sandbox/itsi_sandbox_rails/tmp/.keep +0 -0
  235. data/sandbox/itsi_sandbox_rails/tmp/pids/.keep +0 -0
  236. data/sandbox/itsi_sandbox_rails/tmp/storage/.keep +0 -0
  237. data/sandbox/itsi_sandbox_rails/vendor/.keep +0 -0
  238. data/sandbox/itsi_sandbox_rails/vendor/javascript/.keep +0 -0
  239. data/sandbox/itsi_sandbox_roda/Gemfile +5 -0
  240. data/sandbox/itsi_sandbox_roda/Gemfile.lock +44 -0
  241. data/sandbox/itsi_sandbox_roda/config.ru +39 -0
  242. data/sandbox/itsi_sinatra/Gemfile +9 -0
  243. data/sandbox/itsi_sinatra/Gemfile.lock +81 -0
  244. data/sandbox/itsi_sinatra/app.rb +9 -0
  245. data/sandbox/pebble/docker-compose.yml +11 -0
  246. data/tasks.txt +4 -4
  247. metadata +199 -10
  248. data/gems/server/lib/itsi/signals.rb +0 -23
  249. data/gems/server/test/test_helper.rb +0 -7
@@ -1,9 +1,281 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "test_helper"
1
+ require "socket"
2
+ require "net/http"
3
+ require "minitest/autorun"
4
4
 
5
5
  class TestItsiServer < Minitest::Test
6
6
  def test_that_it_has_a_version_number
7
7
  refute_nil ::Itsi::Server::VERSION
8
8
  end
9
+
10
+ def test_hello_world
11
+ run_app(lambda do |env|
12
+ [200, { "Content-Type" => "text/plain" }, ["Hello, World!"]]
13
+ end) do |uri|
14
+ assert_equal "Hello, World!", Net::HTTP.get(uri)
15
+ end
16
+ end
17
+
18
+ def test_post
19
+ run_app(lambda do |env|
20
+ assert_equal env["REQUEST_METHOD"], "POST"
21
+ assert_equal "data", env["rack.input"].read
22
+ [200, { "Content-Type" => "text/plain" }, ["Hello, World!"]]
23
+ end) do |uri|
24
+ assert_equal "Hello, World!", Net::HTTP.post(uri, "data").body
25
+ end
26
+ end
27
+
28
+ def test_full_hijack
29
+ run_app(lambda do |env|
30
+ io = env["rack.hijack"].call
31
+ io.write("HTTP/1.1 200 Ok\r\n")
32
+ io.write("Content-Type: text/plain\r\n")
33
+ io.write("Transfer-Encoding: chunked\r\n")
34
+ io.write("\r\n")
35
+ io.write("7\r\n")
36
+ io.write("Hello, \r\n")
37
+ io.write("6\r\n")
38
+ io.write("World!\r\n")
39
+ io.write("0\r\n\r\n")
40
+ io.close
41
+ end) do |uri|
42
+ assert_equal "Hello, World!", Net::HTTP.get(uri)
43
+ end
44
+ end
45
+
46
+ def test_streaming_body
47
+ run_app(lambda do |env|
48
+ [200, { "Content-Type" => "text/plain" }, lambda { |stream|
49
+ stream.write("Hello")
50
+ stream.write(", World!")
51
+ stream.close
52
+ }]
53
+ end) do |uri|
54
+ assert_equal "Hello, World!", Net::HTTP.get(uri)
55
+ end
56
+ end
57
+
58
+ def test_partial_hijack
59
+ run_app(lambda do |env|
60
+ [200, { "Content-Type" => "text/plain", "rack.hijack" => lambda { |stream|
61
+ stream.write("Hello")
62
+ stream.write(", World!")
63
+ stream.close
64
+ } }, []]
65
+ end) do |uri|
66
+ assert_equal "Hello, World!", Net::HTTP.get(uri)
67
+ end
68
+ end
69
+
70
+ def test_enumerable_body
71
+ run_app(lambda do |env|
72
+ [200, { "Content-Type" => "application/json" },
73
+ %W[one\n two\n three\n]]
74
+ end) do |uri|
75
+ assert_equal "one\ntwo\nthree\n", Net::HTTP.get(uri)
76
+ end
77
+ end
78
+
79
+ def test_scheduler_non_blocking
80
+ run_app(
81
+ lambda do |env|
82
+ sleep 0.25
83
+ [200, { "Content-Type" => "text/plain" }, "Hello, World!"]
84
+ end,
85
+ scheduler_class: "Itsi::Scheduler"
86
+ ) do |uri|
87
+ start_time = Time.now
88
+ 20.times.map do
89
+ Thread.new do
90
+ assert_equal "Hello, World!", Net::HTTP.get(uri)
91
+ end
92
+ end.each(&:join)
93
+ assert_in_delta 0.25, Time.now - start_time, 0.5
94
+ end
95
+ end
96
+
97
+ def test_query_params
98
+ run_app(lambda do |env|
99
+ [200, { "Content-Type" => "text/plain" }, [env["QUERY_STRING"]]]
100
+ end) do |uri|
101
+ uri.query = "foo=bar&baz=qux"
102
+ assert_equal "foo=bar&baz=qux", Net::HTTP.get(uri)
103
+ end
104
+ end
105
+
106
+ def test_put_request
107
+ run_app(lambda do |env|
108
+ body = env["rack.input"].read
109
+ [200, { "Content-Type" => "text/plain" }, [body]]
110
+ end) do |uri|
111
+ uri_obj = URI(uri)
112
+ req = Net::HTTP::Put.new(uri_obj)
113
+ req.body = "put data"
114
+ response = Net::HTTP.start(uri_obj.hostname, uri_obj.port) { |http| http.request(req) }
115
+ assert_equal "put data", response.body
116
+ end
117
+ end
118
+
119
+ def test_custom_headers
120
+ run_app(lambda do |env|
121
+ header = env["HTTP_X_CUSTOM"] || ""
122
+ [200, { "Content-Type" => "text/plain" }, [header]]
123
+ end) do |uri|
124
+ uri_obj = URI(uri)
125
+ req = Net::HTTP::Get.new(uri_obj)
126
+ req["X-Custom"] = "custom-value"
127
+ response = Net::HTTP.start(uri_obj.hostname, uri_obj.port) { |http| http.request(req) }
128
+ assert_equal "custom-value", response.body
129
+ end
130
+ end
131
+
132
+ def test_error_response
133
+ response = nil
134
+ capture_subprocess_io do
135
+ run_app(lambda do |env|
136
+ raise "Intentional error for testing"
137
+ end) do |uri|
138
+ response = Net::HTTP.get_response(uri)
139
+ end
140
+ end
141
+ assert_equal "500", response.code
142
+ end
143
+
144
+ def test_redirect
145
+ run_app(lambda do |env|
146
+ [302, { "Location" => "http://example.com" }, []]
147
+ end) do |uri|
148
+ response = Net::HTTP.get_response(uri)
149
+ assert_equal "302", response.code
150
+ assert_equal "http://example.com", response["location"]
151
+ end
152
+ end
153
+
154
+ def test_not_found
155
+ run_app(lambda do |env|
156
+ if env["PATH_INFO"] == "/"
157
+ [200, { "Content-Type" => "text/plain" }, ["Home"]]
158
+ else
159
+ [404, { "Content-Type" => "text/plain" }, ["Not Found"]]
160
+ end
161
+ end) do |uri|
162
+ uri.path = "/nonexistent"
163
+ response = Net::HTTP.get_response(uri)
164
+ assert_equal "404", response.code
165
+ assert_equal "Not Found", response.body
166
+ end
167
+ end
168
+
169
+ def test_head_request
170
+ run_app(lambda do |env|
171
+ [200, { "Content-Type" => "text/plain", "Content-Length" => "13" }, ["Hello, World!"]]
172
+ end) do |uri|
173
+ uri_obj = URI(uri)
174
+ response = Net::HTTP.start(uri_obj.hostname, uri_obj.port) do |http|
175
+ http.head("/")
176
+ end
177
+ assert_equal "200", response.code
178
+ assert_empty response.body.to_s
179
+ assert_equal "13", response["content-length"]
180
+ end
181
+ end
182
+
183
+ def test_options_request
184
+ run_app(lambda do |env|
185
+ [200, { "Allow" => "GET,POST,OPTIONS", "Content-Type" => "text/plain" }, ["Options Response"]]
186
+ end) do |uri|
187
+ uri_obj = URI(uri)
188
+ req = Net::HTTP::Options.new(uri_obj)
189
+ response = Net::HTTP.start(uri_obj.hostname, uri_obj.port) { |http| http.request(req) }
190
+ assert_equal "200", response.code
191
+ assert_equal "GET,POST,OPTIONS", response["allow"]
192
+ assert_equal "Options Response", response.body
193
+ end
194
+ end
195
+
196
+ def test_cookie_handling
197
+ run_app(lambda do |env|
198
+ [200, { "Content-Type" => "text/plain", "Set-Cookie" => "session=abc123; Path=/" }, ["Cookie Test"]]
199
+ end) do |uri|
200
+ response = Net::HTTP.get_response(uri)
201
+ assert_equal "200", response.code
202
+ assert_match(/session=abc123/, response["set-cookie"])
203
+ assert_equal "Cookie Test", response.body
204
+ end
205
+ end
206
+
207
+ def test_multiple_headers
208
+ run_app(lambda do |env|
209
+ [200, { "Content-Type" => "text/plain", "X-Example" => "one, two, three" }, ["Multiple Headers"]]
210
+ end) do |uri|
211
+ response = Net::HTTP.get_response(uri)
212
+ assert_equal "200", response.code
213
+ assert_equal "one, two, three", response["x-example"]
214
+ assert_equal "Multiple Headers", response.body
215
+ end
216
+ end
217
+
218
+ def test_large_body
219
+ large_text = "A" * 10_000
220
+ run_app(lambda do |env|
221
+ [200, { "Content-Type" => "text/plain", "Content-Length" => large_text.bytesize.to_s }, [large_text]]
222
+ end) do |uri|
223
+ response = Net::HTTP.get_response(uri)
224
+ assert_equal "200", response.code
225
+ assert_equal large_text, response.body
226
+ end
227
+ end
228
+
229
+ def test_custom_status_code
230
+ run_app(lambda do |env|
231
+ [201, { "Content-Type" => "text/plain" }, ["Created"]]
232
+ end) do |uri|
233
+ response = Net::HTTP.get_response(uri)
234
+ assert_equal "201", response.code
235
+ assert_equal "Created", response.body
236
+ end
237
+ end
238
+
239
+ def test_empty_body
240
+ run_app(lambda do |env|
241
+ [204, { "Content-Type" => "text/plain" }, []]
242
+ end) do |uri|
243
+ response = Net::HTTP.get_response(uri)
244
+ assert_equal "204", response.code
245
+ assert_nil response.body
246
+ end
247
+ end
248
+
249
+ def test_utf8_response
250
+ utf8_text = "こんにちは世界"
251
+ run_app(lambda do |env|
252
+ [200, { "Content-Type" => "text/plain; charset=utf-8" }, [utf8_text]]
253
+ end) do |uri|
254
+ response = Net::HTTP.get_response(uri)
255
+ assert_equal "200", response.code
256
+ assert_equal utf8_text, response.body.force_encoding("UTF-8")
257
+ end
258
+ end
259
+
260
+ def test_custom_request_header
261
+ run_app(lambda do |env|
262
+ header_value = env["HTTP_X_MY_HEADER"] || ""
263
+ [200, { "Content-Type" => "text/plain" }, [header_value]]
264
+ end) do |uri|
265
+ uri_obj = URI(uri)
266
+ req = Net::HTTP::Get.new(uri_obj)
267
+ req["X-My-Header"] = "test-header"
268
+ response = Net::HTTP.start(uri_obj.hostname, uri_obj.port) { |http| http.request(req) }
269
+ assert_equal "test-header", response.body
270
+ end
271
+ end
272
+
273
+ def test_url_encoded_query_params
274
+ run_app(lambda do |env|
275
+ [200, { "Content-Type" => "text/plain" }, [env["QUERY_STRING"]]]
276
+ end) do |uri|
277
+ uri.query = "param=%C3%A9" # %C3%A9 represents 'é'
278
+ assert_equal "param=%C3%A9", Net::HTTP.get(uri)
279
+ end
280
+ end
9
281
  end
data/lib/itsi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Itsi
2
- VERSION = "0.1.7"
2
+ VERSION = '0.1.9'
3
3
  end
@@ -0,0 +1,238 @@
1
+ terraform {
2
+ required_providers {
3
+ aws = {
4
+ source = "hashicorp/aws"
5
+ version = "~> 5.0"
6
+ }
7
+ cloudflare = {
8
+ source = "cloudflare/cloudflare"
9
+ version = "~> 5.0.0"
10
+ }
11
+ }
12
+
13
+ required_version = ">= 0.14.9"
14
+ }
15
+
16
+ provider "aws" {
17
+ region = var.aws_region
18
+ }
19
+
20
+
21
+ data "aws_region" "current" {
22
+ name = var.aws_region
23
+ }
24
+
25
+ data "aws_ami" "ubuntu" {
26
+ most_recent = true
27
+
28
+ filter {
29
+ name = "name"
30
+ values = ["ubuntu/images/hvm-ssd-gp3/*ubuntu-noble-24.04-arm64-server-*"]
31
+ }
32
+
33
+ filter {
34
+ name = "virtualization-type"
35
+ values = ["hvm"]
36
+ }
37
+
38
+ owners = ["099720109477"] # Canonical
39
+ }
40
+
41
+ # Create VPC
42
+ # terraform aws create vpc
43
+ resource "aws_vpc" "vpc" {
44
+ cidr_block = "10.0.0.0/16"
45
+ instance_tenancy = "default"
46
+ enable_dns_hostnames = true
47
+ tags = {
48
+ Name = "${var.environment}-vpc"
49
+ }
50
+ }
51
+ resource "aws_subnet" "public_subnet_a" {
52
+ vpc_id = aws_vpc.vpc.id
53
+ cidr_block = "10.0.1.0/24"
54
+ availability_zone = var.subnet_az
55
+ map_public_ip_on_launch = true
56
+
57
+ tags = {
58
+ Name = "${var.environment} Public Subnet A"
59
+ }
60
+ }
61
+
62
+ resource "aws_subnet" "private_subnet_a" {
63
+ vpc_id = aws_vpc.vpc.id
64
+ cidr_block = "10.0.2.0/24"
65
+ availability_zone = var.subnet_az
66
+
67
+ tags = {
68
+ Name = "${var.environment} Private Subnet A"
69
+ }
70
+ }
71
+
72
+ resource "aws_internet_gateway" "ig_a" {
73
+ vpc_id = aws_vpc.vpc.id
74
+
75
+ tags = {
76
+ Name = "${var.environment} Internet Gateway A"
77
+ }
78
+ }
79
+
80
+ resource "aws_route_table" "public_rt" {
81
+ vpc_id = aws_vpc.vpc.id
82
+
83
+ route {
84
+ cidr_block = "0.0.0.0/0"
85
+ gateway_id = aws_internet_gateway.ig_a.id
86
+ }
87
+
88
+ route {
89
+ ipv6_cidr_block = "::/0"
90
+ gateway_id = aws_internet_gateway.ig_a.id
91
+ }
92
+
93
+ tags = {
94
+ Name = "${var.environment} Public Route Table"
95
+ }
96
+ }
97
+
98
+ resource "aws_route_table_association" "public_1_rt_a" {
99
+ subnet_id = aws_subnet.public_subnet_a.id
100
+ route_table_id = aws_route_table.public_rt.id
101
+ }
102
+
103
+ resource "aws_security_group" "web_sg" {
104
+ name = "HTTP and SSH"
105
+ vpc_id = aws_vpc.vpc.id
106
+
107
+ ingress {
108
+ from_port = 443
109
+ to_port = 443
110
+ protocol = "tcp"
111
+ cidr_blocks = ["0.0.0.0/0"]
112
+ }
113
+
114
+
115
+ ingress {
116
+ from_port = 80
117
+ to_port = 80
118
+ protocol = "tcp"
119
+ cidr_blocks = ["0.0.0.0/0"]
120
+ }
121
+
122
+ ingress {
123
+ from_port = 22
124
+ to_port = 22
125
+ protocol = "tcp"
126
+ cidr_blocks = ["0.0.0.0/0"]
127
+ }
128
+
129
+ egress {
130
+ from_port = 0
131
+ to_port = 0
132
+ protocol = -1
133
+ cidr_blocks = ["0.0.0.0/0"]
134
+ }
135
+
136
+ tags = {
137
+ Name = "${var.environment} Web Security Group"
138
+ }
139
+ }
140
+
141
+
142
+ resource "aws_instance" "web" {
143
+ ami = data.aws_ami.ubuntu.id
144
+ instance_type = "t4g.micro"
145
+ key_name = "key-pair-aws-admin"
146
+ iam_instance_profile = aws_iam_instance_profile.web.name
147
+
148
+ tags = {
149
+ Name = "web-${var.environment}"
150
+ }
151
+
152
+ subnet_id = aws_subnet.public_subnet_a.id
153
+ security_groups = [aws_security_group.web_sg.id]
154
+ associate_public_ip_address = true
155
+
156
+ user_data = <<EOF
157
+ #!/bin/bash
158
+ apt-get update
159
+ apt-get install zlib1g-dev libyaml-dev libssl-dev libffi-dev libgmp3-dev libclang-dev build-essential -y && \
160
+ apt-get clean && rm -rf /var/lib/apt/lists/* && apt-get autoremove -y
161
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
162
+ curl https://mise.run | sh
163
+ export HOME=/root
164
+ echo "eval \"\$(/root/.local/bin/mise activate bash)\"" >> ~/.bashrc
165
+ eval "$(/root/.local/bin/mise activate bash)"
166
+ mise use ruby@3.4.2
167
+ gem install itsi
168
+ EOF
169
+
170
+ root_block_device {
171
+ encrypted = true
172
+ volume_type = "gp3"
173
+ volume_size = 12
174
+ tags = {
175
+ Name = "web-root-block-device-${var.environment}"
176
+ }
177
+ }
178
+
179
+ depends_on = [aws_route_table_association.public_1_rt_a]
180
+ }
181
+
182
+ locals {
183
+ role_policy_arns = [
184
+ "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM",
185
+ "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
186
+ ]
187
+ }
188
+
189
+ resource "aws_iam_instance_profile" "web" {
190
+ name = "EC2-Profile-${var.environment}"
191
+ role = aws_iam_role.web.name
192
+ }
193
+
194
+ resource "aws_iam_role_policy_attachment" "web" {
195
+ count = length(local.role_policy_arns)
196
+
197
+ role = aws_iam_role.web.name
198
+ policy_arn = element(local.role_policy_arns, count.index)
199
+ }
200
+
201
+ resource "aws_iam_role_policy" "web" {
202
+ name = "EC2-Inline-Policy-${var.environment}"
203
+ role = aws_iam_role.web.id
204
+ policy = jsonencode(
205
+ {
206
+ "Version" : "2012-10-17",
207
+ "Statement" : [
208
+ {
209
+ "Effect" : "Allow",
210
+ "Action" : [
211
+ "ssm:GetParameter"
212
+ ],
213
+ "Resource" : "*"
214
+ }
215
+ ]
216
+ }
217
+ )
218
+ }
219
+
220
+ resource "aws_iam_role" "web" {
221
+ name = "EC2-Role-${var.environment}"
222
+ path = "/"
223
+
224
+ assume_role_policy = jsonencode(
225
+ {
226
+ "Version" : "2012-10-17",
227
+ "Statement" : [
228
+ {
229
+ "Action" : "sts:AssumeRole",
230
+ "Principal" : {
231
+ "Service" : "ec2.amazonaws.com"
232
+ },
233
+ "Effect" : "Allow"
234
+ }
235
+ ]
236
+ }
237
+ )
238
+ }
@@ -0,0 +1,4 @@
1
+ output "ec2_public_ip" {
2
+ description = "Public IP of the EC2 instance"
3
+ value = aws_instance.web.public_ip
4
+ }
@@ -0,0 +1,11 @@
1
+ variable "aws_region" {
2
+ default = "ap-southeast-2"
3
+ }
4
+
5
+ variable "environment" {
6
+ default = "itsi-production"
7
+ }
8
+
9
+ variable "subnet_az" {
10
+ default = "ap-southeast-2a"
11
+ }
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'iodine'
4
+ gem 'unicorn'
5
+ gem 'puma'
6
+ gem 'passenger'
7
+ gem 'agoo'
8
+ gem 'falcon'
9
+ gem "itsi-server", path: "../../gems/server"
10
+ gem "itsi-scheduler", path: "../../gems/scheduler"
@@ -0,0 +1,140 @@
1
+ PATH
2
+ remote: ../../gems/scheduler
3
+ specs:
4
+ itsi-scheduler (0.1.0)
5
+ libclang (~> 14.0)
6
+ rb_sys (~> 0.9.91)
7
+
8
+ PATH
9
+ remote: ../../gems/server
10
+ specs:
11
+ itsi-server (0.1.1)
12
+ libclang (~> 14.0)
13
+ rack (~> 2.2)
14
+ rb_sys (~> 0.9.91)
15
+
16
+ GEM
17
+ remote: https://rubygems.org/
18
+ specs:
19
+ agoo (2.15.13)
20
+ async (2.23.1)
21
+ console (~> 1.29)
22
+ fiber-annotation
23
+ io-event (~> 1.9)
24
+ metrics (~> 0.12)
25
+ traces (~> 0.15)
26
+ async-container (0.24.0)
27
+ async (~> 2.22)
28
+ async-container-supervisor (0.5.1)
29
+ async-container (~> 0.22)
30
+ async-service
31
+ io-endpoint
32
+ memory-leak (~> 0.5)
33
+ async-http (0.87.0)
34
+ async (>= 2.10.2)
35
+ async-pool (~> 0.9)
36
+ io-endpoint (~> 0.14)
37
+ io-stream (~> 0.6)
38
+ metrics (~> 0.12)
39
+ protocol-http (~> 0.49)
40
+ protocol-http1 (~> 0.30)
41
+ protocol-http2 (~> 0.22)
42
+ traces (~> 0.10)
43
+ async-http-cache (0.4.5)
44
+ async-http (~> 0.56)
45
+ async-pool (0.10.3)
46
+ async (>= 1.25)
47
+ async-service (0.13.0)
48
+ async
49
+ async-container (~> 0.16)
50
+ console (1.30.2)
51
+ fiber-annotation
52
+ fiber-local (~> 1.1)
53
+ json
54
+ falcon (0.51.1)
55
+ async
56
+ async-container (~> 0.20)
57
+ async-container-supervisor (~> 0.5.0)
58
+ async-http (~> 0.75)
59
+ async-http-cache (~> 0.4)
60
+ async-service (~> 0.10)
61
+ bundler
62
+ localhost (~> 1.1)
63
+ openssl (~> 3.0)
64
+ protocol-http (~> 0.31)
65
+ protocol-rack (~> 0.7)
66
+ samovar (~> 2.3)
67
+ fiber-annotation (0.2.0)
68
+ fiber-local (1.1.0)
69
+ fiber-storage
70
+ fiber-storage (1.0.0)
71
+ io-endpoint (0.15.2)
72
+ io-event (1.10.0)
73
+ io-stream (0.6.1)
74
+ iodine (0.7.58)
75
+ json (2.10.2)
76
+ kgio (2.11.4)
77
+ libclang (14.0.6-aarch64-linux)
78
+ libclang (14.0.6-arm64-darwin)
79
+ libclang (14.0.6-x86_64-darwin)
80
+ libclang (14.0.6-x86_64-linux)
81
+ libclang (14.0.6-x86_64-linux-musl)
82
+ localhost (1.3.1)
83
+ mapping (1.1.1)
84
+ memory-leak (0.5.2)
85
+ metrics (0.12.2)
86
+ nio4r (2.7.4)
87
+ openssl (3.3.0)
88
+ passenger (6.0.23)
89
+ rack (>= 1.6.13)
90
+ rackup
91
+ rake (>= 12.3.3)
92
+ protocol-hpack (1.5.1)
93
+ protocol-http (0.49.0)
94
+ protocol-http1 (0.30.0)
95
+ protocol-http (~> 0.22)
96
+ protocol-http2 (0.22.1)
97
+ protocol-hpack (~> 1.4)
98
+ protocol-http (~> 0.47)
99
+ protocol-rack (0.11.2)
100
+ protocol-http (~> 0.43)
101
+ rack (>= 1.0)
102
+ puma (6.6.0)
103
+ nio4r (~> 2.0)
104
+ rack (2.2.13)
105
+ rackup (1.0.1)
106
+ rack (< 3)
107
+ webrick
108
+ raindrops (0.20.1)
109
+ rake (13.2.1)
110
+ rake-compiler-dock (1.9.1)
111
+ rb_sys (0.9.111)
112
+ rake-compiler-dock (= 1.9.1)
113
+ samovar (2.3.0)
114
+ console (~> 1.0)
115
+ mapping (~> 1.0)
116
+ traces (0.15.2)
117
+ unicorn (6.1.0)
118
+ kgio (~> 2.6)
119
+ raindrops (~> 0.7)
120
+ webrick (1.9.1)
121
+
122
+ PLATFORMS
123
+ aarch64-linux
124
+ arm64-darwin
125
+ x86_64-darwin
126
+ x86_64-linux
127
+ x86_64-linux-musl
128
+
129
+ DEPENDENCIES
130
+ agoo
131
+ falcon
132
+ iodine
133
+ itsi-scheduler!
134
+ itsi-server!
135
+ passenger
136
+ puma
137
+ unicorn
138
+
139
+ BUNDLED WITH
140
+ 2.6.3