analysand 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ require 'analysand/errors'
4
+ require 'analysand/instance'
5
+ require 'uri'
6
+ require 'vcr'
7
+
8
+ require File.expand_path('../a_session_grantor', __FILE__)
9
+
10
+ module Analysand
11
+ describe Instance do
12
+ describe '#initialize' do
13
+ it 'requires an absolute URI' do
14
+ lambda { Instance.new(URI("/abc")) }.should raise_error(InvalidURIError)
15
+ end
16
+ end
17
+
18
+ let(:instance) { Instance.new(instance_uri) }
19
+
20
+ describe '#establish_session' do
21
+ describe 'given admin credentials' do
22
+ let(:credentials) { admin_credentials }
23
+
24
+ it_should_behave_like 'a session grantor'
25
+ end
26
+
27
+ describe 'given member credentials' do
28
+ let(:credentials) { member1_credentials }
29
+
30
+ it_should_behave_like 'a session grantor'
31
+ end
32
+
33
+ describe 'given incorrect credentials' do
34
+ it 'returns [nil, response]' do
35
+ session, resp = instance.establish_session('wrong', 'wrong')
36
+
37
+ session.should be_nil
38
+ resp.code.should == '401'
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '#renew_session' do
44
+ let(:credentials) { admin_credentials }
45
+
46
+ before do
47
+ @session, _ = instance.establish_session(credentials[:username], credentials[:password])
48
+ end
49
+
50
+ describe 'if CouchDB refreshes the session cookie' do
51
+ around do |example|
52
+ VCR.use_cassette('get_session_refreshes_cookie') { example.call }
53
+ end
54
+
55
+ it_should_behave_like 'a session grantor' do
56
+ let(:result) { instance.renew_session(@session) }
57
+ let(:role_locator) do
58
+ lambda { |resp| resp['userCtx']['roles'] }
59
+ end
60
+ end
61
+ end
62
+
63
+ describe 'if CouchDB does not refresh the session cookie' do
64
+ around do |example|
65
+ VCR.use_cassette('get_session_does_not_refresh_cookie') { example.call }
66
+ end
67
+
68
+ it_should_behave_like 'a session grantor' do
69
+ let(:result) { instance.renew_session(@session) }
70
+ let(:role_locator) do
71
+ lambda { |resp| resp['userCtx']['roles'] }
72
+ end
73
+ end
74
+ end
75
+
76
+ describe 'given an invalid session' do
77
+ it 'returns [nil, response]' do
78
+ session, resp = instance.renew_session({ :token => 'AuthSession=wrong' })
79
+
80
+ session.should be_nil
81
+ resp.code.should == '400'
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ require 'analysand/database'
4
+ require 'analysand/response'
5
+
6
+ module Analysand
7
+ describe Response do
8
+ let(:db) { Database.new(database_uri) }
9
+
10
+ describe '#etag' do
11
+ let(:response) do
12
+ VCR.use_cassette('head_request_with_etag') do
13
+ db.head('abc123', admin_credentials)
14
+ end
15
+ end
16
+
17
+ it 'removes quotes from ETags' do
18
+ response.etag.should == '1-967a00dff5e02add41819138abb3284d'
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ require 'analysand/view_response'
4
+
5
+ module Analysand
6
+ describe ViewResponse do
7
+ describe '#docs' do
8
+ let(:resp_with_docs) do
9
+ '{"rows": [{"id":"foo","key":"foo","value":{},"doc":{"foo":"bar"}}]}'
10
+ end
11
+
12
+ let(:resp_without_docs) do
13
+ '{"rows": [{"id":"foo","key":"foo","value":{}}]}'
14
+ end
15
+
16
+ describe 'if the view includes docs' do
17
+ subject { ViewResponse.new(stub(:body => resp_with_docs)) }
18
+
19
+ it 'returns the value of the "doc" key in each row' do
20
+ subject.docs.should == [{'foo' => 'bar'}]
21
+ end
22
+ end
23
+
24
+ describe 'if the view does not include docs' do
25
+ subject { ViewResponse.new(stub(:body => resp_without_docs)) }
26
+
27
+ it 'returns []' do
28
+ subject.docs.should == []
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,73 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: http://localhost:5984/_session
6
+ body:
7
+ string: name=admin&password=admin
8
+ headers:
9
+ Connection:
10
+ - keep-alive
11
+ Accept:
12
+ - "*/*"
13
+ Keep-Alive:
14
+ - 30
15
+ Content-Type:
16
+ - application/x-www-form-urlencoded
17
+ response:
18
+ status:
19
+ code: 200
20
+ message: OK
21
+ headers:
22
+ Date:
23
+ - Sat, 31 Mar 2012 22:35:18 GMT
24
+ Set-Cookie:
25
+ - AuthSession=YWRtaW46NEY3Nzg2QTY6WVqDNxuHpu4OPp07rib-n9WQLt8; Version=1; Path=/; HttpOnly
26
+ Server:
27
+ - CouchDB/1.3.0a-d0a5bf0-git (Erlang OTP/R14B02)
28
+ Content-Length:
29
+ - "56"
30
+ Content-Type:
31
+ - text/plain; charset=utf-8
32
+ Cache-Control:
33
+ - must-revalidate
34
+ body:
35
+ string: |
36
+ {"ok":true,"name":null,"roles":["_admin","site_admin"]}
37
+ recorded_at: Sat, 31 Mar 2012 22:35:18 GMT
38
+ - request:
39
+ method: get
40
+ uri: http://localhost:5984/_session
41
+ headers:
42
+ Cookie:
43
+ - AuthSession=YWRtaW46NEY3Nzg2QTY6WVqDNxuHpu4OPp07rib-n9WQLt8; Version=1; Path=/; HttpOnly
44
+ Connection:
45
+ - keep-alive
46
+ Accept:
47
+ - "*/*"
48
+ Keep-Alive:
49
+ - 30
50
+ Content-Type:
51
+ - application/x-www-form-urlencoded
52
+ response:
53
+ status:
54
+ code: 200
55
+ message: OK
56
+ headers:
57
+ Date:
58
+ - Sat, 31 Mar 2012 22:35:18 GMT
59
+ Server:
60
+ - CouchDB/1.3.0a-d0a5bf0-git (Erlang OTP/R14B02)
61
+ Content-Length:
62
+ - "56"
63
+ Content-Type:
64
+ - text/plain; charset=utf-8
65
+ Cache-Control:
66
+ - must-revalidate
67
+ body:
68
+ string: |
69
+ {"ok":true,"userCtx":{"name":null,"roles":["_admin","site_admin"]},"info":{"authentication_db":"_users","authentication_handlers":["oauth","cookie","default"]}}
70
+
71
+ http_version:
72
+ recorded_at: Sat, 31 Mar 2012 22:35:18 GMT
73
+ recorded_with: VCR 2.0.1
@@ -0,0 +1,75 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: http://localhost:5984/_session
6
+ body:
7
+ string: name=admin&password=admin
8
+ headers:
9
+ Connection:
10
+ - keep-alive
11
+ Accept:
12
+ - "*/*"
13
+ Keep-Alive:
14
+ - 30
15
+ Content-Type:
16
+ - application/x-www-form-urlencoded
17
+ response:
18
+ status:
19
+ code: 200
20
+ message: OK
21
+ headers:
22
+ Date:
23
+ - Sat, 31 Mar 2012 22:35:18 GMT
24
+ Set-Cookie:
25
+ - AuthSession=YWRtaW46NEY3Nzg2QTY6WVqDNxuHpu4OPp07rib-n9WQLt8; Version=1; Path=/; HttpOnly
26
+ Server:
27
+ - CouchDB/1.3.0a-d0a5bf0-git (Erlang OTP/R14B02)
28
+ Content-Length:
29
+ - "56"
30
+ Content-Type:
31
+ - text/plain; charset=utf-8
32
+ Cache-Control:
33
+ - must-revalidate
34
+ body:
35
+ string: |
36
+ {"ok":true,"name":null,"roles":["_admin","site_admin"]}
37
+ recorded_at: Sat, 31 Mar 2012 22:35:18 GMT
38
+ - request:
39
+ method: get
40
+ uri: http://localhost:5984/_session
41
+ headers:
42
+ Cookie:
43
+ - AuthSession=YWRtaW46NEY3Nzg2QTY6WVqDNxuHpu4OPp07rib-n9WQLt8; Version=1; Path=/; HttpOnly
44
+ Connection:
45
+ - keep-alive
46
+ Accept:
47
+ - "*/*"
48
+ Keep-Alive:
49
+ - 30
50
+ Content-Type:
51
+ - application/x-www-form-urlencoded
52
+ response:
53
+ status:
54
+ code: 200
55
+ message: OK
56
+ headers:
57
+ Date:
58
+ - Sat, 31 Mar 2012 22:35:18 GMT
59
+ Set-Cookie:
60
+ - AuthSession=YWRtaW46NEY3Nzg3RTk6Lj1LSc4dWHBMZoFKm9ZMxq0L3Ec; Version=1; Path=/; HttpOnly
61
+ Server:
62
+ - CouchDB/1.3.0a-d0a5bf0-git (Erlang OTP/R14B02)
63
+ Content-Length:
64
+ - "56"
65
+ Content-Type:
66
+ - text/plain; charset=utf-8
67
+ Cache-Control:
68
+ - must-revalidate
69
+ body:
70
+ string: |
71
+ {"ok":true,"userCtx":{"name":null,"roles":["_admin","site_admin"]},"info":{"authentication_db":"_users","authentication_handlers":["oauth","cookie","default"]}}
72
+
73
+ http_version:
74
+ recorded_at: Sat, 31 Mar 2012 22:35:18 GMT
75
+ recorded_with: VCR 2.0.1
@@ -0,0 +1,40 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: head
5
+ uri: http://admin:admin@localhost:5984/analysand_test/abc123
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ Connection:
15
+ - keep-alive
16
+ Keep-Alive:
17
+ - 30
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Server:
24
+ - CouchDB/1.3.0a-d6ab08d-git (Erlang OTP/R15B)
25
+ Etag:
26
+ - ! '"1-967a00dff5e02add41819138abb3284d"'
27
+ Date:
28
+ - Tue, 22 May 2012 14:21:26 GMT
29
+ Content-Type:
30
+ - text/plain; charset=utf-8
31
+ Content-Length:
32
+ - '61'
33
+ Cache-Control:
34
+ - must-revalidate
35
+ body:
36
+ encoding: US-ASCII
37
+ string: ''
38
+ http_version:
39
+ recorded_at: Tue, 22 May 2012 14:21:26 GMT
40
+ recorded_with: VCR 2.0.1
@@ -0,0 +1,19 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
2
+
3
+ require File.expand_path('../support/database_access', __FILE__)
4
+ require File.expand_path('../support/example_isolation', __FILE__)
5
+ require File.expand_path('../support/test_parameters', __FILE__)
6
+
7
+ require 'vcr'
8
+
9
+ RSpec.configure do |config|
10
+ config.include DatabaseAccess
11
+ config.include ExampleIsolation
12
+ config.include TestParameters
13
+ end
14
+
15
+ VCR.configure do |c|
16
+ c.allow_http_connections_when_no_cassette = true
17
+ c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
18
+ c.hook_into :webmock
19
+ end
@@ -0,0 +1,40 @@
1
+ require 'net/http'
2
+
3
+ module DatabaseAccess
4
+ ##
5
+ # Sets members and admins for the database.
6
+ #
7
+ # Assumes #admin_credentials returns a Hash containing the keys :username and
8
+ # :password, where those keys' values are the username and password of a
9
+ # CouchDB admin user.
10
+ def set_security(members, admins = {})
11
+ doc = {
12
+ 'members' => members,
13
+ 'admins' => admins
14
+ }
15
+
16
+ credentials = admin_credentials
17
+ uri = instance_uri
18
+
19
+ Net::HTTP.start(uri.host, uri.port) do |h|
20
+ req = Net::HTTP::Put.new("/#{database_name}/_security")
21
+ req.basic_auth(credentials[:username], credentials[:password])
22
+ req.body = doc.to_json
23
+
24
+ resp = h.request(req)
25
+
26
+ unless Net::HTTPSuccess === resp
27
+ raise "Unable to set security parameters on #{database_name}: response code = #{resp.code}, body = #{resp.body}"
28
+ end
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Resets member and admin lists for the test database to [].
34
+ def clear_security
35
+ set_security({ 'users' => [], 'roles' => [] },
36
+ { 'users' => [], 'roles' => [] })
37
+ end
38
+ end
39
+
40
+ # vim:ts=2:sw=2:et:tw=78
@@ -0,0 +1,86 @@
1
+ require File.expand_path('../test_parameters', __FILE__)
2
+
3
+ ##
4
+ # CouchDB doesn't implement a commit/rollback scheme like other databases, but
5
+ # it would nevertheless still sometimes be nice to be able to isolate
6
+ # datastore changes made between tests.
7
+ #
8
+ # This module provides methods to drop and create databases, which provides a
9
+ # slow-yet-effective way of achieving said isolation. Examples:
10
+ #
11
+ # describe Something do
12
+ # let(:database_uri) { 'http://localhost:5984' }
13
+ # let(:database_name) { 'something' }
14
+ #
15
+ # before do
16
+ # clean_databases!
17
+ # end
18
+ # end
19
+ #
20
+ # describe AnotherThing do
21
+ # let(:database_uri) { 'http://localhost:5984' }
22
+ # let(:database_names) { ['another', 'database'] }
23
+ #
24
+ # before do
25
+ # clean_databases!
26
+ # end
27
+ # end
28
+ #
29
+ # If both database_name and database_names are specified in the same example
30
+ # group, the latter will have precedence.
31
+ #
32
+ #
33
+ # Clean databases come with a performance cost
34
+ # ============================================
35
+ #
36
+ # Dropping and creating databases has a real performance cost, so it is
37
+ # advised that you only use this when absolutely necessary. Databases are
38
+ # only cleaned when
39
+ #
40
+ # clean_databases!
41
+ #
42
+ # is included in an example group's before block.
43
+ module ExampleIsolation
44
+ def clean_databases!
45
+ drop_databases!
46
+ create_databases!
47
+ end
48
+
49
+ def drop_databases!
50
+ affected_databases.each do |db|
51
+ uri = instance_uri + "/#{db}"
52
+ credentials = admin_credentials
53
+
54
+ Net::HTTP.start(uri.host, uri.port) do |http|
55
+ req = Net::HTTP::Delete.new(uri.path)
56
+ req.basic_auth(admin_username, admin_password)
57
+
58
+ http.request(req)
59
+ end
60
+ end
61
+ end
62
+
63
+ def create_databases!
64
+ affected_databases.each do |db|
65
+ uri = instance_uri + "/#{db}"
66
+ credentials = admin_credentials
67
+
68
+ Net::HTTP.start(uri.host, uri.port) do |http|
69
+ req = Net::HTTP::Put.new(uri.path)
70
+ req.basic_auth(admin_username, admin_password)
71
+
72
+ http.request(req)
73
+ end
74
+ end
75
+ end
76
+
77
+ def affected_databases
78
+ if respond_to?(:database_name)
79
+ [database_name]
80
+ elsif respond_to?(:database_names)
81
+ database_names
82
+ end.flatten
83
+ end
84
+ end
85
+
86
+ # vim:ts=2:sw=2:et:tw=78