Last active
December 10, 2015 02:09
-
-
Save gbuesing/4365756 to your computer and use it in GitHub Desktop.
Rails commands multi-process demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# Rails commands multi-process demo | |
# | |
# For use with https://github.com/rails/commands | |
# | |
# Put this file in an app in script/superconsole (or whatever name) and chmod +x | |
# or just put this in lib/superconsole.rb. | |
# | |
# This script opens the console in the development env, and forks a child process | |
# with the app in the test env. | |
# | |
# Console can send commands to the test env via the "testenv" method, e.g.: | |
# | |
# testenv.rake 'about' | |
# | |
# This message is sent to the testenv via a Unix socket | |
require 'socket' | |
# create unix socket to enable message passing between parent process (dev env) and child (test env) | |
CHILD_SOCKET, PARENT_SOCKET = Socket.pair(:UNIX, :DGRAM, 0) | |
APP_PATH = File.expand_path('../../config/application', __FILE__) | |
require File.expand_path('../../config/boot', __FILE__) | |
# load gems before forking | |
Bundler.require(:default, :assets) | |
# fork for test environment | |
child_pid = fork do | |
ENV['RAILS_ENV'] = Rails.env = 'test' | |
require APP_PATH | |
Rails.application.require_environment! | |
trap(:INT) { exit(0) } # close silently | |
commander = Rails::Commands::Commander.new | |
loop do | |
msg = CHILD_SOCKET.recv(1000) | |
# puts "[#{Rails.env}] received message: #{msg.inspect}\n" | |
argv = msg.split(' ') | |
command = argv.shift | |
args = argv.join(' ') | |
args = nil unless args.match(/\S/) | |
retval = if commander.respond_to?(command) | |
commander.send(command, args) | |
else | |
'Unrecognized command' | |
end | |
CHILD_SOCKET.write(retval) | |
end | |
end | |
# cleanup: kill child process at exit | |
at_exit do | |
Process.kill(:INT, child_pid) | |
end | |
# enable communication between dev console and test env child process | |
module TestEnv | |
def self.send msg | |
PARENT_SOCKET.write(msg) | |
PARENT_SOCKET.recv(1000) | |
end | |
def self.method_missing(m, *args, &block) | |
send "#{m} #{args.join(' ')}" | |
end | |
end | |
module ConsoleDelegationOverride | |
def testenv | |
TestEnv | |
end | |
def test *args | |
testenv.test *args | |
end | |
end | |
require 'rails/commands/console' | |
require APP_PATH | |
Rails.application.require_environment! | |
Rails::ConsoleMethods.send :include, ConsoleDelegationOverride | |
Rails::Console.start(Rails.application) |
Added ConsoleDelegationOverride, so that the bare test command now runs in child process
I made this a gem: https://github.com/gbuesing/duoconsole
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Should be easy enough to have the bare "test" command delegate to testenv.test in the parent process, and actually run the tests in the child.