diff --git a/test/fixtures/files/test.png b/test/fixtures/files/test.png new file mode 100644 index 0000000000000000000000000000000000000000..afbbb4f8b77c0826e00104e7a685a732184bb5f5 Binary files /dev/null and b/test/fixtures/files/test.png differ diff --git a/test/fixtures/http_invalid_header.xml b/test/fixtures/http_invalid_header.xml new file mode 100644 index 0000000000000000000000000000000000000000..6ddfedc088de25082a8644c6d1da39d4bd0dff52 --- /dev/null +++ b/test/fixtures/http_invalid_header.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<Error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"> + <Code>InvalidHeaderValue</Code> + <Message>The value for one of the HTTP headers is not in the correct format.\nRequestId:266be2bc-0001-0018-1256-d3bb92000000\nTime:2016-07-01T05:06:32.5922690Z</Message> + <HeaderName>Range</HeaderName> + <HeaderValue>bytes=0-512</HeaderValue> +</Error> diff --git a/test/support/fixtures.rb b/test/support/fixtures.rb index 087df4ff6303896a89075e9517f9ffcb0a907dad..4398aa167fc5656597d06893c40233fe932cea6f 100644 --- a/test/support/fixtures.rb +++ b/test/support/fixtures.rb @@ -21,7 +21,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- -require "pathname" +require "azure/core/http/retry_policy" Fixtures = Hash.new do |hash, fixture| if path = Fixtures.xml?(fixture) @@ -49,3 +49,48 @@ end def Fixtures.json?(fixture) file?("#{fixture}.json") end + +module Azure + module Core + Fixtures = Hash.new do |hash, fixture| + if path = Fixtures.xml?(fixture) + hash[fixture] = path.read + elsif path = Fixtures.file?(fixture) + hash[fixture] = path + end + end + def Fixtures.root + Pathname("../../fixtures").expand_path(__FILE__) + end + def Fixtures.file?(fixture) + path = root.join(fixture) + path.file? && path + end + def Fixtures.xml?(fixture) + file?("#{fixture}.xml") + end + + class FixtureRetryPolicy < Azure::Core::Http::RetryPolicy + def initialize + super &:should_retry? + end + def should_retry?(response, retry_data) + retry_data[:error].inspect.include?('Error: Retry') + end + end + + class NewUriRetryPolicy < Azure::Core::Http::RetryPolicy + def initialize + @count = 1 + super &:should_retry? + end + + def should_retry?(response, retry_data) + retry_data[:uri] = URI.parse "http://bar.com" + @count = @count - 1 + @count >= 0 + end + end + + end +end diff --git a/test/unit/core/auth/shared_key_lite_test.rb b/test/unit/core/auth/shared_key_lite_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..75a49e94115cdb71a1fddbfda185d324e5539173 --- /dev/null +++ b/test/unit/core/auth/shared_key_lite_test.rb @@ -0,0 +1,51 @@ +#------------------------------------------------------------------------- +# # Copyright (c) Microsoft and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#-------------------------------------------------------------------------- +require 'test_helper' +require 'azure/core/auth/shared_key_lite' + +describe Azure::Core::Auth::SharedKeyLite do + subject { Azure::Core::Auth::SharedKeyLite.new 'account-name', 'YWNjZXNzLWtleQ==' } + + let(:verb) { 'POST' } + let(:uri) { URI.parse 'http://dummy.uri/resource' } + let(:headers) do + { + 'Content-MD5' => 'foo', + 'Content-Type' => 'foo', + 'Date' => 'foo' + } + end + let(:headers_without_date) { + headers_without_date = headers.clone + headers_without_date.delete 'Date' + headers_without_date + } + + describe 'sign' do + it 'creates a signature from the provided HTTP method, uri, and reduced set of standard headers' do + subject.sign(verb, uri, headers).must_equal 'account-name:vVFnj/+27JFABZgpt5H8g/JVU2HuWFnjv5aeUIxQvBE=' + end + + it 'ignores standard headers other than Content-MD5, Content-Type, and Date' do + subject.sign(verb, uri, headers.merge({'Content-Encoding' => 'foo'})).must_equal 'account-name:vVFnj/+27JFABZgpt5H8g/JVU2HuWFnjv5aeUIxQvBE=' + end + + it 'throws IndexError when there is no Date header' do + assert_raises IndexError do + subject.sign(verb, uri, headers_without_date) + end + end + end +end diff --git a/test/unit/core/auth/shared_key_test.rb b/test/unit/core/auth/shared_key_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..0cd86466e8d3f5fd3a2a85164859ec3a67fc16c2 --- /dev/null +++ b/test/unit/core/auth/shared_key_test.rb @@ -0,0 +1,59 @@ +#------------------------------------------------------------------------- +# # Copyright (c) Microsoft and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#-------------------------------------------------------------------------- +require 'test_helper' +require 'azure/core/auth/shared_key' + +describe Azure::Core::Auth::SharedKey do + subject { Azure::Core::Auth::SharedKey.new 'account-name', 'YWNjZXNzLWtleQ==' } + + let(:verb) { 'POST' } + let(:uri) { URI.parse 'http://dummy.uri/resource' } + let(:headers) do + { + 'Content-Encoding' => 'foo', + 'Content-Language' => 'foo', + 'Content-Length' => 'foo', + 'Content-MD5' => 'foo', + 'Content-Type' => 'foo', + 'Date' => 'foo', + 'If-Modified-Since' => 'foo', + 'If-Match' => 'foo', + 'If-None-Match' => 'foo', + 'If-Unmodified-Since' => 'foo', + 'Range' => 'foo', + 'x-ms-ImATeapot' => 'teapot', + 'x-ms-ShortAndStout' => 'True', + 'x-ms-reserve-spaces' => 'two speces' + } + end + + describe 'sign' do + it 'creates a signature from the provided HTTP method, uri, and a specific set of standard headers' do + subject.sign(verb, uri, headers).must_equal 'account-name:TVilUAfUwtHIVp+eonglFDXfS5r0/OE0/vVX3GHcaxU=' + end + end + + describe 'canonicalized_headers' do + it 'creates a canonicalized header string' do + subject.canonicalized_headers(headers).must_equal "x-ms-imateapot:teapot\nx-ms-reserve-spaces:two speces\nx-ms-shortandstout:True" + end + end + + describe 'canonicalized_resource' do + it 'creates a canonicalized resource string' do + subject.canonicalized_resource(uri).must_equal '/account-name/resource' + end + end +end diff --git a/test/unit/core/auth/signer_test.rb b/test/unit/core/auth/signer_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..917194b131e35924a1d8cb1b1de67564732ca217 --- /dev/null +++ b/test/unit/core/auth/signer_test.rb @@ -0,0 +1,30 @@ +#------------------------------------------------------------------------- +# # Copyright (c) Microsoft and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#-------------------------------------------------------------------------- +require "test_helper" +require "azure/core/auth/signer" + +describe Azure::Core::Auth::Signer do + subject { Azure::Core::Auth::Signer.new "YWNjZXNzLWtleQ==" } + + it "decodes the base64 encoded access_key" do + subject.access_key.must_equal "access-key" + end + + describe "sign" do + it "creates a signature for the body, as a base64 encoded string, which represents a HMAC hash using the access_key" do + subject.sign("body").must_equal "iuUxVhs1E7PeSNx/90ViyJNO24160qYpoWeCcOsnMoM=" + end + end +end diff --git a/test/unit/core/filter_service_test.rb b/test/unit/core/filter_service_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..d16b222019a800a4075904095685de562a6b869a --- /dev/null +++ b/test/unit/core/filter_service_test.rb @@ -0,0 +1,41 @@ +#------------------------------------------------------------------------- +# # Copyright (c) Microsoft and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#-------------------------------------------------------------------------- +require 'test_helper' +require 'azure/core' +require "azure/core/http/debug_filter" +require "azure/core/http/retry_policy" + +describe 'Azure core service' do + subject do + Azure::Core::FilteredService.new + end + + it 'works with default' do + subject.filters.count.must_equal 0 + end + + it 'works with a debug filter' do + service = Azure::Core::FilteredService.new + service.with_filter Azure::Core::Http::DebugFilter.new + service.filters.count.must_equal 1 + end + + it 'works with retry policy filter' do + service = Azure::Core::FilteredService.new + service.with_filter Azure::Core::Http::DebugFilter.new + service.with_filter Azure::Core::Http::RetryPolicy.new + service.filters.count.must_equal 2 + end +end diff --git a/test/unit/core/http/http_error_test.rb b/test/unit/core/http/http_error_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..49b5040b2d186de6476f3761def0e8e639e3092d --- /dev/null +++ b/test/unit/core/http/http_error_test.rb @@ -0,0 +1,113 @@ +#------------------------------------------------------------------------- +# # Copyright (c) Microsoft and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#-------------------------------------------------------------------------- +require 'test_helper' +require 'azure/core/http/http_error' + +describe Azure::Core::Http::HTTPError do + let :http_response do + stub(body: Azure::Core::Fixtures[:http_error], status_code: 409, uri: 'http://dummy.uri', headers: { 'Content-Type' => 'application/atom+xml' }) + end + + subject do + Azure::Core::Http::HTTPError.new(http_response) + end + + it 'is an instance of Azure::Core::Error' do + subject.must_be_kind_of Azure::Core::Error + end + + it 'lets us see the original uri' do + subject.uri.must_equal 'http://dummy.uri' + end + + it "lets us see the errors'status code" do + subject.status_code.must_equal 409 + end + + it "lets us see the error's type" do + subject.type.must_equal 'TableAlreadyExists' + end + + it "lets us see the error's description" do + subject.description.must_equal 'The table specified already exists.' + end + + it 'generates an error message that wraps both the type and description' do + subject.message.must_equal 'TableAlreadyExists (409): The table specified already exists.' + end + + describe 'with invalid http_response body' do + let :http_response do + stub(:body => "\r\nInvalid request\r\n", :status_code => 409, :uri => 'http://dummy.uri', headers: {}) + end + + it 'sets the type to unknown if the response body is not an XML' do + subject.type.must_equal 'Unknown' + subject.description.must_equal 'Invalid request' + end + end + + describe 'with invalid headers' do + let :http_response do + stub(body: Azure::Core::Fixtures[:http_invalid_header], status_code: 400, uri: 'http://dummy.uri', headers: { 'Content-Type' => 'application/atom+xml'}) + end + + it 'sets the invalid header in the error details' do + subject.status_code.must_equal 400 + subject.type.must_equal 'InvalidHeaderValue' + subject.description.must_include 'The value for one of the HTTP headers is not in the correct format' + subject.header.must_equal 'Range' + subject.header_value.must_equal 'bytes=0-512' + end + end + + describe 'with JSON payload' do + let :http_response do + body = "{\"odata.error\":{\"code\":\"ErrorCode\",\"message\":{\"lang\":\"en-US\",\"value\":\"ErrorDescription\"}}}" + stub(body: body, status_code: 400, uri: 'http://dummy.uri', headers: { 'Content-Type' => 'application/json' }) + end + + it 'parse error response with JSON payload' do + subject.status_code.must_equal 400 + subject.type.must_equal 'ErrorCode' + subject.description.must_include 'ErrorDescription' + end + end + + describe 'with unknown payload' do + let :http_response do + body = 'Unknown Payload Format with Unknown Error Description' + stub(body: body, status_code: 400, uri: 'http://dummy.uri', headers: {}) + end + + it 'parse error response with JSON payload' do + subject.status_code.must_equal 400 + subject.type.must_equal 'Unknown' + subject.description.must_include 'Error Description' + end + end + + describe 'with no response body' do + let :http_response do + body = '' + stub(body: body, status_code: 404, uri: 'http://dummy.uri', headers: {}, reason_phrase: 'dummy reason') + end + + it 'message has value assigned from reason_phrase' do + subject.status_code.must_equal 404 + subject.message.must_equal 'Unknown (404): dummy reason' + end + end +end diff --git a/test/unit/core/http/http_request_test.rb b/test/unit/core/http/http_request_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..fa781fe387da0616501801ee87d543ad6a1ffac9 --- /dev/null +++ b/test/unit/core/http/http_request_test.rb @@ -0,0 +1,201 @@ +#------------------------------------------------------------------------- +# # Copyright (c) Microsoft and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#-------------------------------------------------------------------------- +require 'test_helper' +require 'azure/core/http/http_request' + +describe Azure::Core::Http::HttpRequest do + let(:uri) { URI('http://example.com') } + + describe ' default_headers ' do + subject do + Azure::Core::Http::HttpRequest.new(:get, uri, body: nil, current_time: 'Thu, 04 Oct 2012 06:38:27 GMT') + end + + it 'sets the x-ms-date header to the current_time' do + subject.headers['x-ms-date'] = 'Thu, 04 Oct 2012 06:38:27 GMT' + end + + it 'sets the x-ms-version header to the current API version' do + subject.headers['x-ms-version'] = '2011-08-18' + end + + it 'sets the DataServiceVersion header to the current API version' do + subject.headers['DataServiceVersion'] = '1.0;NetFx' + end + + it 'sets the MaxDataServiceVersion header to the current max` API version' do + subject.headers['MaxDataServiceVersion'] = '2.0;NetFx' + end + end + + describe 'when passed custom headers' do + subject do + Azure::Core::Http::HttpRequest.new(:get, + uri, + body: nil, + headers: { + 'blah' => 'something', + 'x-ms-version' => '123' + }) + end + + it 'should have overridden the value of x-ms-version' do + subject.headers['x-ms-version'].must_equal '123' + end + + it 'should have added in the blah = something header' do + subject.headers['blah'].must_equal 'something' + end + + end + + describe ' when passed a body ' do + describe " of type IO" do + subject do + file = File.open(File.expand_path("../../../../fixtures/files/test.png", __FILE__)) + Azure::Core::Http::HttpRequest.new(:post, uri, body: file) + end + + it 'sets the default Content-Type header' do + subject.headers['Content-Type'].must_equal 'application/atom+xml; charset=utf-8' + end + + it 'sets the Content-Length header' do + subject.headers['Content-Length'].must_equal '4054' + end + + it 'sets the Content-MD5 header to a Base64 encoded representation of the MD5 hash of the body' do + subject.headers['Content-MD5'].must_equal 'nxTCAVCgA9fOTeV8KY8Pug==' + end + end + + describe 'of type Tempfile' do + subject do + tempfile = Tempfile.open('azure') + file = File.open(File.expand_path('../../../../fixtures/files/test.png', __FILE__)) + IO.copy_stream(file, tempfile) + + Azure::Core::Http::HttpRequest.new(:post, uri, body: tempfile) + end + + it 'sets the default Content-Type header' do + subject.headers['Content-Type'].must_equal 'application/atom+xml; charset=utf-8' + end + + it 'sets the Content-Length header' do + subject.headers['Content-Length'].must_equal '4054' + end + + it 'sets the Content-MD5 header to a Base64 encoded representation of the MD5 hash of the body' do + subject.headers['Content-MD5'].must_equal 'nxTCAVCgA9fOTeV8KY8Pug==' + end + end + + describe ' of type StringIO' do + subject do + Azure::Core::Http::HttpRequest.new(:post, uri, body: StringIO.new('<body/>')) + end + + it 'sets the default Content-Type header' do + subject.headers['Content-Type'].must_equal 'application/atom+xml; charset=utf-8' + end + + it 'sets the Content-Length header' do + subject.headers['Content-Length'].must_equal '7' + end + + it 'sets the Content-MD5 header to a Base64 encoded representation of the MD5 hash of the body' do + subject.headers['Content-MD5'].must_equal 'PNeJy7qyzV4XUoBBHkVu0g==' + end + end + + + describe ' of type String' do + subject do + Azure::Core::Http::HttpRequest.new(:post, uri, body: '<body/>') + end + + it 'sets the default Content-Type header' do + subject.headers['Content-Type'].must_equal 'application/atom+xml; charset=utf-8' + end + + it 'sets the Content-Length header' do + subject.headers['Content-Length'].must_equal '7' + end + + it 'sets the Content-MD5 header to a Base64 encoded representation of the MD5 hash of the body' do + subject.headers['Content-MD5'].must_equal 'PNeJy7qyzV4XUoBBHkVu0g==' + end + end + end + + describe ' when the body is nil ' do + subject do + Azure::Core::Http::HttpRequest.new(:get, uri) + end + + it 'leaves the Content-Type, Content-Length, and Content-MD5 headers blank' do + subject.headers['Content-Length'].must_equal '0' + subject.headers['Content-MD5'].must_be_nil + end + end + + describe '#call' do + + let(:mock_conn) do + conn = mock + conn.expects(:run_request, [uri, nil, nil]).returns(mock_res) + conn + end + + subject do + sub = Azure::Core::Http::HttpRequest.new(:get, uri) + sub.expects(:http_setup).returns(mock_conn) + sub + end + + describe 'on success' do + let(:body) { '</body>' } + + let(:mock_res) do + res = mock + res.expects(:success?).returns(true) + res.expects(:body).returns(body) + res + end + + it 'should return a response' do + subject.call.body.must_equal(body) + end + end + + describe 'on failure' do + let(:body) { 'OH NO!!' } + + let(:mock_res) do + res = mock + res.expects(:success?).returns(false).at_least_once + res.expects(:status).returns(401).at_least_once + res.expects(:body).returns(body).at_least_once + res.expects(:headers).returns({}).at_least_once + res + end + + it 'should return a response' do + -> { subject.call }.must_raise(Azure::Core::Http::HTTPError) + end + end + end +end diff --git a/test/unit/core/http/http_response_test.rb b/test/unit/core/http/http_response_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..95a127db054d399a049d4ce00f9da0f4bdefbfa5 --- /dev/null +++ b/test/unit/core/http/http_response_test.rb @@ -0,0 +1,20 @@ +#------------------------------------------------------------------------- +# # Copyright (c) Microsoft and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#-------------------------------------------------------------------------- +require 'test_helper' +require 'azure/core/http/http_response' + +describe Azure::Core::Http::HttpResponse do + # TODO: fill in with better tests. +end diff --git a/test/unit/core/service_test.rb b/test/unit/core/service_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..2f706c9c96978fcd5f43452b1851cb1a143654ca --- /dev/null +++ b/test/unit/core/service_test.rb @@ -0,0 +1,73 @@ +#------------------------------------------------------------------------- +# # Copyright (c) Microsoft and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#-------------------------------------------------------------------------- +require 'test_helper' +require 'azure/core' + +describe 'Azure core service' do + subject do + Azure::Core::Service.new + end + + it 'generate_uri should return URI instance' do + subject.host = 'http://dumyhost.uri' + subject.generate_uri.must_be_kind_of ::URI + subject.generate_uri.to_s.must_equal 'http://dumyhost.uri/' + end + + it 'generate_uri should add path to the url' do + subject.generate_uri('resource/entity/').path.must_equal '/resource/entity/' + end + + it 'generate_uri should correctly join the path if host url contained a path' do + subject.host = 'http://dummy.uri/host/path' + subject.generate_uri('resource/entity/').path.must_equal '/host/path/resource/entity/' + end + + it 'generate_uri should encode the keys' do + subject.generate_uri('', {'key !' => 'value'}).query.must_include 'key+%21=value' + end + + it 'generate_uri should encode the values' do + subject.generate_uri('', {'key' => 'value !'}).query.must_include 'key=value+%21' + end + + it 'generate_uri should set query string to the encoded result' do + subject.generate_uri('', {'key' => 'value !', 'key !' => 'value'}).query.must_equal 'key=value+%21&key+%21=value' + end + + it 'generate_uri should override the default timeout' do + subject.generate_uri('', {'timeout' => 45}).query.must_equal 'timeout=45' + end + + it 'generate_uri should not include any query parameters' do + subject.generate_uri('', nil).query.must_be_nil + end + + it 'generate_uri should not re-encode path with spaces' do + subject.host = 'http://dumyhost.uri' + encoded_path = 'blob%20name%20with%20spaces' + uri = subject.generate_uri(encoded_path, nil) + uri.host.must_equal 'dumyhost.uri' + uri.path.must_equal '/blob%20name%20with%20spaces' + end + + it 'generate_uri should not re-encode path with special characters' do + subject.host = 'http://dumyhost.uri' + encoded_path = 'host/path/%D1%84%D0%B1%D0%B0%D1%84.jpg' + uri = subject.generate_uri(encoded_path, nil) + uri.host.must_equal 'dumyhost.uri' + uri.path.must_equal '/host/path/%D1%84%D0%B1%D0%B0%D1%84.jpg' + end +end diff --git a/test/unit/core/utility_test.rb b/test/unit/core/utility_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..a8f77a39a682a7d0f23295525e41bebb692e1560 --- /dev/null +++ b/test/unit/core/utility_test.rb @@ -0,0 +1,123 @@ +#------------------------------------------------------------------------- +# # Copyright (c) Microsoft and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#-------------------------------------------------------------------------- +require 'test_helper' +require 'azure/core/utility' + +describe Azure::Core::Logger do + subject { Azure::Core::Logger } + let(:msg) { "message" } + + after { + subject.initialize_external_logger(nil) + } + + describe "Log without external logger" do + before { + subject.initialize_external_logger(nil) + } + + it "#info" do + out, err = capture_io { subject.info(msg) } + assert_equal("\e[37m\e[1m" + msg + "\e[0m\e[0m\n", out) + end + + it "#error_with_exit" do + out, err = capture_io do + error = assert_raises(RuntimeError) do + subject.error_with_exit(msg) + end + assert_equal("\e[31m\e[1m" + msg + "\e[0m\e[0m", error.message) + end + assert_equal("\e[31m\e[1m" + msg + "\e[0m\e[0m\n", out) + end + + it "#warn" do + out, err = capture_io do + warn = subject.warn(msg) + assert_equal(msg, warn) + end + assert_equal("\e[33m" + msg + "\e[0m\n", out) + end + + it "#error" do + out, err = capture_io do + error = subject.error(msg) + assert_equal(msg, error) + end + assert_equal("\e[31m\e[1m" + msg + "\e[0m\e[0m\n", out) + end + + it "#exception_message" do + out, err = capture_io do + exception = assert_raises(RuntimeError) do + subject.exception_message(msg) + end + assert_equal("\e[31m\e[1m" + msg + "\e[0m\e[0m", exception.message) + end + assert_equal("\e[31m\e[1m" + msg + "\e[0m\e[0m\n", out) + end + + it "#success" do + out, err = capture_io { subject.success(msg) } + assert_equal("\e[32m" + msg + "\n\e[0m", out) + end + end + + describe "Log with external logger" do + let(:fake_output) { StringIO.new } + + before { + subject.initialize_external_logger(Logger.new(fake_output)) + } + + it "#info" do + subject.info(msg) + assert_match(/INFO -- : #{msg}\n/, fake_output.string) + end + + it "#error_with_exit" do + error = assert_raises(RuntimeError) do + subject.error_with_exit(msg) + end + assert_match(/ERROR -- : #{msg}\n/, fake_output.string) + assert_equal("\e[31m\e[1m" + msg + "\e[0m\e[0m", error.message) + end + + it "#warn" do + warn = subject.warn(msg) + assert_match(/WARN -- : #{msg}\n/, fake_output.string) + assert_equal(msg, warn) + end + + it "#error" do + error = subject.error(msg) + assert_match(/ERROR -- : #{msg}\n/, fake_output.string) + assert_equal(msg, error) + end + + it "#exception_message" do + exception = assert_raises(RuntimeError) do + subject.exception_message(msg) + end + assert_match(/WARN -- : #{msg}\n/, fake_output.string) + assert_equal("\e[31m\e[1m" + msg + "\e[0m\e[0m", exception.message) + end + + it "#success" do + subject.success(msg) + assert_match(/INFO -- : #{msg}\n/, fake_output.string) + end + end +end \ No newline at end of file