forward 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,12 +9,15 @@ module Forward
9
9
  class BadResponse < StandardError; end
10
10
  class ResourceNotFound < StandardError; end
11
11
  class ResourceError < StandardError
12
- attr_reader :action, :errors
12
+ attr_reader :code, :type, :action, :api_message, :errors
13
13
 
14
- def initialize(action, json)
15
- @action = action
16
- @json = json
17
- @errors = json[:errors]
14
+ def initialize(code, action, json = {})
15
+ @code = code
16
+ @action = action
17
+ @json = json
18
+ @type = json[:type]
19
+ @api_message = json[:message]
20
+ @errors = json[:errors] || {}
18
21
  end
19
22
  end
20
23
 
@@ -35,11 +38,11 @@ module Forward
35
38
  end
36
39
 
37
40
  def self.token=(token)
38
- @@api_token = token
41
+ @api_token = token
39
42
  end
40
43
 
41
44
  def self.token
42
- defined?(@@api_token) ? @@api_token : nil
45
+ defined?(@api_token) ? @api_token : nil
43
46
  end
44
47
  end
45
48
  end
@@ -4,7 +4,7 @@ module Forward
4
4
 
5
5
  def self.create(log)
6
6
  resource = ClientLog.new(:create)
7
- resource.uri = '/api/client_logs'
7
+ resource.uri = '/api/v2/client_logs'
8
8
  params = {
9
9
  :client => Forward.client_string,
10
10
  :log => log
@@ -28,8 +28,6 @@ module Forward
28
28
  response = @http.request(@request)
29
29
 
30
30
  parse_response(response)
31
- rescue ResourceError => e
32
- self.class.dispatch_error(e)
33
31
  end
34
32
 
35
33
  def build_request(method, params = {})
@@ -77,10 +75,11 @@ module Forward
77
75
 
78
76
  def parse_response(response)
79
77
  log(:debug, "Response: [#{response.code}] `#{response.body}'")
78
+ code = response.code.to_i
80
79
 
81
- if response.code.to_i == 404
80
+ if code == 404
82
81
  raise ResourceNotFound
83
- elsif response.code.to_i != 200
82
+ elsif ![ 200, 422, 401 ].include? code
84
83
  raise BadResponse, "response code was: #{response.code}"
85
84
  elsif response['content-type'] !~ /^application\/json/
86
85
  raise BadResponse, "response was not JSON, unable to parse"
@@ -90,22 +89,22 @@ module Forward
90
89
 
91
90
  if json.is_a? Hash
92
91
  json.symbolize_keys!
93
- raise ResourceError.new(@action, json) if json.has_key?(:errors)
92
+ raise ResourceError.new(code, @action, json) if code != 200
94
93
  end
95
94
 
96
95
  json
97
96
  end
98
97
 
99
- def self.dispatch_error(error)
100
- Forward.log(:debug, "Dispatching ResourceError: action: #{error.action} errors: #{error.errors.inspect}")
101
- method = :"#{error.action}_error"
102
-
103
- if respond_to? method
104
- send(method, error.errors)
105
- else
106
- Forward::Client.cleanup_and_exit!('An error occured, please contact support@forwardhq.com')
107
- end
108
- end
98
+ # def self.dispatch_error(error)
99
+ # Forward.log(:debug, "Dispatching ResourceError: action: #{error.action} errors: #{error.errors.inspect}")
100
+ # method = :"#{error.action}_error"
101
+ #
102
+ # if respond_to? method
103
+ # send(method, error.errors)
104
+ # else
105
+ # Forward::Client.cleanup_and_exit!('An error occured, please contact support@forwardhq.com')
106
+ # end
107
+ # end
109
108
 
110
109
  private
111
110
 
@@ -4,7 +4,7 @@ module Forward
4
4
 
5
5
  def self.create(options = {})
6
6
  resource = Tunnel.new(:create)
7
- resource.uri = '/api/tunnels'
7
+ resource.uri = '/api/v2/tunnels'
8
8
  params = {
9
9
  :hostport => options[:port],
10
10
  :vhost => options[:host],
@@ -15,35 +15,39 @@ module Forward
15
15
  params[param] = options[param] unless options[param].nil?
16
16
  end
17
17
 
18
- resource.post(params)
18
+ resource.post(params)[:tunnel].symbolize_keys
19
+ rescue ResourceError => e
20
+ error_on_create(e, options)
19
21
  end
20
22
 
21
23
  def self.index
22
24
  resource = Tunnel.new(:index)
23
- resource.uri = "/api/tunnels"
25
+ resource.uri = "/api/v2/tunnels"
24
26
 
25
- resource.get
27
+ resource.get[:tunnels]
26
28
  end
27
29
 
28
30
  def self.destroy(id)
29
31
  resource = Tunnel.new(:destroy)
30
- resource.uri = "/api/tunnels/#{id}"
32
+ resource.uri = "/api/v2/tunnels/#{id}"
31
33
 
32
34
  resource.delete
35
+ rescue ResourceError => e
36
+ nil
33
37
  end
34
38
 
35
39
  def self.show(id)
36
40
  resource = Tunnel.new(:show)
37
- resource.uri = "/api/tunnels/#{id}"
41
+ resource.uri = "/api/v2/tunnels/#{id}"
38
42
 
39
- resource.get
43
+ resource.get[:tunnel].symbolize_keys
40
44
  rescue Forward::Api::ResourceNotFound
41
45
  nil
42
46
  end
43
47
 
44
48
  private
45
49
 
46
- def self.ask_to_destroy(message)
50
+ def self.ask_to_destroy(message, options)
47
51
  tunnels = index
48
52
 
49
53
  puts message
@@ -51,49 +55,42 @@ module Forward
51
55
  menu.prompt = "Choose a tunnel from the list to close or `q' to exit forward "
52
56
 
53
57
  tunnels.each do |tunnel|
54
- text = "tunnel forwarding port #{tunnel['hostport']}"
55
- menu.choice(text) { destroy_and_create(tunnel['_id']) }
58
+ text = "Forwarding port #{tunnel['hostport']}"
59
+ menu.choice(text) { destroy_and_create(tunnel['_id'], options) }
56
60
  end
57
61
  menu.hidden('quit') { Forward::Client.cleanup_and_exit! }
58
62
  menu.hidden('exit') { Forward::Client.cleanup_and_exit! }
59
63
  end
60
64
  end
61
65
 
62
- def self.destroy_and_create(id)
66
+ def self.destroy_and_create(id, options)
63
67
  Forward.log(:debug, "Destroying tunnel: #{id}")
64
68
  destroy(id)
65
69
  puts "tunnel removed, now we're creating a new one"
66
- create(Forward.client.options)
70
+ create(options)
67
71
  end
68
72
 
69
- def self.create_error(errors)
70
- Forward.log(:debug, "An error occured creating tunnel:\n#{errors.inspect}")
71
- base_errors = errors['base']
73
+ def self.error_on_create(error, options)
74
+ Forward.log(:debug, "An error occured creating tunnel:\n#{error.inspect}")
72
75
 
73
- if base_errors && base_errors.any? { |e| e.include? 'limit' }
74
- message = base_errors.select { |e| e.include? 'limit' }.first
76
+ if error.type == 'tunnel_limit_reached'
75
77
  Forward.log(:debug, 'Tunnel limit reached')
76
- ask_to_destroy(message)
78
+ ask_to_destroy(error.api_message, options)
79
+ elsif error.type =~ /(?:account_suspended|trial_expired)/i
80
+ Forward::Client.cleanup_and_exit!(error.api_message)
77
81
  else
78
82
  message = "We were unable to create your tunnel for the following reasons: \n"
79
- errors.each do |key, value|
80
- if key != 'base'
81
- message << " #{key} #{value.join(', ')}\n"
82
- elsif key == 'base'
83
- base_errors.each do |error|
84
- message << " #{error}\n"
85
- end
83
+ error.errors.each do |key, value|
84
+ if key == 'base'
85
+ message << " #{value.join(', ')}\n"
86
+ else
87
+ value.each { |m| message << " #{key} #{m}\n"}
86
88
  end
87
89
  end
88
90
  Forward::Client.cleanup_and_exit!(message)
89
91
  end
90
92
  end
91
93
 
92
- def self.destroy_error(errors)
93
- # TODO: this is where we will tie into the logger
94
- nil
95
- end
96
-
97
94
  end
98
95
  end
99
96
  end
@@ -4,11 +4,13 @@ module Forward
4
4
 
5
5
  def self.create
6
6
  resource = TunnelKey.new(:create)
7
- resource.uri = '/api/tunnel_keys'
7
+ resource.uri = '/api/v2/tunnel_keys'
8
8
 
9
9
  response = resource.post
10
10
 
11
11
  response[:private_key]
12
+ rescue
13
+ Forward::Client.cleanup_and_exit!
12
14
  end
13
15
 
14
16
  end
@@ -4,13 +4,14 @@ module Forward
4
4
 
5
5
  def self.api_token(email, password)
6
6
  resource = User.new(:api_token)
7
- resource.uri = '/api/users/api_token'
7
+ resource.uri = '/api/v2/users/api_token'
8
8
  params = { :email => email, :password => password }
9
9
 
10
- resource.post(params)
11
- end
10
+ user = resource.post(params)[:user].symbolize_keys
11
+ user[:id] = user.delete(:_id)
12
12
 
13
- def self.api_token_error(errors)
13
+ user
14
+ rescue ResourceError => e
14
15
  Forward::Client.cleanup_and_exit!('Unable to authenticate with email and password')
15
16
  end
16
17
 
@@ -20,8 +20,9 @@ module Forward
20
20
  if @tunnel.id
21
21
  @tunnel.poll_status
22
22
  else
23
- cleanup_and_exit!('Unable to create a tunnel. If this continues contact support@forwardhq.com')
23
+ Forward::Client.cleanup_and_exit!('Unable to create a tunnel. If this continues contact support@forwardhq.com')
24
24
  end
25
+ Forward.log(:debug, "Tunnel setup: #{@tunnel.inspect}")
25
26
 
26
27
  @tunnel
27
28
  end
@@ -48,6 +49,23 @@ module Forward
48
49
  true
49
50
  end
50
51
 
52
+ def self.forwarding_message(tunnel)
53
+ remote = "\033[04mhttps://#{@tunnel.subdomain}.fwd.wf\033[0m"
54
+
55
+ unless tunnel.cname.nil? || tunnel.cname.empty?
56
+ remote << " and \033[04mhttp://#{@tunnel.cname}\033[0m"
57
+ end
58
+
59
+ if !tunnel.vhost.nil? && tunnel.vhost !~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/
60
+ local = tunnel.vhost
61
+ local << " port #{tunnel.hostport}" unless tunnel.hostport.to_i == 80
62
+ else
63
+ local = "port #{tunnel.hostport}"
64
+ end
65
+
66
+ "Forwarding #{local} to #{remote}\nCtrl-C to stop forwarding"
67
+ end
68
+
51
69
  def self.start(options = {})
52
70
  Forward.log(:debug, 'Starting client')
53
71
  trap(:INT) { cleanup_and_exit!('closing tunnel and exiting...') }
@@ -56,8 +74,9 @@ module Forward
56
74
  @tunnel = @client.setup_tunnel
57
75
  @session = Net::SSH.start(@tunnel.tunneler, Forward.ssh_user, @client.ssh_options)
58
76
 
59
- Forward.log(:debug, "Starting remote forward at #{@tunnel.subdomain}.fwd.wf on port #{@tunnel.port}")
60
- puts "Forwarding port #{@tunnel.hostport} at \033[04mhttps://#{@tunnel.subdomain}.fwd.wf\033[0m\nCtrl-C to stop forwarding"
77
+ Forward.log(:debug, "Starting remote forward at #{@tunnel.subdomain}.fwd.wf")
78
+ # puts "Forwarding port #{@tunnel.hostport} at \033[04mhttps://#{@tunnel.subdomain}.fwd.wf\033[0m\nCtrl-C to stop forwarding"
79
+ puts forwarding_message(@tunnel)
61
80
 
62
81
  @session.forward.remote(@tunnel.hostport, @tunnel.host, @tunnel.port)
63
82
  @session.loop { watch_session(@session) }
@@ -2,20 +2,24 @@ module Forward
2
2
  class Tunnel
3
3
  CHECK_INTERVAL = 7
4
4
 
5
- # The Tunnel resource ID.
5
+ # The Tunnel resource ID
6
6
  attr_reader :id
7
- # The domain for the Tunnel.
7
+ # The domain for the Tunnel
8
8
  attr_reader :subdomain
9
+ # The CNAME for the Tunnel
10
+ attr_reader :cname
9
11
  # The host
10
12
  attr_reader :host
11
13
  # The vhost
12
14
  attr_reader :vhost
13
15
  # The hostport (local port)
14
16
  attr_reader :hostport
15
- # The remote port.
17
+ # The remote port
16
18
  attr_reader :port
17
- # The tunneler host.
19
+ # The tunneler host
18
20
  attr_reader :tunneler
21
+ # The timeout
22
+ attr_reader :timeout
19
23
  # The amount of time in seconds the Tunnel has be inactive for
20
24
  attr_accessor :inactive_for
21
25
 
@@ -28,6 +32,7 @@ module Forward
28
32
  @response = Forward::Api::Tunnel.create(options)
29
33
  @id = @response[:_id]
30
34
  @subdomain = @response[:subdomain]
35
+ @cname = @response[:cname]
31
36
  @vhost = @response[:vhost]
32
37
  @hostport = @response[:hostport]
33
38
  @port = @response[:port]
@@ -1,3 +1,3 @@
1
1
  module Forward
2
- VERSION = '0.1.6'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -6,19 +6,19 @@ describe Forward::Api::TunnelKey do
6
6
  FakeWeb.allow_net_connect = false
7
7
  end
8
8
 
9
- it 'retrieves the public_key and returns it' do
9
+ it "retrieves the public_key and returns it" do
10
10
  fake_body = { :private_key => 'ssh-key 1234567890' }
11
11
 
12
- stub_api_request(:post, '/api/tunnel_keys', :body => fake_body.to_json)
12
+ stub_api_request(:post, '/api/v2/tunnel_keys', :body => fake_body.to_json)
13
13
 
14
14
  response = Api::TunnelKey.create
15
15
  response.must_equal fake_body[:private_key]
16
16
  end
17
17
 
18
- it 'exits with message if response has errors' do
19
- fake_body = { :errors => { :base => 'Unable to retrieve a private key' } }
18
+ it "exits with message if response has errors" do
19
+ fake_body = { :type => 'api_error' }
20
20
 
21
- stub_api_request(:post, '/api/tunnel_keys', :body => fake_body.to_json)
21
+ stub_api_request(:post, '/api/v2/tunnel_keys', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
22
22
 
23
23
  lambda {
24
24
  dev_null { Api::TunnelKey.create }
@@ -7,66 +7,104 @@ describe Forward::Api::Tunnel do
7
7
  Forward::Api.token = 'abc123'
8
8
  end
9
9
 
10
- it 'creates a tunnel and returns the attributes' do
11
- Forward.client = mock
12
- fake_body = { :_id => '1', :subdomain => 'foo', :port => 56789 }
10
+ it "creates a tunnel and returns the attributes" do
11
+ fake_body = { :tunnel => { :_id => '1', :subdomain => 'foo', :port => 56789 }}
13
12
 
14
- stub_api_request(:post, '/api/tunnels', :body => fake_body.to_json)
13
+ stub_api_request(:post, '/api/v2/tunnels', :body => fake_body.to_json)
15
14
 
16
15
  response = Forward::Api::Tunnel.create(:port => 3000)
17
16
 
18
- fake_body.each do |key, value|
19
- response[key].must_equal fake_body[key]
20
- end
17
+ response[:_id].must_equal fake_body[:tunnel][:_id]
18
+ response[:subdomain].must_equal fake_body[:tunnel][:subdomain]
19
+ response[:port].must_equal fake_body[:tunnel][:port]
21
20
  end
22
21
 
23
- it 'exits with message if create response has errors' do
24
- Forward.client = mock
25
- fake_body = { :errors => { :base => [ 'unable to create tunnel' ] } }
26
-
27
- stub_api_request(:post, '/api/tunnels', :body => fake_body.to_json)
28
-
29
- lambda {
30
- dev_null { Forward::Api::Tunnel.create(:port => 3000) }
31
- }.must_raise SystemExit
22
+ it "exits with message if create response is a resource_error" do
23
+ fake_body = {
24
+ :type => 'resource_error',
25
+ :errors => {
26
+ :base => [ 'did not work '],
27
+ :subdomain => [ 'is invalid', 'is too short' ]
28
+ }
29
+ }
30
+
31
+ stub_api_request(:post, '/api/v2/tunnels', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
32
+
33
+ out, err = capture_io do
34
+ begin
35
+ Forward::Api::Tunnel.create(:port => 3000)
36
+ rescue SystemExit; end
37
+ end
38
+ out.must_match /did not work/i
39
+ out.must_match /subdomain is invalid/i
40
+ out.must_match /subdomain is too short/i
32
41
  end
33
42
 
34
- it 'gives a choice and closes a tunnel if limit is reached' do
35
- Forward.client = mock
36
- post_options = [
37
- { :body => { :errors => { :base => [ 'you have reached your limit' ] } }.to_json },
38
- { :body => { :_id => '1', :subdomain => 'foo', :port => 56789 }.to_json }
39
- ]
40
- index_body = [ { :_id => 'abc123' }, { :_id => 'def456' } ]
43
+ it "exits with message if trial has expired" do
44
+ fake_body = {
45
+ :type => 'trial_expired',
46
+ :message => 'your trial has expired'
47
+ }
48
+
49
+ stub_api_request(:post, '/api/v2/tunnels', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
50
+
51
+ out, err = capture_io do
52
+ begin
53
+ Forward::Api::Tunnel.create(:port => 3000)
54
+ rescue SystemExit; end
55
+ end
56
+ out.must_match /trial has expired/i
57
+ end
58
+
59
+ it "exits with message if account has been suspended" do
60
+ fake_body = {
61
+ :type => 'account_suspended',
62
+ :message => 'your account has been suspended due for failed payment'
63
+ }
64
+
65
+ stub_api_request(:post, '/api/v2/tunnels', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
66
+
67
+ out, err = capture_io do
68
+ begin
69
+ Forward::Api::Tunnel.create(:port => 3000)
70
+ rescue SystemExit; end
71
+ end
72
+ out.must_match /account has been suspended/i
73
+ end
74
+
75
+ it "gives a choice and closes a tunnel if limit is reached" do
76
+ post_options = [
77
+ { :body => { :type => 'tunnel_limit_reached', :message => 'you have reached your limit' }.to_json, :status => [ 422, 'Unprocessable Entity' ] },
78
+ { :body => { :tunnel => { :_id => '1', :subdomain => 'foo', :port => 56789 } }.to_json }
79
+ ]
80
+ index_body = { :tunnels => [ { :_id => 'abc123', :hostport => 1234 }, { :_id => 'def456', :hostport => 1235 } ] }
41
81
 
42
- stub_api_request(:post, '/api/tunnels', post_options)
43
- stub_api_request(:get, '/api/tunnels', :body => index_body.to_json)
44
- STDIN.expects(:gets).returns('1')
45
- Forward::Api::Tunnel.expects(:destroy).with(index_body.first[:_id])
82
+ stub_api_request(:post, '/api/v2/tunnels', post_options)
83
+ stub_api_request(:get, '/api/v2/tunnels', :body => index_body.to_json)
84
+ STDIN.expects(:gets).returns('1')
85
+ Forward::Api::Tunnel.expects(:destroy).with(index_body[:tunnels].first[:_id])
46
86
 
47
- dev_null { Forward::Api::Tunnel.create(:port => 3000) }
48
- end
87
+ dev_null { Forward::Api::Tunnel.create(:port => 3000) }
88
+ end
49
89
 
50
- it 'destroys a tunnel and returns the attributes' do
51
- Forward.client = mock
52
- fake_body = { :_id => '1', :subdomain => 'foo', :port => 56789 }
90
+ it 'destroys a tunnel and returns the attributes' do
91
+ fake_body = { :_id => '1', :subdomain => 'foo', :port => 56789 }
53
92
 
54
- stub_api_request(:delete, '/api/tunnels/1', :body => fake_body.to_json)
93
+ stub_api_request(:delete, '/api/v2/tunnels/1', :body => fake_body.to_json)
55
94
 
56
- response = Forward::Api::Tunnel.destroy(1)
95
+ response = Forward::Api::Tunnel.destroy(1)
57
96
 
58
- fake_body.each do |key, value|
59
- response[key].must_equal fake_body[key]
60
- end
61
- end
97
+ fake_body.each do |key, value|
98
+ response[key].must_equal fake_body[key]
99
+ end
100
+ end
62
101
 
63
- it 'gracefully handles the error if destroy has errors' do
64
- Forward.client = mock
65
- fake_body = { :errors => { :base => 'unable to create tunnel' } }
102
+ it 'gracefully handles the error if destroy has errors' do
103
+ fake_body = { :type => 'api_error' }
66
104
 
67
- stub_api_request(:delete, '/api/tunnels/1', :body => fake_body.to_json)
105
+ stub_api_request(:delete, '/api/v2/tunnels/1', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
68
106
 
69
- Forward::Api::Tunnel.destroy(1).must_be_nil
70
- end
107
+ Forward::Api::Tunnel.destroy(1).must_be_nil
108
+ end
71
109
 
72
110
  end
@@ -6,19 +6,32 @@ describe Forward::Api::User do
6
6
  FakeWeb.allow_net_connect = false
7
7
  end
8
8
 
9
- it 'retrieves the users api token and returns it' do
10
- fake_body = { :api_token => '123abc' }
9
+ it "retrieves the users api token and returns it" do
10
+ fake_body = { :user => { :api_token => '123abc' } }
11
11
 
12
- stub_api_request(:post, '/api/users/api_token', :body => fake_body.to_json)
12
+ stub_api_request(:post, '/api/v2/users/api_token', :body => fake_body.to_json)
13
13
 
14
14
  response = Api::User.api_token('guy@example.com', 'secret')
15
15
  response[:api_token].must_equal '123abc'
16
16
  end
17
17
 
18
- it 'exits with message if response has errors' do
19
- fake_body = { :errors => { :base => 'Unable to authenticate user' } }
18
+ it "exits with message if authentication fails" do
19
+ fake_body = { :type => 'api_error' }
20
20
 
21
- stub_api_request(:post, '/api/users/api_token', :body => fake_body.to_json)
21
+ stub_api_request(:post, '/api/v2/users/api_token', :body => fake_body.to_json, :status => [ 401, 'Authentication Failed' ])
22
+
23
+ out, err = capture_io do
24
+ begin
25
+ Api::User.api_token('guy@example.com', 'secret')
26
+ rescue SystemExit; end
27
+ end
28
+ out.must_match /unable to authenticate/i
29
+ end
30
+
31
+ it "exits with message if response has errors" do
32
+ fake_body = { :type => 'api_error' }
33
+
34
+ stub_api_request(:post, '/api/v2/users/api_token', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
22
35
 
23
36
  lambda {
24
37
  dev_null { Api::User.api_token('guy@example.com', 'secret') }
@@ -2,7 +2,28 @@ require 'test_helper'
2
2
 
3
3
  describe Forward::Tunnel do
4
4
 
5
- it 'should have access to api resources via the api method ' do
5
+ it "create a tunnel instance" do
6
+ tunnel_response = {
7
+ :_id => '1234',
8
+ :subdomain => 'foo',
9
+ :cname => 'foo.bar.com',
10
+ :vhost => '127.0.0.1',
11
+ :hostport => '3000',
12
+ :port => 20000,
13
+ :tunneler_public => 'test.forwardhq.com',
14
+ :timeout => 0
15
+ }
6
16
 
17
+ Forward::Api::Tunnel.expects(:create).returns(tunnel_response)
18
+ tunnel = Forward::Tunnel.new
19
+
20
+ tunnel.id.must_equal tunnel_response[:_id]
21
+ tunnel.subdomain.must_equal tunnel_response[:subdomain]
22
+ tunnel.cname.must_equal tunnel_response[:cname]
23
+ tunnel.vhost.must_equal tunnel_response[:vhost]
24
+ tunnel.hostport.must_equal tunnel_response[:hostport]
25
+ tunnel.port.must_equal tunnel_response[:port]
26
+ tunnel.tunneler.must_equal tunnel_response[:tunneler_public]
27
+ tunnel.timeout.must_equal tunnel_response[:timeout]
7
28
  end
8
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forward
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-18 00:00:00.000000000 Z
12
+ date: 2012-12-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json