tests.rb 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. # frozen_string_literal: true
  2. require 'pg'
  3. require 'active_record'
  4. # Uncomment these two to see all queries.
  5. # ActiveRecord.verbose_query_logs = true
  6. # ActiveRecord::Base.logger = Logger.new(STDOUT)
  7. ActiveRecord::Base.establish_connection(
  8. adapter: 'postgresql',
  9. host: '127.0.0.1',
  10. port: 6432,
  11. username: 'sharding_user',
  12. password: 'sharding_user',
  13. database: 'sharded_db',
  14. application_name: 'testing_pgcat',
  15. prepared_statements: false, # Transaction mode
  16. advisory_locks: false # Same
  17. )
  18. class TestSafeTable < ActiveRecord::Base
  19. self.table_name = 'test_safe_table'
  20. end
  21. class ShouldNeverHappenException < RuntimeError
  22. end
  23. class CreateSafeShardedTable < ActiveRecord::Migration[7.0]
  24. # Disable transasctions or things will fly out of order!
  25. disable_ddl_transaction!
  26. SHARDS = 3
  27. def up
  28. SHARDS.times do |x|
  29. # This will make this migration reversible!
  30. connection.execute "SET SHARD TO '#{x.to_i}'"
  31. connection.execute "SET SERVER ROLE TO 'primary'"
  32. connection.execute <<-SQL
  33. CREATE TABLE test_safe_table (
  34. id BIGINT PRIMARY KEY,
  35. name VARCHAR,
  36. description TEXT
  37. ) PARTITION BY HASH (id);
  38. CREATE TABLE test_safe_table_data PARTITION OF test_safe_table
  39. FOR VALUES WITH (MODULUS #{SHARDS.to_i}, REMAINDER #{x.to_i});
  40. SQL
  41. end
  42. end
  43. def down
  44. SHARDS.times do |x|
  45. connection.execute "SET SHARD TO '#{x.to_i}'"
  46. connection.execute "SET SERVER ROLE TO 'primary'"
  47. connection.execute 'DROP TABLE test_safe_table CASCADE'
  48. end
  49. end
  50. end
  51. SHARDS = 3
  52. 2.times do
  53. begin
  54. CreateSafeShardedTable.migrate(:down)
  55. rescue Exception
  56. puts "Tables don't exist yet"
  57. end
  58. CreateSafeShardedTable.migrate(:up)
  59. SHARDS.times do |x|
  60. TestSafeTable.connection.execute "SET SHARD TO '#{x.to_i}'"
  61. TestSafeTable.connection.execute "SET SERVER ROLE TO 'primary'"
  62. TestSafeTable.connection.execute "TRUNCATE #{TestSafeTable.table_name}"
  63. end
  64. # Equivalent to Makara's stick_to_master! except it sticks until it's changed.
  65. TestSafeTable.connection.execute "SET SERVER ROLE TO 'primary'"
  66. 200.times do |x|
  67. x += 1 # Postgres ids start at 1
  68. TestSafeTable.connection.execute "SET SHARDING KEY TO '#{x.to_i}'"
  69. TestSafeTable.create(id: x, name: "something_special_#{x.to_i}", description: "It's a surprise!")
  70. end
  71. TestSafeTable.connection.execute "SET SERVER ROLE TO 'replica'"
  72. 100.times do |x|
  73. x += 1 # 0 confuses our sharding function
  74. TestSafeTable.connection.execute "SET SHARDING KEY TO '#{x.to_i}'"
  75. TestSafeTable.find_by_id(x).id
  76. end
  77. # Will use the query parser to direct reads to replicas
  78. TestSafeTable.connection.execute "SET SERVER ROLE TO 'auto'"
  79. 100.times do |x|
  80. x += 101
  81. TestSafeTable.connection.execute "SET SHARDING KEY TO '#{x.to_i}'"
  82. TestSafeTable.find_by_id(x).id
  83. end
  84. end
  85. # Test wrong shard
  86. TestSafeTable.connection.execute "SET SHARD TO '1'"
  87. begin
  88. TestSafeTable.create(id: 5, name: 'test', description: 'test description')
  89. raise ShouldNeverHappenException('Uh oh')
  90. rescue ActiveRecord::StatementInvalid
  91. puts 'OK'
  92. end