turnout_proxy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ tmp/
2
+ .DS_Store
3
+ .tags*
4
+ .rvmrc
5
+ .exrc
6
+ pkg/
7
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - ree-1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
7
+ branches:
8
+ only:
9
+ - master
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rake'
7
+ gem 'posix-spawn'
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Vladimir Yarotsky
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,18 @@
1
+ Turnout Proxy
2
+ =============
3
+
4
+ [![Build Status](https://secure.travis-ci.org/v-yarotsky/turnout_proxy.png)](http://travis-ci.org/v-yarotsky/turnout_proxy)
5
+ [![Gem Version](https://badge.fury.io/rb/turnout_proxy.png)](http://badge.fury.io/rb/turnout_proxy)
6
+
7
+ Proxy server which allows to switch between two destinations using lock file.
8
+
9
+ Installation:
10
+ -------------
11
+
12
+ $ gem install turnout_proxy
13
+
14
+ Usage:
15
+ ------
16
+
17
+ $ turnout_proxy --help
18
+
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/clean'
6
+ require 'bundler/gem_tasks'
7
+
8
+ begin
9
+ Bundler.setup
10
+ rescue Bundler::BundlerError => e
11
+ $stderr.puts e.message
12
+ $stderr.puts "Run `bundle install` to install missing gems"
13
+ exit e.status_code
14
+ end
15
+
16
+ CLOBBER.include('doc/**', 'pkg/**', 'coverage/**')
17
+
18
+ Rake::TestTask.new do |t|
19
+ t.libs << "test"
20
+ t.pattern = "test/{lib,acceptance}/**/test*.rb"
21
+ end
22
+
23
+ task :default => [:test]
24
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/turnout_proxy ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'turnout_proxy'
6
+
7
+ options = {
8
+ :lock_file => "/tmp/turnout.lock",
9
+ :default => { :host => "127.0.0.1" },
10
+ :alternate => { :host => "127.0.0.1" },
11
+ :host => "0.0.0.0",
12
+ :port => 5678,
13
+ :debug => false
14
+ }
15
+
16
+ OptionParser.new do |opts|
17
+ opts.banner = "Usage: turnout_proxy [options]"
18
+ opts.version = TurnoutProxy::VERSION
19
+
20
+ opts.separator "Proxy options:"
21
+ opts.on("--host HOST", "Proxy host (Default: localhost)") { |v| options[:host] = v }
22
+ opts.on("--port PORT", Integer, "Proxy port (Default: 5678)") { |v| options[:port] = v }
23
+ opts.on("--lock-file FILE", "File, which existence determines destination server (Default: /tmp/turnout.lock)") { |v| options[:lock_file] = v }
24
+
25
+ opts.separator "Default destination server options:"
26
+ opts.on("--default-host HOST", "(Default: localhost)") { |v| options[:default][:host] = v }
27
+ opts.on("--default-port PORT", Integer) { |v| options[:default][:port] = v }
28
+
29
+ opts.separator "Alternate destination server options:"
30
+ opts.on("--alternate-host HOST", "(Default: localhost)") { |v| options[:alternate][:host] = v }
31
+ opts.on("--alternate-port PORT", Integer) { |v| options[:alternate][:port] = v }
32
+
33
+ opts.separator "Special options:"
34
+ opts.on("--debug") { |*| options[:debug] = true }
35
+ end.parse!
36
+
37
+ Signal.trap("SIGINT") do
38
+ puts "Terminating"
39
+ exit
40
+ end
41
+
42
+ TurnoutProxy.run(options)
@@ -0,0 +1,37 @@
1
+ module TurnoutProxy
2
+
3
+ class HostChooser
4
+ attr_accessor :file_checker
5
+
6
+ def initialize(connection, options = {})
7
+ @connection = connection
8
+ @file_checker = File
9
+
10
+ @default = validate_host(options[:default])
11
+ @alternate = validate_host(options[:alternate])
12
+
13
+ @lock_file = options[:lock_file]
14
+ end
15
+
16
+ def on_data(data)
17
+ use_alternate? ? @connection.server(:alternate, @alternate) : @connection.server(:default, @default)
18
+ data
19
+ end
20
+
21
+ private
22
+
23
+ def use_alternate?
24
+ @file_checker.exists?(@lock_file)
25
+ end
26
+
27
+ private
28
+
29
+ def validate_host(host_config)
30
+ if host_config.nil? || String(host_config[:host]).empty? || host_config[:port].nil?
31
+ raise ArgumentError, "Bad host config, both host and port must be present."
32
+ end
33
+ host_config
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,15 @@
1
+ require 'em-proxy'
2
+ require 'turnout_proxy/host_chooser'
3
+
4
+ module TurnoutProxy
5
+ version_file = File.expand_path('../VERSION', File.dirname(__FILE__))
6
+ VERSION = File.read(version_file).freeze
7
+
8
+ def self.run(options = {})
9
+ Proxy.start(options) do |conn|
10
+ callbacks = HostChooser.new(conn, options)
11
+ conn.on_data &callbacks.method(:on_data)
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,63 @@
1
+ require 'test_helper'
2
+ require 'fileutils'
3
+ require 'net/http'
4
+ require 'posix/spawn'
5
+ require 'support/hello_server'
6
+ require 'turnout_proxy'
7
+
8
+ class TestTurnoutProxy < TurnoutProxyTestCase
9
+ include POSIX::Spawn
10
+ include TurnoutProxy
11
+
12
+ TEST_LOCK_FILE = PROJECT_ROOT.join("lock")
13
+
14
+ def setup
15
+ @@servers ||= begin
16
+ HelloServer.new(8083, "S1")
17
+ HelloServer.new(8084, "S2")
18
+ end
19
+ FileUtils.rm_rf TEST_LOCK_FILE
20
+ end
21
+
22
+ def teardown
23
+ FileUtils.rm_rf TEST_LOCK_FILE
24
+ end
25
+
26
+ def with_running_proxy(default_port = 8083, alternate_port = 8084)
27
+ router = PROJECT_ROOT.join("bin/turnout_proxy")
28
+ pid = spawn("ruby -Ilib #{router} --default-port=#{default_port} --alternate-port=#{alternate_port} --lock-file=#{TEST_LOCK_FILE}")
29
+ sleep 0.5
30
+ yield pid
31
+ sleep 0.5
32
+ ensure
33
+ Process.kill(:SIGQUIT, pid)
34
+ end
35
+
36
+ test "proxies to default server when lock does not exist" do
37
+ called = false
38
+ with_running_proxy do
39
+ called = Net::HTTP.get(URI("http://127.0.0.1:5678")) == "S1"
40
+ end
41
+ assert called, "Expected to proxy to server on 8083"
42
+ end
43
+
44
+ test "proxies to alternate server when lock file does exist" do
45
+ FileUtils.touch TEST_LOCK_FILE
46
+ called = false
47
+ with_running_proxy do
48
+ called = Net::HTTP.get(URI("http://127.0.0.1:5678")) == "S2"
49
+ end
50
+ assert called, "Expected to proxy to server on 8084"
51
+ end
52
+
53
+ test "doesn't fail if destination server isn't responding" do
54
+ @pid = nil
55
+ with_running_proxy(8085) do |pid|
56
+ @pid = pid
57
+ Net::HTTP.get(URI("http://127.0.0.1:5678")) rescue nil
58
+ end
59
+ Process.kill 0, @pid
60
+ end
61
+
62
+ end
63
+
@@ -0,0 +1,66 @@
1
+ require 'test_helper'
2
+ require 'turnout_proxy/host_chooser'
3
+
4
+ class TestHostChooser < TurnoutProxyTestCase
5
+ include TurnoutProxy
6
+
7
+ class FakeConnection
8
+ attr_reader :forwards
9
+
10
+ def initialize
11
+ @forwards = []
12
+ end
13
+
14
+ def server(*data)
15
+ @forwards << data
16
+ end
17
+ end
18
+
19
+ class FakeFile
20
+ def exists!(file)
21
+ @existing_file = file
22
+ end
23
+
24
+ def exists?(file)
25
+ !!@existing_file
26
+ end
27
+ end
28
+
29
+ def setup
30
+ @connection = FakeConnection.new
31
+ @file_checker = FakeFile.new
32
+ end
33
+
34
+ ALTERNATE_CONFIG = { :host => "127.0.0.1", :port => 19999 }
35
+ DEFAULT_CONFIG = { :host => "127.0.0.1", :port => 9012 }
36
+
37
+ def host_chooser
38
+ host_chooser = HostChooser.new(@connection,
39
+ :default => DEFAULT_CONFIG,
40
+ :alternate => ALTERNATE_CONFIG)
41
+ host_chooser.file_checker = @file_checker
42
+ host_chooser
43
+ end
44
+
45
+ test "it routes to developer tunnel if lock file exists" do
46
+ @file_checker.exists!("/tmp/betsoft.lock")
47
+ host_chooser.on_data("Hello")
48
+ assert_equal [[:alternate, ALTERNATE_CONFIG]], @connection.forwards
49
+ end
50
+
51
+ test "it routes to staging if lock file does not exist" do
52
+ host_chooser.on_data("Hello")
53
+ assert_equal [[:default, DEFAULT_CONFIG]], @connection.forwards
54
+ end
55
+
56
+ test "it raises if alternate host not specified" do
57
+ assert_raise(ArgumentError) do
58
+ HostChooser.new(@connection, :default => DEFAULT_CONFIG)
59
+ end
60
+
61
+ assert_raise(ArgumentError) do
62
+ HostChooser.new(@connection, :default => DEFAULT_CONFIG, :alternate => {})
63
+ end
64
+ end
65
+ end
66
+
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'posix/spawn'
4
+ require 'eventmachine'
5
+
6
+ class HelloServer
7
+ include POSIX::Spawn
8
+
9
+ def initialize(port, message)
10
+ @pid = spawn("ruby #{__FILE__} #{port} #{message}")
11
+ at_exit { die }
12
+ end
13
+
14
+ def pid
15
+ @pid
16
+ end
17
+
18
+ def die
19
+ Process.kill(:SIGQUIT, pid)
20
+ end
21
+ end
22
+
23
+ def HelloServer(response)
24
+ Module.new do
25
+ define_method :receive_data do |data|
26
+ send_data "HTTP/1.1 200 OK\r\nContent-Length: #{response.length}\r\n\r\n#{response}"
27
+ close_connection_after_writing
28
+ end
29
+ end
30
+ end
31
+
32
+ if $0 == __FILE__
33
+ EventMachine.run do
34
+ EventMachine.start_server "0.0.0.0", ARGV[0].to_i, HelloServer(ARGV[1] || "OK")
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ require 'test/unit'
2
+ require 'pathname'
3
+
4
+ $:.unshift File.expand_path('../../lib', __FILE__)
5
+
6
+ class TurnoutProxyTestCase < Test::Unit::TestCase
7
+ PROJECT_ROOT = Pathname.new(File.expand_path("../../", __FILE__))
8
+
9
+ def default_test
10
+ # Make Test::Unit happy...
11
+ end
12
+
13
+ def self.test(name, &block)
14
+ raise ArgumentError, "Example name can't be empty" if String(name).empty?
15
+ define_method "test #{name}", &block
16
+ end
17
+ end
18
+
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ $:.unshift File.expand_path('../lib/', __FILE__)
4
+
5
+ require 'turnout_proxy'
6
+ require 'date'
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = "turnout_proxy"
10
+ s.summary = "Proxy server which allows to switch between two destinations using lock file"
11
+
12
+ s.version = TurnoutProxy::VERSION.dup
13
+ s.authors = ["Vladimir Yarotsky"]
14
+ s.date = Date.today.to_s
15
+ s.email = "vladimir.yarotksy@gmail.com"
16
+ s.homepage = "http://github.com/v-yarotsky/turnout_proxy"
17
+ s.licenses = ["MIT"]
18
+
19
+ s.rubygems_version = "1.8.21"
20
+ s.required_rubygems_version = ">= 1.3.6"
21
+ s.specification_version = 3
22
+
23
+ s.files = `git ls-files`.split($/)
24
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
25
+ s.test_files = s.files.grep(%r{^(test)/})
26
+ s.require_paths = ["lib"]
27
+ s.extra_rdoc_files = %w[LICENSE.txt README.md]
28
+
29
+ s.add_dependency("em-proxy", "~> 0.1")
30
+
31
+ s.add_development_dependency("rake")
32
+ s.add_development_dependency("posix-spawn")
33
+ end
34
+
35
+
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: turnout_proxy
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Vladimir Yarotsky
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-04-04 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: em-proxy
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ hash: 9
28
+ segments:
29
+ - 0
30
+ - 1
31
+ version: "0.1"
32
+ type: :runtime
33
+ requirement: *id001
34
+ prerelease: false
35
+ - !ruby/object:Gem::Dependency
36
+ name: rake
37
+ version_requirements: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :development
47
+ requirement: *id002
48
+ prerelease: false
49
+ - !ruby/object:Gem::Dependency
50
+ name: posix-spawn
51
+ version_requirements: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ requirement: *id003
62
+ prerelease: false
63
+ description:
64
+ email: vladimir.yarotksy@gmail.com
65
+ executables:
66
+ - turnout_proxy
67
+ extensions: []
68
+
69
+ extra_rdoc_files:
70
+ - LICENSE.txt
71
+ - README.md
72
+ files:
73
+ - .gitignore
74
+ - .travis.yml
75
+ - Gemfile
76
+ - LICENSE.txt
77
+ - README.md
78
+ - Rakefile
79
+ - VERSION
80
+ - bin/turnout_proxy
81
+ - lib/turnout_proxy.rb
82
+ - lib/turnout_proxy/host_chooser.rb
83
+ - test/acceptance/test_turnout_proxy.rb
84
+ - test/lib/turnout_proxy/test_host_chooser.rb
85
+ - test/support/hello_server.rb
86
+ - test/test_helper.rb
87
+ - turnout_proxy.gemspec
88
+ homepage: http://github.com/v-yarotsky/turnout_proxy
89
+ licenses:
90
+ - MIT
91
+ post_install_message:
92
+ rdoc_options: []
93
+
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ hash: 23
111
+ segments:
112
+ - 1
113
+ - 3
114
+ - 6
115
+ version: 1.3.6
116
+ requirements: []
117
+
118
+ rubyforge_project:
119
+ rubygems_version: 1.8.24
120
+ signing_key:
121
+ specification_version: 3
122
+ summary: Proxy server which allows to switch between two destinations using lock file
123
+ test_files:
124
+ - test/acceptance/test_turnout_proxy.rb
125
+ - test/lib/turnout_proxy/test_host_chooser.rb
126
+ - test/support/hello_server.rb
127
+ - test/test_helper.rb