# Copyright (C) 2008-2011 AMEE UK Ltd. - http://www.amee.com # Released as Open Source Software under the BSD 3-Clause license. See LICENSE.txt for details. require 'spec_helper.rb' describe AMEE::Connection do it "requires server name, username, and password" do flexmock(Net::HTTP).new_instances.should_receive(:start => nil) lambda{AMEE::Connection.new(nil, nil, nil)}.should raise_error lambda{AMEE::Connection.new(nil, 'username', nil)}.should raise_error lambda{AMEE::Connection.new(nil, nil, 'password')}.should raise_error lambda{AMEE::Connection.new(nil, 'username', 'password')}.should raise_error lambda{AMEE::Connection.new('server.example.com', nil, nil)}.should raise_error lambda{AMEE::Connection.new('server.example.com', 'username', nil)}.should raise_error lambda{AMEE::Connection.new('server.example.com', nil, 'password')}.should raise_error c = AMEE::Connection.new('server.example.com', 'username', 'password') c.should be_valid end it "has default timeout of 60 seconds" do flexmock(Net::HTTP).new_instances.should_receive(:start => nil) c = AMEE::Connection.new('server.example.com', 'username', 'password') c.timeout.should be(60) end it "can set timeout" do flexmock(Net::HTTP).new_instances.should_receive(:start => nil) c = AMEE::Connection.new('server.example.com', 'username', 'password') c.timeout = 30 c.timeout.should be(30) end it "can set timeout on creation" do flexmock(Net::HTTP).new_instances.should_receive(:start => nil) c = AMEE::Connection.new('server.example.com', 'username', 'password', :timeout => 30) c.timeout.should be(30) end end describe AMEE::Connection, "with authentication" do it "should start out unauthenticated" do flexmock(Net::HTTP).new_instances.should_receive(:start => nil) amee = AMEE::Connection.new('server.example.com', 'username', 'password') amee.authenticated?.should be_false end it "detects the API version (1)" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '200', :body => '0', :'[]' => 'dummy_auth_token_data')) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') amee.authenticate amee.authenticated?.should be_true amee.version.should == 1.0 end it "detects the API version (2 - XML)" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '200', :body => '/authACTIVESTANDARDameeStandardAll2.0', :'[]' => 'dummy_auth_token_data')) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') amee.authenticate amee.authenticated?.should be_true amee.version.should == 2.0 end it "detects the API version (2 - JSON)" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '200', :body => '{ "next" : "/auth","user" : { "apiVersion" : "2.0","groupNames" : [ "amee","Standard","All"],"status" : "ACTIVE","type" : "STANDARD","uid" : "DB2C6DA7EAA7"}}', :'[]' => 'dummy_auth_token_data')) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') amee.authenticate amee.authenticated?.should be_true amee.version.should == 2.0 end it "should be able to get private URLs" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '401', :body => '')).once mock.should_receive(:request).and_return(flexmock(:code => '200', :body => '', :'[]' => 'dummy_auth_token_data')).once mock.should_receive(:request).and_return { |request| if request['authToken'] == 'dummy_auth_token_data' flexmock(:code => '200', :body => 'RootHomehomeMetadatametadataTesttestTransporttransportUseruser') else flexmock(:code => '401', :body => '') end }.once mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') amee.get('/data') do |response| response.should_not be_empty end amee.authenticated?.should be_true end it "should handle 404s gracefully" do flexmock(Net::HTTP).new_instances.should_receive(:start => nil, :request => flexmock(:code => '404', :body => ""), :finish => nil) amee = AMEE::Connection.new('server.example.com', 'username', 'password') lambda{amee.get('/missing_url')}.should raise_error(AMEE::NotFound, "The URL was not found on the server.\nRequest: GET /missing_url") end it "should raise error if permission for operation is denied" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '403', :body => '{}')) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') lambda { amee.get('/data') }.should raise_error(AMEE::PermissionDenied,"You do not have permission to perform the requested operation. Request: GET /data Response: {}") end it "should raise error if authentication succeeds, but permission for operation is denied" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '401', :body => ''), flexmock(:code => '200', :body => '', :'[]' => 'dummy_auth_token_data'), flexmock(:code => '403', :body => '{}')) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') lambda { amee.get('/data') }.should raise_error(AMEE::PermissionDenied,"You do not have permission to perform the requested operation. Request: GET /data Response: {}") amee.authenticated?.should be_true end it "should raise error if unhandled errors occur in connection" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '500', :body => '{}')) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') lambda { amee.get('/data') }.should raise_error(AMEE::UnknownError,"An error occurred while talking to AMEE: HTTP response code 500. Request: GET /data Response: {}") end end describe AMEE::Connection, "with retry enabled" do [ Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError ].each do |e| it "should retry after #{e.name} the correct number of times" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_raise(e.new).twice mock.should_receive(:request).and_return(flexmock(:code => '200', :body => '{}')).once mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password', :retries => 2) lambda { amee.get('/data') }.should_not raise_error end it "should retry #{e.name} the correct number of times and raise error on failure" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_raise(e.new).times(3) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password', :retries => 2) lambda { amee.get('/data') }.should raise_error(e) end end [ '502', '503', '504' ].each do |e| it "should retry after #{e} the correct number of times" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => e, :body => '{}')).twice mock.should_receive(:request).and_return(flexmock(:code => '200', :body => '{}')).once mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password', :retries => 2) lambda { amee.get('/data') }.should_not raise_error end it "should retry #{e} the correct number of times and raise error on failure" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => e, :body => '{}')).times(3) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password', :retries => 2) lambda { amee.get('/data') }.should raise_error(AMEE::ConnectionFailed) end end end describe AMEE::Connection, "with incorrect server name" do it "should raise a useful error" do flexmock(Net::HTTP).new_instances.should_receive(:start).and_raise(SocketError.new) amee = AMEE::Connection.new('badservername.example.com', 'username', 'password') lambda{ amee.get('/') }.should raise_error(AMEE::ConnectionFailed, "Connection failed. Check server name or network connection.") end end describe AMEE::Connection, "with bad authentication information" do it "should be capable of making requests for public URLs" do flexmock(Net::HTTP).new_instances.should_receive(:start => nil, :request => flexmock(:code => '200', :body => ""), :finish => nil) amee = AMEE::Connection.new('server.example.com', 'wrong', 'details') lambda{amee.get('/')}.should_not raise_error end it "should get an authentication failure when accessing private URLs" do flexmock(Net::HTTP).new_instances.should_receive(:start => nil, :request => flexmock(:code => '401', :body => "", :'[]' => nil), :finish => nil) amee = AMEE::Connection.new('server.example.com', 'wrong', 'details') lambda{amee.get('/data')}.should raise_error(AMEE::AuthFailed, "Authentication failed. Please check your username and password. (tried wrong,details)") end end describe AMEE::Connection, "with authentication , doing write-requests" do it "should be able to send post requests" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '200', :body => '')) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') amee.post('/profiles', :test => 1, :test2 => 2) do |response| response.should be_empty end end it "should be able to send put requests" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '200', :body => '')) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') amee.put('/profiles/ABC123', :test => 1, :test2 => 2) do |response| response.should be_empty end end it "should be able to send delete requests" do flexmock(Net::HTTP).new_instances do |mock| mock.should_receive(:start => nil) mock.should_receive(:request).and_return(flexmock(:code => '200', :body => '')) mock.should_receive(:finish => nil) end amee = AMEE::Connection.new('server.example.com', 'username', 'password') amee.delete('/profiles/ABC123') do |response| response.should be_empty end end end