protocol_spec.rb 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. # frozen_string_literal: true
  2. require_relative 'spec_helper'
  3. describe "Portocol handling" do
  4. let(:processes) { Helpers::Pgcat.single_instance_setup("sharded_db", 1, "session") }
  5. let(:sequence) { [] }
  6. let(:pgcat_socket) { PostgresSocket.new('localhost', processes.pgcat.port) }
  7. let(:pgdb_socket) { PostgresSocket.new('localhost', processes.all_databases.first.port) }
  8. after do
  9. pgdb_socket.close
  10. pgcat_socket.close
  11. processes.all_databases.map(&:reset)
  12. processes.pgcat.shutdown
  13. end
  14. def run_comparison(sequence, socket_a, socket_b)
  15. sequence.each do |msg, *args|
  16. socket_a.send(msg, *args)
  17. socket_b.send(msg, *args)
  18. compare_messages(
  19. socket_a.read_from_server,
  20. socket_b.read_from_server
  21. )
  22. end
  23. end
  24. def compare_messages(msg_arr0, msg_arr1)
  25. if msg_arr0.count != msg_arr1.count
  26. error_output = []
  27. error_output << "#{msg_arr0.count} : #{msg_arr1.count}"
  28. error_output << "PgCat Messages"
  29. error_output += msg_arr0.map { |message| "\t#{message[:code]} - #{message[:bytes].map(&:chr).join(" ")}" }
  30. error_output << "PgServer Messages"
  31. error_output += msg_arr1.map { |message| "\t#{message[:code]} - #{message[:bytes].map(&:chr).join(" ")}" }
  32. error_desc = error_output.join("\n")
  33. raise StandardError, "Message count mismatch #{error_desc}"
  34. end
  35. (0..msg_arr0.count - 1).all? do |i|
  36. msg0 = msg_arr0[i]
  37. msg1 = msg_arr1[i]
  38. result = [
  39. msg0[:code] == msg1[:code],
  40. msg0[:len] == msg1[:len],
  41. msg0[:bytes] == msg1[:bytes],
  42. ].all?
  43. next result if result
  44. if result == false
  45. error_string = []
  46. if msg0[:code] != msg1[:code]
  47. error_string << "code #{msg0[:code]} != #{msg1[:code]}"
  48. end
  49. if msg0[:len] != msg1[:len]
  50. error_string << "len #{msg0[:len]} != #{msg1[:len]}"
  51. end
  52. if msg0[:bytes] != msg1[:bytes]
  53. error_string << "bytes #{msg0[:bytes]} != #{msg1[:bytes]}"
  54. end
  55. err = error_string.join("\n")
  56. raise StandardError, "Message mismatch #{err}"
  57. end
  58. end
  59. end
  60. RSpec.shared_examples "at parity with database" do
  61. before do
  62. pgcat_socket.send_startup_message("sharding_user", "sharded_db", "sharding_user")
  63. pgdb_socket.send_startup_message("sharding_user", "shard0", "sharding_user")
  64. end
  65. it "works" do
  66. run_comparison(sequence, pgcat_socket, pgdb_socket)
  67. end
  68. end
  69. context "Cancel Query" do
  70. let(:sequence) {
  71. [
  72. [:send_query_message, "SELECT pg_sleep(5)"],
  73. [:cancel_query]
  74. ]
  75. }
  76. it_behaves_like "at parity with database"
  77. end
  78. xcontext "Simple query after parse" do
  79. let(:sequence) {
  80. [
  81. [:send_parse_message, "SELECT 5"],
  82. [:send_query_message, "SELECT 1"],
  83. [:send_bind_message],
  84. [:send_describe_message, "P"],
  85. [:send_execute_message],
  86. [:send_sync_message],
  87. ]
  88. }
  89. # Known to fail due to PgCat not supporting flush
  90. it_behaves_like "at parity with database"
  91. end
  92. xcontext "Flush message" do
  93. let(:sequence) {
  94. [
  95. [:send_parse_message, "SELECT 1"],
  96. [:send_flush_message]
  97. ]
  98. }
  99. # Known to fail due to PgCat not supporting flush
  100. it_behaves_like "at parity with database"
  101. end
  102. xcontext "Bind without parse" do
  103. let(:sequence) {
  104. [
  105. [:send_bind_message]
  106. ]
  107. }
  108. # This is known to fail.
  109. # Server responds immediately, Proxy buffers the message
  110. it_behaves_like "at parity with database"
  111. end
  112. context "Simple message" do
  113. let(:sequence) {
  114. [[:send_query_message, "SELECT 1"]]
  115. }
  116. it_behaves_like "at parity with database"
  117. end
  118. context "Extended protocol" do
  119. let(:sequence) {
  120. [
  121. [:send_parse_message, "SELECT 1"],
  122. [:send_bind_message],
  123. [:send_describe_message, "P"],
  124. [:send_execute_message],
  125. [:send_sync_message],
  126. ]
  127. }
  128. it_behaves_like "at parity with database"
  129. end
  130. end