streaming_server_manager.rb 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. # frozen_string_literal: true
  2. class StreamingServerManager
  3. @running_thread = nil
  4. def initialize
  5. at_exit { stop }
  6. end
  7. def start(port: 4020)
  8. return if @running_thread
  9. queue = Queue.new
  10. @queue = queue
  11. @running_thread = Thread.new do
  12. Open3.popen2e(
  13. {
  14. 'REDIS_NAMESPACE' => ENV.fetch('REDIS_NAMESPACE'),
  15. 'DB_NAME' => "#{ENV.fetch('DB_NAME', 'mastodon')}_test#{ENV.fetch('TEST_ENV_NUMBER', '')}",
  16. 'RAILS_ENV' => ENV.fetch('RAILS_ENV', 'test'),
  17. 'NODE_ENV' => ENV.fetch('STREAMING_NODE_ENV', 'development'),
  18. 'PORT' => port.to_s,
  19. },
  20. 'node index.js', # must not call yarn here, otherwise it will fail because yarn does not send signals to its child process
  21. chdir: Rails.root.join('streaming')
  22. ) do |_stdin, stdout_err, process_thread|
  23. status = :starting
  24. # Spawn a thread to listen on streaming server output
  25. output_thread = Thread.new do
  26. stdout_err.each_line do |line|
  27. Rails.logger.info "Streaming server: #{line}"
  28. if status == :starting && line.match('Streaming API now listening on')
  29. status = :started
  30. @queue.enq 'started'
  31. end
  32. end
  33. end
  34. # And another thread to listen on commands from the main thread
  35. loop do
  36. msg = queue.pop
  37. case msg
  38. when 'stop'
  39. # we need to properly stop the reading thread
  40. output_thread.kill
  41. # Then stop the node process
  42. Process.kill('KILL', process_thread.pid)
  43. # And we stop ourselves
  44. @running_thread.kill
  45. end
  46. end
  47. end
  48. end
  49. # wait for 10 seconds for the streaming server to start
  50. Timeout.timeout(10) do
  51. loop do
  52. break if @queue.pop == 'started'
  53. end
  54. end
  55. end
  56. def stop
  57. return unless @running_thread
  58. @queue.enq 'stop'
  59. # Wait for the thread to end
  60. @running_thread.join
  61. end
  62. end
  63. RSpec.configure do |config|
  64. config.before :suite do
  65. if streaming_examples_present?
  66. # Compile assets
  67. Webpacker.compile
  68. # Start the node streaming server
  69. streaming_server_manager.start(port: STREAMING_PORT)
  70. end
  71. end
  72. config.after :suite do
  73. if streaming_examples_present?
  74. # Stop the node streaming server
  75. streaming_server_manager.stop
  76. end
  77. end
  78. config.around :each, :streaming, type: :system do |example|
  79. # Streaming server needs DB access but `use_transactional_tests` rolls back
  80. # every transaction. Disable this feature for streaming tests, and use
  81. # DatabaseCleaner to clean the database tables between each test.
  82. self.use_transactional_tests = false
  83. DatabaseCleaner.cleaning do
  84. # NOTE: we switched registrations mode to closed by default, but the specs
  85. # very heavily rely on having it enabled by default, as it relies on users
  86. # being approved by default except in select cases where explicitly testing
  87. # other registration modes
  88. # Also needs to be set per-example here because of the database cleaner.
  89. Setting.registrations_mode = 'open'
  90. # Load seeds so we have the default roles otherwise cleared by `DatabaseCleaner`
  91. Rails.application.load_seed
  92. example.run
  93. end
  94. self.use_transactional_tests = true
  95. end
  96. private
  97. def streaming_server_manager
  98. @streaming_server_manager ||= StreamingServerManager.new
  99. end
  100. def streaming_examples_present?
  101. RSpec.world.filtered_examples.values.flatten.any? { |example| example.metadata[:streaming] == true }
  102. end
  103. end