server-postgres.cr 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. require "kemal"
  2. require "pg"
  3. require "pool/connection"
  4. require "html_builder"
  5. # Compose Objects (like Hash) to have a to_json method
  6. require "json/to_json"
  7. DB = ConnectionPool.new(capacity: 25, timeout: 0.01) do
  8. PG.connect("postgres://benchmarkdbuser:benchmarkdbpass@#{ENV["DBHOST"]? || "127.0.0.1"}/hello_world")
  9. end
  10. class CONTENT
  11. UTF8 = "; charset=UTF-8"
  12. JSON = "application/json"
  13. PLAIN = "text/plain"
  14. HTML = "text/html" + UTF8
  15. end
  16. ID_MAXIMUM = 10_000
  17. private def randomWorld
  18. id = rand(1..ID_MAXIMUM)
  19. conn = DB.checkout
  20. result = conn.exec({Int32, Int32}, "SELECT id, randomNumber FROM world WHERE id = $1", [id]).rows.first
  21. DB.checkin(conn)
  22. {:id => result[0], :randomNumber => result[1]}
  23. end
  24. private def setWorld(world)
  25. conn = DB.checkout
  26. result = conn.exec("UPDATE world set randomNumber = $1 where id = $2", [world[:randomNumber], world[:id]])
  27. DB.checkin(conn)
  28. world
  29. end
  30. private def fortunes
  31. data = [] of Hash(Symbol, (String | Int32))
  32. DB.connection.exec({Int32, String}, "select id, message from Fortune").rows.each do |row|
  33. data.push({:id => row[0], :message => row[1]})
  34. end
  35. data
  36. end
  37. private def sanitizedQueryCount(request)
  38. queries = request.params["queries"] as String
  39. return 1 if queries.empty? || queries.to_i?.nil?
  40. if queries.to_i > 500
  41. queries = 500
  42. elsif queries.to_i < 1
  43. queries = 1
  44. end
  45. queries.to_i
  46. end
  47. before_all do |env|
  48. env.response.headers["Server"] = "Kemal"
  49. env.response.headers["Date"] = Time.now.to_s
  50. end
  51. #
  52. # Basic Tests
  53. #
  54. # Test 1: JSON Serialization
  55. get "/json", do |env|
  56. env.response.content_type = CONTENT::JSON
  57. { :message => "Hello, World!" }.to_json
  58. end
  59. # Test 6: Plaintext
  60. get "/plaintext", do |env|
  61. env.response.content_type = CONTENT::PLAIN
  62. "Hello, World!"
  63. end
  64. #
  65. # Postgres DatabaseTests
  66. #
  67. # Postgres Test 2: Single database query
  68. get "/db", do |env|
  69. env.response.content_type = CONTENT::JSON
  70. randomWorld.to_json
  71. end
  72. # Postgres Test 3: Multiple database query
  73. get "/queries", do |env|
  74. results = (1..sanitizedQueryCount(env)).map do
  75. randomWorld
  76. end
  77. env.response.content_type = CONTENT::JSON
  78. results.to_json
  79. end
  80. # Postgres Test 4: Fortunes
  81. get "/fortunes", do |env|
  82. data = fortunes
  83. additional_fortune = {
  84. :id => 0,
  85. :message => "Additional fortune added at request time."
  86. }
  87. data.push(additional_fortune)
  88. data.sort! do |a, b|
  89. a[:message].to_s <=> b[:message].to_s
  90. end
  91. # New builder for each request!
  92. html = HTML::Builder.new.build do
  93. html {
  94. head {
  95. title { text "Fortunes" }
  96. }
  97. body {
  98. table {
  99. tr {
  100. thead { text "id" }
  101. thead { text "message" }
  102. }
  103. data.each { |e|
  104. tr {
  105. td { text e[:id].to_s }
  106. td { text e[:message].to_s }
  107. }
  108. }
  109. }
  110. }
  111. }
  112. end
  113. # Doctype not available in builder
  114. # builder only supports `thead`, tests need to see `th`
  115. env.response.content_type = CONTENT::HTML
  116. "<!doctype html>" + html.gsub("thead", "th")
  117. end
  118. # Postgres Test 5: Database Updates
  119. get "/updates", do |env|
  120. updated = (1..sanitizedQueryCount(env)).map do
  121. world = randomWorld
  122. world[:randomNumber] = rand(1..ID_MAXIMUM)
  123. setWorld(world)
  124. end
  125. env.response.content_type = CONTENT::JSON
  126. updated.to_json
  127. end