syntropy 0.29.0 → 0.31.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -2
  3. data/CHANGELOG.md +22 -0
  4. data/README.md +0 -2
  5. data/bin/syntropy +8 -86
  6. data/cmd/_banner.rb +16 -0
  7. data/cmd/help.rb +12 -0
  8. data/cmd/serve.rb +95 -0
  9. data/cmd/test.rb +40 -0
  10. data/examples/{counter.rb → basic/counter.rb} +1 -1
  11. data/examples/{templates.rb → basic/templates.rb} +1 -1
  12. data/examples/mcp-oauth/.ruby-version +1 -0
  13. data/examples/mcp-oauth/Gemfile +8 -0
  14. data/examples/mcp-oauth/README.md +128 -0
  15. data/examples/mcp-oauth/app/.well-known/oauth-authorization-server.rb +18 -0
  16. data/examples/mcp-oauth/app/.well-known/oauth-protected-resource.rb +10 -0
  17. data/examples/mcp-oauth/app/_lib/auth_store.rb +23 -0
  18. data/examples/mcp-oauth/app/index.md +1 -0
  19. data/examples/mcp-oauth/app/mcp.rb +38 -0
  20. data/examples/mcp-oauth/app/oauth/authorize.rb +26 -0
  21. data/examples/mcp-oauth/app/oauth/consent.rb +86 -0
  22. data/examples/mcp-oauth/app/oauth/register.rb +15 -0
  23. data/examples/mcp-oauth/app/oauth/token.rb +79 -0
  24. data/examples/mcp-oauth/app/signin.rb +85 -0
  25. data/examples/mcp-oauth/test/helper.rb +9 -0
  26. data/examples/mcp-oauth/test/test_app.rb +27 -0
  27. data/examples/mcp-oauth/test/test_oauth.rb +628 -0
  28. data/lib/syntropy/app.rb +23 -12
  29. data/lib/syntropy/applets/builtin/default_error_handler.rb +3 -3
  30. data/lib/syntropy/applets/builtin/req.rb +1 -1
  31. data/lib/syntropy/dev_mode.rb +1 -1
  32. data/lib/syntropy/errors.rb +19 -12
  33. data/lib/syntropy/http/client.rb +43 -0
  34. data/lib/syntropy/http/client_connection.rb +36 -0
  35. data/lib/syntropy/http/io_extensions.rb +148 -0
  36. data/lib/syntropy/http/server.rb +174 -0
  37. data/lib/syntropy/http/server_connection.rb +367 -0
  38. data/lib/syntropy/http/status.rb +76 -0
  39. data/lib/syntropy/http.rb +7 -0
  40. data/lib/syntropy/json_api.rb +2 -5
  41. data/lib/syntropy/logger.rb +5 -1
  42. data/lib/syntropy/mime_types.rb +37 -0
  43. data/lib/syntropy/papercraft_extensions.rb +1 -1
  44. data/lib/syntropy/request/mock_adapter.rb +60 -0
  45. data/lib/syntropy/request/request_info.rb +255 -0
  46. data/lib/syntropy/request/response.rb +206 -0
  47. data/lib/syntropy/request/validation.rb +146 -0
  48. data/lib/syntropy/request.rb +99 -0
  49. data/lib/syntropy/routing_tree.rb +2 -1
  50. data/lib/syntropy/test.rb +65 -0
  51. data/lib/syntropy/utils.rb +1 -1
  52. data/lib/syntropy/version.rb +1 -1
  53. data/lib/syntropy.rb +4 -27
  54. data/syntropy.gemspec +2 -4
  55. data/test/app/.well-known/foo.rb +3 -0
  56. data/test/app/about/_error.rb +1 -1
  57. data/test/app/api+.rb +1 -1
  58. data/test/app_custom/_site.rb +1 -1
  59. data/test/bm_router_proc.rb +3 -3
  60. data/test/helper.rb +4 -27
  61. data/test/test_app.rb +83 -98
  62. data/test/test_caching.rb +2 -2
  63. data/test/test_errors.rb +6 -6
  64. data/test/test_http_client.rb +52 -0
  65. data/test/test_http_client_connection.rb +43 -0
  66. data/test/{test_connection.rb → test_http_server_connection.rb} +32 -32
  67. data/test/test_json_api.rb +14 -12
  68. data/test/test_mock_adapter.rb +59 -0
  69. data/test/{test_request_extensions.rb → test_request.rb} +150 -18
  70. data/test/test_response.rb +112 -0
  71. data/test/test_routing_tree.rb +15 -3
  72. data/test/test_server.rb +1 -1
  73. metadata +57 -35
  74. data/lib/syntropy/connection.rb +0 -402
  75. data/lib/syntropy/request_extensions.rb +0 -308
  76. data/lib/syntropy/server.rb +0 -173
  77. /data/examples/{bad.rb → basic/bad.rb} +0 -0
  78. /data/examples/{card.rb → basic/card.rb} +0 -0
  79. /data/examples/{counter.js → basic/counter.js} +0 -0
  80. /data/examples/{counter_api.rb → basic/counter_api.rb} +0 -0
  81. /data/examples/{favicon.ico → basic/favicon.ico} +0 -0
  82. /data/examples/{index.md → basic/index.md} +0 -0
data/test/test_errors.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require_relative 'helper'
4
4
 
5
5
  class ErrorsTest < Minitest::Test
6
- ISE = Qeweney::Status::INTERNAL_SERVER_ERROR
6
+ ISE = Syntropy::HTTP::INTERNAL_SERVER_ERROR
7
7
 
8
8
  def test_error_http_status_class_method
9
9
  e = RuntimeError.new
@@ -12,27 +12,27 @@ class ErrorsTest < Minitest::Test
12
12
  e = Syntropy::Error.new
13
13
  assert_equal ISE, Syntropy::Error.http_status(e)
14
14
 
15
- e = Syntropy::Error.new("", Qeweney::Status::UNAUTHORIZED)
16
- assert_equal Qeweney::Status::UNAUTHORIZED, Syntropy::Error.http_status(e)
15
+ e = Syntropy::Error.new("", Syntropy::HTTP::UNAUTHORIZED)
16
+ assert_equal Syntropy::HTTP::UNAUTHORIZED, Syntropy::Error.http_status(e)
17
17
  end
18
18
 
19
19
  def test_method_not_allowed_error
20
20
  e = Syntropy::Error.method_not_allowed('foo')
21
21
  assert_kind_of Syntropy::Error, e
22
- assert_equal Qeweney::Status::METHOD_NOT_ALLOWED, e.http_status
22
+ assert_equal Syntropy::HTTP::METHOD_NOT_ALLOWED, e.http_status
23
23
  assert_equal 'foo', e.message
24
24
  end
25
25
 
26
26
  def test_not_found_error
27
27
  e = Syntropy::Error.not_found('bar')
28
28
  assert_kind_of Syntropy::Error, e
29
- assert_equal Qeweney::Status::NOT_FOUND, e.http_status
29
+ assert_equal Syntropy::HTTP::NOT_FOUND, e.http_status
30
30
  assert_equal 'bar', e.message
31
31
  end
32
32
 
33
33
  def test_validation_error
34
34
  e = Syntropy::ValidationError.new('baz')
35
- assert_equal Qeweney::Status::BAD_REQUEST, e.http_status
35
+ assert_equal Syntropy::HTTP::BAD_REQUEST, e.http_status
36
36
  assert_equal 'baz', e.message
37
37
  end
38
38
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './helper'
4
+ require 'json'
5
+
6
+ class HTTPClientTest < Minitest::Test
7
+ def setup
8
+ @machine = UM.new
9
+ @handler = ->(req) { req.respond_json(req.headers) }
10
+
11
+ @port = 10000 + rand(30000)
12
+ @env = { bind: "127.0.0.1:#{@port}" }
13
+ @server = Syntropy::HTTP::Server.new(@machine, @env) { @app&.call(it) }
14
+ @server_fiber = @machine.spin { @server.run }
15
+
16
+ # let server spin and listen to incoming connections
17
+ @machine.sleep(0.01)
18
+
19
+ @client = Syntropy::HTTP::Client.new(@machine)
20
+ end
21
+
22
+ def teardown
23
+ @machine.schedule(@server_fiber, UM::Terminate.new)
24
+ @machine.join(@server_fiber)
25
+ end
26
+
27
+ def test_get
28
+ @app = ->(req) { req.respond('foo') }
29
+ headers, body = @client.get("http://localhost:#{@port}")
30
+
31
+ assert_kind_of Hash, headers
32
+ assert_equal Syntropy::HTTP::OK, headers[':status']
33
+
34
+ assert_kind_of String, body
35
+ assert_equal 'foo', body
36
+ end
37
+
38
+ def test_get_with_block
39
+ @app = ->(req) { req.respond('foo') }
40
+ headers = body = nil
41
+ @client.get("http://localhost:#{@port}") { |h, c|
42
+ headers = h
43
+ body = c.get_response_body(headers)
44
+ }
45
+
46
+ assert_kind_of Hash, headers
47
+ assert_equal Syntropy::HTTP::OK, headers[':status']
48
+
49
+ assert_kind_of String, body
50
+ assert_equal 'foo', body
51
+ end
52
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './helper'
4
+ require 'json'
5
+
6
+ class HTTPClientConectionTest < Minitest::Test
7
+ def setup
8
+ @client_fd, @server_fd = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
9
+ @machine = UM.new
10
+ @handler = ->(req) { req.respond_json(req.headers) }
11
+ @server_connection = Syntropy::HTTP::ServerConnection.new(
12
+ @machine, @server_fd, {}, &->(req) { @handler.(req) }
13
+ )
14
+ @server_fiber = @machine.spin { @server_connection.run }
15
+ @client_connection = Syntropy::HTTP::ClientConnection.new(
16
+ @machine, @client_fd
17
+ )
18
+ end
19
+
20
+ def teardown
21
+ @machine.schedule(@server_fiber, UM::Terminate.new)
22
+ @machine.join(@server_fiber)
23
+ end
24
+
25
+ def test_req_teapot
26
+ @handler = ->(req) { req.respond(nil, ':status' => Syntropy::HTTP::TEAPOT) }
27
+ headers = @client_connection.req(':method' => 'GET', ':path' => '/')
28
+
29
+ assert_kind_of Hash, headers
30
+ assert_equal Syntropy::HTTP::TEAPOT, headers[':status']
31
+ end
32
+
33
+ def test_req_with_response_body
34
+ @handler = ->(req) { req.respond('foo') }
35
+ headers = @client_connection.req(':method' => 'GET', ':path' => '/')
36
+
37
+ assert_kind_of Hash, headers
38
+ assert_equal Syntropy::HTTP::OK, headers[':status']
39
+
40
+ body = @client_connection.get_response_body(headers)
41
+ assert_equal 'foo', body
42
+ end
43
+ end
@@ -3,7 +3,7 @@
3
3
  require_relative './helper'
4
4
  require 'securerandom'
5
5
 
6
- class ConnectionTest < Minitest::Test
6
+ class HTTPServerConnectionTest < Minitest::Test
7
7
  def make_socket_pair
8
8
  port = SecureRandom.random_number(10000..40000)
9
9
  server_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
@@ -29,7 +29,7 @@ class ConnectionTest < Minitest::Test
29
29
  @hook = nil
30
30
  @app = ->(req) { @reqs << req; @hook&.call(req) }
31
31
  @env = {}
32
- @adapter = Syntropy::Connection.new(nil, @machine, @s_fd, @env, &@app)
32
+ @connection = Syntropy::HTTP::ServerConnection.new(@machine, @s_fd, @env, &@app)
33
33
  end
34
34
 
35
35
  def teardown
@@ -54,14 +54,14 @@ class ConnectionTest < Minitest::Test
54
54
 
55
55
  def test_http_unsupported_versions
56
56
  write_http_request "GET / HTTP/0.9\r\n\r\n"
57
- @adapter.serve_request
57
+ @connection.serve_request
58
58
  response = read_client_side
59
59
  assert_equal "HTTP/1.1 505\r\nTransfer-Encoding: chunked\r\n\r\n1a\r\nHTTP version not supported\r\n0\r\n\r\n", response
60
60
 
61
61
  setup
62
62
 
63
63
  write_http_request "GET / HTTP/1.0\r\n\r\n"
64
- @adapter.serve_request
64
+ @connection.serve_request
65
65
  response = read_client_side
66
66
  assert_equal "HTTP/1.1 505\r\nTransfer-Encoding: chunked\r\n\r\n1a\r\nHTTP version not supported\r\n0\r\n\r\n", response
67
67
 
@@ -69,7 +69,7 @@ class ConnectionTest < Minitest::Test
69
69
 
70
70
  @hook = ->(req) { req.respond('hi') }
71
71
  write_http_request "GET / HTTP/1.1\r\n\r\n"
72
- @adapter.serve_request
72
+ @connection.serve_request
73
73
  @machine.close(@s_fd)
74
74
  response = read_client_side
75
75
  assert_equal "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n2\r\nhi\r\n0\r\n\r\n", response
@@ -78,7 +78,7 @@ class ConnectionTest < Minitest::Test
78
78
  def test_basic_request_parsing
79
79
  write_http_request "GET / HTTP/1.1\r\n\r\n"
80
80
 
81
- @adapter.serve_request
81
+ @connection.serve_request
82
82
  assert_equal 1, @reqs.size
83
83
  req = @reqs.shift
84
84
  headers = req.headers
@@ -101,7 +101,7 @@ class ConnectionTest < Minitest::Test
101
101
  HTTP
102
102
  write_http_request msg
103
103
 
104
- @adapter.run
104
+ @connection.run
105
105
  assert_equal 2, @reqs.size
106
106
  req0 = @reqs.shift
107
107
  headers = req0.headers
@@ -137,7 +137,7 @@ class ConnectionTest < Minitest::Test
137
137
  @bodies = []
138
138
  @hook = ->(req) { @bodies << req.read }
139
139
 
140
- @adapter.run
140
+ @connection.run
141
141
  assert_equal 2, @reqs.size
142
142
 
143
143
  req0 = @reqs.shift
@@ -195,7 +195,7 @@ class ConnectionTest < Minitest::Test
195
195
  @bodies = []
196
196
  @hook = ->(req) { @bodies << req.read }
197
197
 
198
- @adapter.run
198
+ @connection.run
199
199
  assert_equal 2, @reqs.size
200
200
 
201
201
  req0 = @reqs.shift
@@ -247,7 +247,7 @@ class ConnectionTest < Minitest::Test
247
247
  chunks = []
248
248
  @hook = ->(req) { req.each_chunk { chunks << it } }
249
249
 
250
- @adapter.serve_request
250
+ @connection.serve_request
251
251
  assert_equal 1, @reqs.size
252
252
 
253
253
  req0 = @reqs.shift
@@ -263,7 +263,7 @@ class ConnectionTest < Minitest::Test
263
263
  assert_equal ['abc', 'de'], chunks
264
264
 
265
265
  chunks.clear
266
- @adapter.serve_request
266
+ @connection.serve_request
267
267
  assert_equal 1, @reqs.size
268
268
 
269
269
  req1 = @reqs.shift
@@ -285,7 +285,7 @@ class ConnectionTest < Minitest::Test
285
285
  }
286
286
 
287
287
  write_http_request "GET / HTTP/1.1\r\n\r\n"
288
- @adapter.run
288
+ @connection.run
289
289
  response = read_client_side
290
290
 
291
291
  expected = <<~HTTP.crlf_lines
@@ -305,7 +305,7 @@ class ConnectionTest < Minitest::Test
305
305
 
306
306
  # using HTTP 1.0, server should close connection after responding
307
307
  write_http_request "GET / HTTP/1.1\r\n\r\n"
308
- @adapter.run
308
+ @connection.run
309
309
 
310
310
  response = read_client_side
311
311
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\nd\r\nHello, world!\r\n0\r\n\r\n"
@@ -318,14 +318,14 @@ class ConnectionTest < Minitest::Test
318
318
  }
319
319
 
320
320
  write_http_request "GET / HTTP/1.1\r\nConnection: close\r\n\r\n", false
321
- res = @adapter.serve_request
321
+ res = @connection.serve_request
322
322
  assert_equal false, res
323
323
 
324
324
  response = read_client_side
325
325
  assert_equal("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n2\r\nHi\r\n0\r\n\r\n", response)
326
326
 
327
327
  write_http_request "GET / HTTP/1.1\r\n\r\n", false
328
- res = @adapter.serve_request
328
+ res = @connection.serve_request
329
329
  assert_equal true, res
330
330
 
331
331
  response = read_client_side
@@ -344,7 +344,7 @@ class ConnectionTest < Minitest::Test
344
344
  }
345
345
 
346
346
  write_http_request "GET / HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\nFoo: bar\r\n\r\n"
347
- @adapter.run
347
+ @connection.run
348
348
  response = read_client_side
349
349
 
350
350
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\nd\r\nHello, world!\r\n0\r\n\r\n" +
@@ -368,7 +368,7 @@ class ConnectionTest < Minitest::Test
368
368
 
369
369
  msg = "POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nfoobar\r\n"
370
370
  write_http_request msg, false
371
- @machine.spin { @adapter.serve_request rescue nil }
371
+ @machine.spin { @connection.serve_request rescue nil }
372
372
  @machine.sleep(0.01)
373
373
 
374
374
  assert request
@@ -417,7 +417,7 @@ class ConnectionTest < Minitest::Test
417
417
 
418
418
  msg = "GET / HTTP/1.1\r\nUpgrade: echo\r\nConnection: upgrade\r\n\r\n"
419
419
  write_http_request(msg, false)
420
- @machine.spin { @adapter.serve_request rescue nil }
420
+ @machine.spin { @connection.serve_request rescue nil }
421
421
  @machine.sleep(0.01)
422
422
 
423
423
  response = read_client_side
@@ -462,7 +462,7 @@ class ConnectionTest < Minitest::Test
462
462
 
463
463
  write_client_side("GET / HTTP/1.1\r\n\r\n")
464
464
  @machine.spin do
465
- @adapter.serve_request
465
+ @connection.serve_request
466
466
  rescue => e
467
467
  p e
468
468
  p e.backtrace
@@ -498,7 +498,7 @@ class ConnectionTest < Minitest::Test
498
498
 
499
499
  write_client_side("GET / HTTP/1.1\r\n\r\n")
500
500
  @machine.spin do
501
- @adapter.serve_request
501
+ @connection.serve_request
502
502
  rescue => e
503
503
  p e
504
504
  p e.backtrace
@@ -531,7 +531,7 @@ class ConnectionTest < Minitest::Test
531
531
  count = 0
532
532
 
533
533
  write_client_side("GET / HTTP/1.1\r\n\r\n")
534
- @machine.spin { @adapter.serve_request }
534
+ @machine.spin { @connection.serve_request }
535
535
 
536
536
  while (data = read_client_side(65536))
537
537
  response << data
@@ -551,7 +551,7 @@ class ConnectionTest < Minitest::Test
551
551
  end
552
552
 
553
553
  write_client_side("GET / HTTP/1.1\r\n\r\n")
554
- @adapter.serve_request
554
+ @connection.serve_request
555
555
  response = read_client_side(65536)
556
556
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\nServer: Syntropy\r\n\r\n3\r\nfoo\r\n0\r\n\r\n"
557
557
  assert_equal expected, response
@@ -559,7 +559,7 @@ class ConnectionTest < Minitest::Test
559
559
  @env[:server_headers] = "Server: TP3\r\n"
560
560
 
561
561
  write_client_side("GET / HTTP/1.1\r\n\r\n")
562
- @adapter.serve_request
562
+ @connection.serve_request
563
563
  response = read_client_side(65536)
564
564
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\nServer: TP3\r\n\r\n3\r\nfoo\r\n0\r\n\r\n"
565
565
  assert_equal expected, response
@@ -572,7 +572,7 @@ class ConnectionTest < Minitest::Test
572
572
  }
573
573
 
574
574
  write_client_side("GET / HTTP/1.1\r\n\r\n")
575
- @adapter.serve_request
575
+ @connection.serve_request
576
576
  response = read_client_side(65536)
577
577
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\nSet-Cookie: foo=bar\r\n\r\n3\r\nfoo\r\n0\r\n\r\n"
578
578
  assert_equal expected, response
@@ -583,7 +583,7 @@ class ConnectionTest < Minitest::Test
583
583
  }
584
584
 
585
585
  write_client_side("GET / HTTP/1.1\r\n\r\n")
586
- @adapter.serve_request
586
+ @connection.serve_request
587
587
  response = read_client_side(65536)
588
588
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\nSet-Cookie: foo=bar\r\nContent-Type: text/plain\r\n\r\n3\r\nfoo\r\n0\r\n\r\n"
589
589
  assert_equal expected, response
@@ -597,7 +597,7 @@ class ConnectionTest < Minitest::Test
597
597
  }
598
598
 
599
599
  write_client_side("GET / HTTP/1.1\r\n\r\n")
600
- @adapter.serve_request
600
+ @connection.serve_request
601
601
  response = read_client_side(65536)
602
602
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\nSet-Cookie: foo=bar\r\nFoo: bar\r\nContent-Type: text/plain\r\n\r\n3\r\nfoo\r\n0\r\n\r\n"
603
603
  assert_equal expected, response
@@ -610,11 +610,11 @@ class ConnectionTest < Minitest::Test
610
610
  }
611
611
 
612
612
  write_client_side("GET / HTTP/1.1\r\n\r\n")
613
- @adapter.serve_request
613
+ @connection.serve_request
614
614
  response = read_client_side(65536)
615
615
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\nSet-Cookie: foo=bar; HttpOnly\r\n\r\n3\r\nfoo\r\n0\r\n\r\n"
616
616
  assert_equal expected, response
617
-
617
+
618
618
  end
619
619
 
620
620
  def test_set_cookie_multi1
@@ -624,11 +624,11 @@ class ConnectionTest < Minitest::Test
624
624
  }
625
625
 
626
626
  write_client_side("GET / HTTP/1.1\r\n\r\n")
627
- @adapter.serve_request
627
+ @connection.serve_request
628
628
  response = read_client_side(65536)
629
629
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\nSet-Cookie: foo=bar; HttpOnly\r\nSet-Cookie: bar=baz\r\n\r\n3\r\nfoo\r\n0\r\n\r\n"
630
630
  assert_equal expected, response
631
-
631
+
632
632
  end
633
633
 
634
634
  def test_set_cookie_multi2
@@ -640,10 +640,10 @@ class ConnectionTest < Minitest::Test
640
640
  }
641
641
 
642
642
  write_client_side("GET / HTTP/1.1\r\n\r\n")
643
- @adapter.serve_request
643
+ @connection.serve_request
644
644
  response = read_client_side(65536)
645
645
  expected = "HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\nSet-Cookie: a=1\r\nSet-Cookie: b=2\r\nSet-Cookie: c=3\r\nSet-Cookie: d=4\r\nSet-Cookie: e=5\r\n\r\n3\r\nfoo\r\n0\r\n\r\n"
646
646
  assert_equal expected, response
647
-
647
+
648
648
  end
649
649
  end
@@ -3,6 +3,8 @@
3
3
  require_relative 'helper'
4
4
 
5
5
  class JSONAPITest < Minitest::Test
6
+ HTTP = Syntropy::HTTP
7
+
6
8
  class TestAPI < Syntropy::JSONAPI
7
9
  def foo(req)
8
10
  @value
@@ -21,39 +23,39 @@ class JSONAPITest < Minitest::Test
21
23
  def test_json_api
22
24
  req = mock_req(':method' => 'GET', ':path' => '/')
23
25
  @app.call(req)
24
- assert_equal Qeweney::Status::BAD_REQUEST, req.response_status
26
+ assert_equal HTTP::BAD_REQUEST, req.response_status
25
27
 
26
28
  req = mock_req(':method' => 'GET', ':path' => '/?q=foo')
27
29
  @app.call(req)
28
- assert_equal Qeweney::Status::OK, req.response_status
29
- assert_equal({ status: 'OK', response: nil }, req.response_json)
30
+ assert_equal HTTP::OK, req.response_status
31
+ assert_equal({ 'status' => 'OK', 'response' => nil }, req.response_json)
30
32
 
31
33
  req = mock_req(':method' => 'POST', ':path' => '/?q=foo')
32
34
  @app.call(req)
33
- assert_equal Qeweney::Status::METHOD_NOT_ALLOWED, req.response_status
35
+ assert_equal HTTP::METHOD_NOT_ALLOWED, req.response_status
34
36
 
35
37
 
36
38
  req = mock_req(':method' => 'POST', ':path' => '/?q=bar&v=foo')
37
39
  @app.call(req)
38
- assert_equal Qeweney::Status::OK, req.response_status
39
- assert_equal({ status: 'OK', response: true }, req.response_json)
40
+ assert_equal HTTP::OK, req.response_status
41
+ assert_equal({ 'status' => 'OK', 'response' => true }, req.response_json)
40
42
 
41
43
  req = mock_req(':method' => 'GET', ':path' => '/?q=bar&v=foo')
42
44
  @app.call(req)
43
- assert_equal Qeweney::Status::METHOD_NOT_ALLOWED, req.response_status
45
+ assert_equal HTTP::METHOD_NOT_ALLOWED, req.response_status
44
46
 
45
47
  req = mock_req(':method' => 'GET', ':path' => '/?q=foo')
46
48
  @app.call(req)
47
- assert_equal Qeweney::Status::OK, req.response_status
48
- assert_equal({ status: 'OK', response: 'foo' }, req.response_json)
49
+ assert_equal HTTP::OK, req.response_status
50
+ assert_equal({ 'status' => 'OK', 'response' => 'foo' }, req.response_json)
49
51
 
50
52
  req = mock_req(':method' => 'GET', ':path' => '/?q=foo')
51
53
  @app.call(req)
52
- assert_equal Qeweney::Status::OK, req.response_status
53
- assert_equal({ status: 'OK', response: 'foo' }, req.response_json)
54
+ assert_equal HTTP::OK, req.response_status
55
+ assert_equal({ 'status' => 'OK', 'response' => 'foo' }, req.response_json)
54
56
 
55
57
  req = mock_req(':method' => 'GET', ':path' => '/?q=xxx')
56
58
  @app.call(req)
57
- assert_equal Qeweney::Status::NOT_FOUND, req.response_status
59
+ assert_equal HTTP::NOT_FOUND, req.response_status
58
60
  end
59
61
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ class MockAdapterTest < Minitest::Test
6
+ def test_mock_adapter
7
+ adapter = Syntropy::MockAdapter.new(nil)
8
+ req = Syntropy::Request.new({ ':path' => '/foo' }, adapter)
9
+ req.respond('bar', 'Content-Type' => 'baz')
10
+
11
+ assert_equal 'bar', adapter.response_body
12
+ assert_equal({'Content-Type' => 'baz'}, adapter.response_headers)
13
+ end
14
+
15
+ def test_mock_adapter_with_body
16
+ adapter = Syntropy::MockAdapter.new('barbaz')
17
+ req = Syntropy::Request.new({ ':path' => '/foo' }, adapter)
18
+ assert_equal false, req.complete?
19
+
20
+ body = req.read
21
+ assert_equal 'barbaz', body
22
+ assert_equal true, req.complete?
23
+ end
24
+
25
+ def test_mock_adapter_with_chunked_body
26
+ adapter = Syntropy::MockAdapter.new(['bar', 'baz'])
27
+ req = Syntropy::Request.new({ ':path' => '/foo' }, adapter)
28
+ assert_equal false, req.complete?
29
+
30
+ chunk = req.next_chunk
31
+ assert_equal 'bar', chunk
32
+ assert_equal false, req.complete?
33
+
34
+ chunk = req.next_chunk
35
+ assert_equal 'baz', chunk
36
+ assert_equal true, req.complete?
37
+ end
38
+
39
+ def test_mock_adapter_each_chunk
40
+ chunks = []
41
+ adapter = Syntropy::MockAdapter.new(['bar', 'baz'])
42
+ req = Syntropy::Request.new({ ':path' => '/foo' }, adapter)
43
+ assert_equal false, req.complete?
44
+
45
+ req.each_chunk { chunks << _1 }
46
+ assert_equal ['bar', 'baz'], chunks
47
+ assert_equal true, req.complete?
48
+ end
49
+
50
+ def test_set_response_headers
51
+ adapter = Syntropy::MockAdapter.new(nil)
52
+ req = Syntropy::Request.new({ ':path' => '/foo' }, adapter)
53
+ adapter.set_response_headers('Foo' => 'bar')
54
+ req.respond('hi', 'Bar' => 'baz')
55
+
56
+ assert_equal 'hi', adapter.response_body
57
+ assert_equal({'Foo' => 'bar', 'Bar' => 'baz'}, adapter.response_headers)
58
+ end
59
+ end