forward 0.3.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/Gemfile +0 -2
  4. data/README.md +24 -0
  5. data/Rakefile +3 -1
  6. data/bin/forward +1 -1
  7. data/forward.gemspec +17 -11
  8. data/lib/forward/api/resource.rb +51 -83
  9. data/lib/forward/api/tunnel.rb +41 -68
  10. data/lib/forward/api/user.rb +14 -11
  11. data/lib/forward/api.rb +7 -26
  12. data/lib/forward/cli.rb +55 -253
  13. data/lib/forward/command/account.rb +69 -0
  14. data/lib/forward/command/base.rb +62 -0
  15. data/lib/forward/command/config.rb +64 -0
  16. data/lib/forward/command/tunnel.rb +178 -0
  17. data/lib/forward/common.rb +44 -0
  18. data/lib/forward/config.rb +75 -118
  19. data/lib/forward/request.rb +72 -0
  20. data/lib/forward/socket.rb +125 -0
  21. data/lib/forward/static/app.rb +157 -0
  22. data/lib/forward/static/directory.erb +142 -0
  23. data/lib/forward/tunnel.rb +102 -40
  24. data/lib/forward/version.rb +1 -1
  25. data/lib/forward.rb +80 -63
  26. data/test/api/resource_test.rb +70 -54
  27. data/test/api/tunnel_test.rb +50 -51
  28. data/test/api/user_test.rb +33 -20
  29. data/test/cli_test.rb +0 -126
  30. data/test/command/account_test.rb +26 -0
  31. data/test/command/tunnel_test.rb +133 -0
  32. data/test/config_test.rb +103 -54
  33. data/test/forward_test.rb +47 -0
  34. data/test/test_helper.rb +35 -26
  35. data/test/tunnel_test.rb +50 -22
  36. metadata +210 -169
  37. data/forwardhq.crt +0 -112
  38. data/lib/forward/api/client_log.rb +0 -20
  39. data/lib/forward/api/tunnel_key.rb +0 -18
  40. data/lib/forward/client.rb +0 -110
  41. data/lib/forward/error.rb +0 -12
  42. data/test/api/tunnel_key_test.rb +0 -28
  43. data/test/api_test.rb +0 -0
  44. data/test/client_test.rb +0 -8
@@ -1,82 +1,98 @@
1
1
  require 'test_helper'
2
2
 
3
- describe Forward::Api::Resource do
4
- Api = Forward::Api
5
-
3
+ describe Forward::API::Resource do
6
4
  before :each do
7
- Api.token = 'abc123'
5
+ Forward::Config.accounts = { foo: 'abc123' }
6
+ Forward::Config.default_account = :foo
8
7
  end
9
8
 
10
9
  it 'builds http requests based on given method' do
11
- resource = Api::Resource.new
12
- resource.uri = '/path'
10
+ resource = Forward::API::Resource.new
13
11
 
14
- [ :get, :post, :put, :delete ].each do |method|
15
- resource.build_request(method)
16
- klass = eval("Net::HTTP::#{method.capitalize}")
17
- request = resource.instance_variable_get('@request')
12
+ [ :get, :post, :delete ].each do |method|
13
+ options = {}
18
14
 
19
- request.kind_of?(klass).must_equal true
15
+ resource.expects(:request).with(method, options)
16
+ resource.send(method, options)
20
17
  end
21
18
  end
22
19
 
23
- it 'builds http requests with json bodies' do
24
- resource = Api::Resource.new
25
- resource.uri = '/path'
20
+ it "adds json headers to every request" do
21
+ resource = Forward::API::Resource.new
22
+ headers = {
23
+ 'Accept' => 'application/json',
24
+ 'Content-Type' => 'application/json'
25
+ }
26
26
 
27
- [ :post, :put, :delete ].each do |method|
28
- params = { :foo => 'bar '}
29
- resource.build_request(method, params)
30
- klass = eval("Net::HTTP::#{method.capitalize}")
31
- request = resource.instance_variable_get('@request')
27
+ stub_request(:get, 'localhost/').
28
+ with(headers: headers).
29
+ to_return(status: 200)
32
30
 
33
- request.kind_of?(klass).must_equal true
34
- request.body.must_equal params.to_json
35
- end
31
+ EM.run_block {
32
+ Forward::API::Resource.new.get(path: '/') {}
33
+ }
36
34
  end
37
35
 
38
- it 'adds auth and json headers to the request' do
39
- resource = Api::Resource.new
40
- resource.uri = '/path'
41
- resource.build_request(:post)
42
- resource.add_headers!
43
- request = resource.instance_variable_get('@request')
44
-
45
- request['Authorization'].must_equal "Token token=#{Api.token}"
46
- request['Content-Type'].must_equal 'application/json'
47
- request['Accept'].must_equal 'application/json'
36
+ it "adds auth header if request is authenticated" do
37
+ resource = Forward::API::Resource.new
38
+ headers = {
39
+ 'Accept' => 'application/json',
40
+ 'Authorization' => 'Token token=abc123',
41
+ 'Content-Type' => 'application/json'
42
+ }
43
+
44
+ stub_request(:get, 'localhost/').
45
+ with(headers: headers).
46
+ to_return(status: 200)
47
+
48
+ EM.run_block {
49
+ Forward::API::Resource.new.get(path: '/', authenticated: true) {}
50
+ }
48
51
  end
49
52
 
53
+ it "adds a json body if params given" do
54
+ resource = Forward::API::Resource.new
55
+ params = { foo: 'bar' }
50
56
 
51
- it 'raises an error if the response code is not 200' do
52
- resource = Api::Resource.new
53
- response = mock
54
- response.stubs(:code).returns(403)
55
- response.stubs(:body)
57
+ stub_request(:post, 'localhost/').
58
+ with(body: params.to_json).
59
+ to_return(status: 200)
56
60
 
57
- lambda { resource.parse_response(response) }.must_raise Api::BadResponse
61
+ EM.run_block {
62
+ Forward::API::Resource.new.post(path: '/', params: params) {}
63
+ }
58
64
  end
59
65
 
60
- it 'raises an error if the response is not json' do
61
- resource = Api::Resource.new
62
- response = mock
63
- response.stubs(:code).returns(200)
64
- response.stubs(:body)
65
- response.stubs(:[]).with('content-type').returns('text/html')
66
+ it "exits with message if status is 401" do
67
+ resource = Forward::API::Resource.new
68
+
69
+ stub_request(:get, 'localhost/').
70
+ to_return(status: 401)
66
71
 
67
- lambda { resource.parse_response(response) }.must_raise Api::BadResponse
72
+ out, err = capture_io do
73
+ begin
74
+ EM.run_block {
75
+ Forward::API::Resource.new.get(path: '/') {}
76
+ }
77
+ rescue SystemExit; end
78
+ end
79
+ out.must_match /Unable to authenticate/i
68
80
  end
69
81
 
70
- it 'parses a json response' do
71
- resource = Api::Resource.new
72
- response = mock
73
- response.stubs(:code).returns(200)
74
- response.stubs(:[]).with('content-type').returns('application/json')
75
- response.stubs(:body).returns('{ "foo": "bar" }')
82
+ it "exits with message if response is invalid JSON" do
83
+ resource = Forward::API::Resource.new
84
+
85
+ stub_request(:get, 'localhost/').
86
+ to_return(status: 200, body: '{"foo"}')
76
87
 
77
- json = resource.parse_response(response)
78
- json.kind_of?(Hash).must_equal true
79
- json[:foo].must_equal 'bar'
88
+ out, err = capture_io do
89
+ begin
90
+ EM.run_block {
91
+ Forward::API::Resource.new.get(path: '/') {}
92
+ }
93
+ rescue SystemExit; end
94
+ end
95
+ out.must_match /Unable to connect to API/i
80
96
  end
81
97
 
82
98
  end
@@ -1,90 +1,89 @@
1
1
  require 'test_helper'
2
2
 
3
- describe Forward::Api::Tunnel do
3
+ describe Forward::API::Tunnel do
4
4
 
5
5
  before :each do
6
- FakeWeb.allow_net_connect = false
7
- Forward::Api.token = 'abc123'
6
+ Forward::Config.accounts = { foo: 'abc123' }
7
+ Forward::Config.default_account = :foo
8
8
  end
9
9
 
10
10
  it "creates a tunnel and returns the attributes" do
11
- fake_body = { :tunnel => { :_id => '1', :subdomain => 'foo', :port => 56789 }}
12
-
13
- stub_api_request(:post, '/api/v2/tunnels', :body => fake_body.to_json)
11
+ tunnel_options = { port: '3000', host: 'localhost' }
12
+ params = {
13
+ hostport: tunnel_options[:port],
14
+ vhost: tunnel_options[:host],
15
+ subdomain: nil, cname: nil,
16
+ username: nil, password: nil, no_auth: nil,
17
+ client: Forward.client_string,
18
+ }
19
+ body = { tunnel: { _id: '1', subdomain: 'foo', port: 56789 }}
14
20
 
15
- response = Forward::Api::Tunnel.create(:port => 3000)
21
+ stub_request(:post, 'localhost/api/v3/tunnels/').
22
+ with(body: params.to_json).
23
+ to_return(status: 200, body: body.to_json)
16
24
 
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]
25
+ EM.run_block {
26
+ Forward::API::Tunnel.create(tunnel_options) do |tunnel|
27
+ tunnel[:id].must_equal body[:id]
28
+ tunnel[:subdomain].must_equal body[:subdomain]
29
+ tunnel[:port].must_equal body[:port]
30
+ end
31
+ }
20
32
  end
21
33
 
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
- }
34
+ it "exits with message on 422" do
35
+ tunnel_options = { port: '3000', host: 'localhost' }
30
36
 
31
- stub_api_request(:post, '/api/v2/tunnels', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
37
+ stub_request(:post, 'localhost/api/v3/tunnels/').
38
+ to_return(status: 422)
32
39
 
33
40
  out, err = capture_io do
34
41
  begin
35
- Forward::Api::Tunnel.create(:port => 3000)
42
+ EM.run_block {
43
+ Forward::API::Tunnel.create(tunnel_options) { }
44
+ }
36
45
  rescue SystemExit; end
37
46
  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
47
+ out.must_match /unable to allocate tunnel/i
41
48
  end
42
49
 
43
- it "exits with message if trial has expired" do
44
- fake_body = {
45
- :type => 'trial_expired',
46
- :message => 'your trial has expired'
50
+ it "exits with message and displays account errors" do
51
+ tunnel_options = { port: '3000', host: 'localhost' }
52
+ body = {
53
+ type: 'account_error',
54
+ errors: { account: ['Trial has expired'] }
47
55
  }
48
56
 
49
- stub_api_request(:post, '/api/v2/tunnels', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
57
+ stub_request(:post, 'localhost/api/v3/tunnels/').
58
+ to_return(status: 422, body: body.to_json)
50
59
 
51
60
  out, err = capture_io do
52
61
  begin
53
- Forward::Api::Tunnel.create(:port => 3000)
62
+ EM.run_block {
63
+ Forward::API::Tunnel.create(tunnel_options) { }
64
+ }
54
65
  rescue SystemExit; end
55
66
  end
56
67
  out.must_match /trial has expired/i
57
68
  end
58
69
 
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'
70
+ it "exits with message on bad tunnel data" do
71
+ tunnel_options = { port: '3000', host: 'localhost' }
72
+ body = {
73
+ type: 'invalid_request_error'
63
74
  }
64
75
 
65
- stub_api_request(:post, '/api/v2/tunnels', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
76
+ stub_request(:post, 'localhost/api/v3/tunnels/').
77
+ to_return(status: 422, body: body.to_json)
66
78
 
67
79
  out, err = capture_io do
68
80
  begin
69
- Forward::Api::Tunnel.create(:port => 3000)
81
+ EM.run_block {
82
+ Forward::API::Tunnel.create(tunnel_options) { }
83
+ }
70
84
  rescue SystemExit; end
71
85
  end
72
- out.must_match /account has been suspended/i
86
+ out.must_match /invalid tunnel parameters/i
73
87
  end
74
88
 
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 } ] }
81
-
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])
86
-
87
- dev_null { Forward::Api::Tunnel.create(:port => 3000) }
88
- end
89
-
90
89
  end
@@ -1,41 +1,54 @@
1
1
  require 'test_helper'
2
2
 
3
- describe Forward::Api::User do
4
-
5
- before :each do
6
- FakeWeb.allow_net_connect = false
7
- end
3
+ describe Forward::API::User do
8
4
 
9
5
  it "retrieves the users api token and returns it" do
10
- fake_body = { :user => { :api_token => '123abc' } }
11
-
12
- stub_api_request(:post, '/api/v2/users/api_token', :body => fake_body.to_json)
13
-
14
- response = Api::User.api_token('guy@example.com', 'secret')
15
- response[:api_token].must_equal '123abc'
6
+ params = { email: 'guy@example.com', password: 'secret' }
7
+ body = { subdomain: 'fooco', token: '123abc' }
8
+
9
+ stub_request(:post, 'localhost/api/v3/user/token').
10
+ with(body: params.to_json).
11
+ to_return(status: 200, body: body.to_json)
12
+
13
+ EM.run_block {
14
+ Forward::API::User.authenticate(params[:email], params[:password]) do |subdomain, token|
15
+ token.must_equal '123abc'
16
+ end
17
+ }
16
18
  end
17
19
 
18
20
  it "exits with message if authentication fails" do
19
- fake_body = { :type => 'api_error' }
21
+ params = { email: 'guy@example.com', password: 'secret' }
20
22
 
21
- stub_api_request(:post, '/api/v2/users/api_token', :body => fake_body.to_json, :status => [ 401, 'Authentication Failed' ])
23
+ stub_request(:post, 'localhost/api/v3/user/token').
24
+ with(body: params.to_json).
25
+ to_return(status: 401)
22
26
 
23
27
  out, err = capture_io do
24
28
  begin
25
- Api::User.api_token('guy@example.com', 'secret')
29
+ EM.run_block {
30
+ Forward::API::User.authenticate(params[:email], params[:password]) {}
31
+ }
26
32
  rescue SystemExit; end
27
33
  end
28
- out.must_match /unable to authenticate/i
34
+ out.must_match /Unable to authenticate/i
29
35
  end
30
36
 
31
37
  it "exits with message if response has errors" do
32
- fake_body = { :type => 'api_error' }
38
+ params = { email: 'guy@example.com', password: 'secret' }
33
39
 
34
- stub_api_request(:post, '/api/v2/users/api_token', :body => fake_body.to_json, :status => [ 422, 'Unprocessable Entity' ])
40
+ stub_request(:post, 'localhost/api/v3/user/token').
41
+ with(body: params.to_json).
42
+ to_return(status: 422)
35
43
 
36
- lambda {
37
- dev_null { Api::User.api_token('guy@example.com', 'secret') }
38
- }.must_raise SystemExit
44
+ out, err = capture_io do
45
+ begin
46
+ EM.run_block {
47
+ Forward::API::User.authenticate(params[:email], params[:password]) {}
48
+ }
49
+ rescue SystemExit; end
50
+ end
51
+ out.must_match /Unable to authenticate/i
39
52
  end
40
53
 
41
54
  end
data/test/cli_test.rb CHANGED
@@ -2,130 +2,4 @@ require 'test_helper'
2
2
 
3
3
  describe Forward::CLI do
4
4
 
5
- it 'parses a forwarded port' do
6
- forwarded = Forward::CLI.parse_forwarded('600')
7
- forwarded.has_key?(:port).must_equal true
8
- forwarded[:port].must_equal 600
9
- end
10
-
11
- it 'parses a forwarded host' do
12
- forwarded = Forward::CLI.parse_forwarded('mysite.dev')
13
- forwarded.has_key?(:host).must_equal true
14
- forwarded[:host].must_equal 'mysite.dev'
15
- end
16
-
17
- it 'parses a forwarded host and port' do
18
- forwarded = Forward::CLI.parse_forwarded('mysite.dev:88')
19
- forwarded.has_key?(:host).must_equal true
20
- forwarded.has_key?(:port).must_equal true
21
- forwarded[:host].must_equal 'mysite.dev'
22
- forwarded[:port].must_equal 88
23
- end
24
-
25
- it 'exits if username is invalid' do
26
- [ 'foo ', ' asdfasdf ', 'fooo bar' ].each do |username|
27
- lambda {
28
- dev_null { Forward::CLI.validate_username(username) }
29
- }.must_raise SystemExit
30
- end
31
- end
32
-
33
- it 'validates a good username' do
34
- [ 'foo', 'asdflkj3r&)(#@#)', 'DF#R::#SFSDF' ].each do |username|
35
- Forward::CLI.validate_username(username).must_be_nil
36
- end
37
- end
38
-
39
- it 'exits if password is invalid' do
40
- [ 'foo ', ' asdfasdf ', 'fooo bar' ].each do |password|
41
- lambda {
42
- dev_null { Forward::CLI.validate_password(password) }
43
- }.must_raise SystemExit
44
- end
45
- end
46
-
47
- it 'validates a good password' do
48
- [ 'foo', 'asdflkj3r&)(#@#)', 'DF#R::#SFSDF' ].each do |password|
49
- Forward::CLI.validate_password(password).must_be_nil
50
- end
51
- end
52
-
53
- it 'parses a Forwardfile' do
54
- hash_to_forwardfile(:auth => 'username:password')
55
-
56
- options = Forward::CLI.parse_forwardfile
57
- options.has_key?(:auth).must_equal true
58
- end
59
-
60
- it 'exits if a Forwardfile does not parse to a Hash' do
61
- hash_to_forwardfile('username:password')
62
-
63
- lambda {
64
- dev_null { Forward::CLI.parse_forwardfile }
65
- }.must_raise SystemExit
66
- end
67
-
68
- it 'overloads Forwardfile options via commandline options' do
69
- hash_to_forwardfile(
70
- :port => 8000,
71
- :username => 'username',
72
- :password => 'password',
73
- :subdomain_prefix => 'foo'
74
- )
75
- args = [ '3000', '-a', 'example:secret', 'bar' ]
76
- options = Forward::CLI.parse_args_and_options(args)
77
-
78
- options[:port].must_equal 3000
79
- options[:username].must_equal 'example'
80
- options[:password].must_equal 'secret'
81
- options[:subdomain_prefix].must_equal 'bar'
82
- end
83
-
84
- it 'doesnt exit on valid ports' do
85
- Forward::CLI.validate_port(69).must_be_nil
86
- Forward::CLI.validate_port(3000).must_be_nil
87
- Forward::CLI.validate_port(65535).must_be_nil
88
- end
89
-
90
- it 'validates port and exits if invalid' do
91
- [ 0, 65536 ].each do |port|
92
- lambda {
93
- dev_null { Forward::CLI.validate_port(port) }
94
- }.must_raise SystemExit
95
- end
96
- end
97
-
98
- it 'doesnt exit on valid cnames' do
99
- [ 'foo.com', 'whatever-foo.com', 'www.foo.com', 'asdf.asdf.asdf.com' ].each do |cname|
100
- Forward::CLI.validate_cname(cname).must_be_nil
101
- end
102
- end
103
-
104
- it 'validates cname and exits if invalid' do
105
- [ 'whatever', 'asdfasdf.', '-asdf', 'adsf#$).com' ].each do |cname|
106
- lambda {
107
- dev_null { Forward::CLI.validate_cname(cname) }
108
- }.must_raise SystemExit
109
- end
110
- end
111
-
112
- it 'doesnt exit on valid subdomains prefix' do
113
- [ 'foo', 'whatever-foo', 'asdf40' ].each do |subdomain|
114
- Forward::CLI.validate_subdomain_prefix(subdomain).must_be_nil
115
- end
116
- end
117
-
118
- it 'validates subdomain prefix and exits if invalid' do
119
- [ '-asdf', 'adsf#$)' ].each do |subdomain|
120
- lambda {
121
- dev_null { Forward::CLI.validate_subdomain_prefix(subdomain) }
122
- }.must_raise SystemExit
123
- end
124
- end
125
-
126
- end
127
-
128
- def hash_to_forwardfile(hash)
129
- yaml = YAML.dump(hash)
130
- File.open('Forwardfile', 'w') { |f| f.write(yaml) }
131
5
  end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ describe Forward::Command::Account do
4
+ before :each do
5
+ FakeFS.activate!
6
+ FileUtils.mkdir_p(ENV['HOME'])
7
+ end
8
+
9
+ after :each do
10
+ FileUtils.rm_rf(ENV['HOME'])
11
+ FakeFS.deactivate!
12
+ end
13
+
14
+ it "logs a client in with a provided email" do
15
+ email = 'foo@example.com'
16
+ password = 'bar'
17
+ command = Forward::Command::Account.new({}, [email])
18
+
19
+ Forward::API::User.expects(:authenticate).with(email, password)
20
+ command.expects(:ask_for_credentials).with(email).returns([email, password])
21
+
22
+ EM.run_block {
23
+ command.login
24
+ }
25
+ end
26
+ end
@@ -0,0 +1,133 @@
1
+ require 'test_helper'
2
+
3
+ describe Forward::Command::Tunnel do
4
+ before :each do
5
+ FakeFS.activate!
6
+ FileUtils.mkdir_p(ENV['HOME'])
7
+ end
8
+
9
+ after :each do
10
+ FileUtils.rm_rf(ENV['HOME'])
11
+ FakeFS.deactivate!
12
+ end
13
+
14
+ it 'parses a forwarded port' do
15
+ command = Forward::Command::Tunnel.new({}, ['600'])
16
+
17
+ command.send(:parse_forwarded)
18
+ command.options[:port].must_equal 600
19
+ end
20
+
21
+ it 'parses a forwarded host' do
22
+ command = Forward::Command::Tunnel.new({}, ['mysite.dev'])
23
+
24
+ command.send(:parse_forwarded)
25
+ command.options[:host].must_equal 'mysite.dev'
26
+ end
27
+
28
+ it 'parses a forwarded host and port' do
29
+ command = Forward::Command::Tunnel.new({}, ['mysite.dev:8888'])
30
+
31
+ command.send(:parse_forwarded)
32
+ command.options[:host].must_equal 'mysite.dev'
33
+ command.options[:port].must_equal 8888
34
+ end
35
+
36
+ it 'exits if auth pair is invalid' do
37
+ [ 'as:df:asdf', 'fooo bar', 'foo oo:bar' ].each do |auth|
38
+ lambda {
39
+ dev_null {
40
+ command = Forward::Command::Tunnel.new(auth: auth)
41
+ command.send(:validate_auth)
42
+ }
43
+ }.must_raise Forward::CLIError
44
+ end
45
+ end
46
+
47
+ it 'validates a auth pair' do
48
+ [ 'foo:asdflkj3r&)', 'tom:#SFSDF' ].each do |auth|
49
+ command = Forward::Command::Tunnel.new(auth: auth)
50
+ command.send(:validate_auth)
51
+ end
52
+ end
53
+
54
+ it 'parses a Forwardfile' do
55
+ hash_to_forwardfile(auth: 'username:password')
56
+
57
+ command = Forward::Command::Tunnel.new
58
+ command.send(:parse_forwardfile)
59
+ command.options[:auth].must_equal 'username:password'
60
+ end
61
+
62
+ it 'exits if a Forwardfile does not parse to a Hash' do
63
+ hash_to_forwardfile('username:password')
64
+
65
+ lambda {
66
+ dev_null { Forward::Command::Tunnel.new.send(:parse_forwardfile) }
67
+ }.must_raise SystemExit
68
+ end
69
+
70
+ it 'overloads Forwardfile options via commandline options' do
71
+ hash_to_forwardfile(
72
+ port: 8000,
73
+ username: 'username',
74
+ password: 'password',
75
+ subdomain_prefix: 'foo'
76
+ )
77
+
78
+ EM.expects(:run)
79
+
80
+ command = Forward::Command::Tunnel.new({auth: 'example:secret'}, ['3000', 'bar'])
81
+ command.start
82
+
83
+ command.options[:port].must_equal 3000
84
+ command.options[:username].must_equal 'example'
85
+ command.options[:password].must_equal 'secret'
86
+ command.options[:subdomain_prefix].must_equal 'bar'
87
+ end
88
+
89
+ it 'validates port and exits if invalid' do
90
+ command = Forward::Command::Tunnel.new
91
+ command.options = { port: 3000 }
92
+
93
+ command.send(:validate_port)
94
+
95
+ [ 0, 65536 ].each do |port|
96
+ lambda {
97
+ dev_null {
98
+ command.options[:port] = port
99
+ command.send(:validate_port) }
100
+ }.must_raise Forward::CLIError
101
+ end
102
+ end
103
+
104
+ it 'validates cname and exits if invalid' do
105
+ command = Forward::Command::Tunnel.new
106
+ command.options = { cname: 'foo.bar.com' }
107
+
108
+ command.send(:validate_cname)
109
+ [ 'whatever', 'asdfasdf.', '-asdf', 'adsf#$).com' ].each do |cname|
110
+ lambda {
111
+ dev_null {
112
+ command.options[:cname] = cname
113
+ command.send(:validate_cname)
114
+ }
115
+ }.must_raise Forward::CLIError
116
+ end
117
+ end
118
+
119
+ it 'validates subdomain prefix and exits if invalid' do
120
+ command = Forward::Command::Tunnel.new
121
+ command.options = { subdomain_prefix: 'foo' }
122
+
123
+ command.send(:validate_subdomain_prefix)
124
+ [ '-asdf', 'adsf#$)' ].each do |subdomain|
125
+ lambda {
126
+ dev_null {
127
+ command.options[:subdomain_prefix] = subdomain
128
+ command.send(:validate_subdomain_prefix)
129
+ }
130
+ }.must_raise Forward::CLIError
131
+ end
132
+ end
133
+ end