couchdb 0.1.3 → 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.
@@ -2,11 +2,14 @@ require 'transport'
2
2
 
3
3
  module CouchDB
4
4
 
5
- autoload :Server, File.join(File.dirname(__FILE__), "couchdb", "server")
5
+ autoload :Collection, File.join(File.dirname(__FILE__), "couchdb", "collection")
6
6
  autoload :Database, File.join(File.dirname(__FILE__), "couchdb", "database")
7
- autoload :Document, File.join(File.dirname(__FILE__), "couchdb", "document")
8
7
  autoload :Design, File.join(File.dirname(__FILE__), "couchdb", "design")
9
- autoload :Collection, File.join(File.dirname(__FILE__), "couchdb", "collection")
8
+ autoload :Document, File.join(File.dirname(__FILE__), "couchdb", "document")
10
9
  autoload :Row, File.join(File.dirname(__FILE__), "couchdb", "row")
10
+ autoload :Security, File.join(File.dirname(__FILE__), "couchdb", "security")
11
+ autoload :Server, File.join(File.dirname(__FILE__), "couchdb", "server")
12
+ autoload :User, File.join(File.dirname(__FILE__), "couchdb", "user")
13
+ autoload :UserDatabase, File.join(File.dirname(__FILE__), "couchdb", "user_database")
11
14
 
12
15
  end
@@ -66,18 +66,22 @@ module CouchDB
66
66
  def fetch_response
67
67
  @response = Transport::JSON.request(
68
68
  :get, url,
69
- :parameters => request_parameters,
70
- :expected_status_code => 200,
71
- :encode_parameters => true
69
+ authentication_options.merge(
70
+ :parameters => request_parameters,
71
+ :expected_status_code => 200,
72
+ :encode_parameters => true
73
+ )
72
74
  )
73
75
  end
74
76
 
75
77
  def fetch_meta_response
76
78
  @response = Transport::JSON.request(
77
79
  :get, url,
78
- :parameters => request_parameters.merge(:limit => 0),
79
- :expected_status_code => 200,
80
- :encode_parameters => true
80
+ authentication_options.merge(
81
+ :parameters => request_parameters.merge(:limit => 0),
82
+ :expected_status_code => 200,
83
+ :encode_parameters => true
84
+ )
81
85
  )
82
86
  end
83
87
 
@@ -97,6 +101,10 @@ module CouchDB
97
101
  @entries = (@response["rows"] || [ ]).map{ |row_hash| Row.new @database, row_hash }
98
102
  end
99
103
 
104
+ def authentication_options
105
+ @database.authentication_options
106
+ end
107
+
100
108
  # A proxy class for the collection's fetched documents.
101
109
  class DocumentsProxy
102
110
 
@@ -21,7 +21,7 @@ module CouchDB
21
21
  end
22
22
 
23
23
  def create!
24
- Transport::JSON.request :put, url, :expected_status_code => 201
24
+ Transport::JSON.request :put, url, authentication_options.merge(:expected_status_code => 201)
25
25
  end
26
26
 
27
27
  def create_if_missing!
@@ -29,7 +29,7 @@ module CouchDB
29
29
  end
30
30
 
31
31
  def delete!
32
- Transport::JSON.request :delete, url, :expected_status_code => 200
32
+ Transport::JSON.request :delete, url, authentication_options.merge(:expected_status_code => 200)
33
33
  end
34
34
 
35
35
  def delete_if_exists!
@@ -37,7 +37,7 @@ module CouchDB
37
37
  end
38
38
 
39
39
  def information
40
- Transport::JSON.request :get, url, :expected_status_code => 200
40
+ Transport::JSON.request :get, url, authentication_options.merge(:expected_status_code => 200)
41
41
  end
42
42
 
43
43
  def exists?
@@ -52,6 +52,14 @@ module CouchDB
52
52
  Collection.new self, url + "/_all_docs", options
53
53
  end
54
54
 
55
+ def security
56
+ @security ||= CouchDB::Security.new self
57
+ end
58
+
59
+ def authentication_options
60
+ @server.authentication_options
61
+ end
62
+
55
63
  end
56
64
 
57
65
  end
@@ -9,6 +9,9 @@ module CouchDB
9
9
  # doesn't exists.
10
10
  class NotFoundError < StandardError; end
11
11
 
12
+ # The UnauthorizedError will be raised if the authentication has failed.
13
+ class UnauthorizedError < StandardError; end
14
+
12
15
  attr_reader :database
13
16
 
14
17
  def initialize(database, properties = { })
@@ -48,6 +51,14 @@ module CouchDB
48
51
  @properties.delete "_rev"
49
52
  end
50
53
 
54
+ def fetch_rev
55
+ properties = Transport::JSON.request :get, url, authentication_options.merge(:expected_status_code => 200)
56
+ self.rev = properties["_rev"]
57
+ rescue Transport::UnexpectedStatusCodeError => error
58
+ raise error unless error.status_code == 404
59
+ @properties.delete "_rev"
60
+ end
61
+
51
62
  def ==(other)
52
63
  self.id == other.id
53
64
  end
@@ -57,7 +68,7 @@ module CouchDB
57
68
  end
58
69
 
59
70
  def exists?
60
- Transport::JSON.request :get, url, :expected_status_code => 200
71
+ Transport::JSON.request :get, url, authentication_options.merge(:expected_status_code => 200)
61
72
  true
62
73
  rescue Transport::UnexpectedStatusCodeError => error
63
74
  raise error unless error.status_code == 404
@@ -65,10 +76,10 @@ module CouchDB
65
76
  end
66
77
 
67
78
  def load
68
- @properties = Transport::JSON.request :get, url, :expected_status_code => 200
79
+ @properties = Transport::JSON.request :get, url, authentication_options.merge(:expected_status_code => 200)
69
80
  true
70
81
  rescue Transport::UnexpectedStatusCodeError => error
71
- upgrade_unexpected_status_error error
82
+ upgrade_status_error error
72
83
  end
73
84
  alias reload load
74
85
 
@@ -78,11 +89,11 @@ module CouchDB
78
89
 
79
90
  def destroy
80
91
  return false if new?
81
- Transport::JSON.request :delete, url, :headers => { "If-Match" => self.rev }, :expected_status_code => 200
92
+ Transport::JSON.request :delete, url, authentication_options.merge(:headers => { "If-Match" => self.rev }, :expected_status_code => 200)
82
93
  self.clear_rev
83
94
  true
84
95
  rescue Transport::UnexpectedStatusCodeError => error
85
- upgrade_unexpected_status_error error
96
+ upgrade_status_error error
86
97
  end
87
98
 
88
99
  def url
@@ -92,27 +103,34 @@ module CouchDB
92
103
  private
93
104
 
94
105
  def create
95
- response = Transport::JSON.request :post, @database.url, :body => @properties, :expected_status_code => 201
106
+ response = Transport::JSON.request :post, @database.url, authentication_options.merge(:body => @properties, :expected_status_code => 201)
96
107
  self.id = response["id"]
97
108
  self.rev = response["rev"]
98
109
  true
99
- rescue Transport::UnexpectedStatusCodeError
110
+ rescue Transport::UnexpectedStatusCodeError => error
111
+ upgrade_status_error error
100
112
  false
101
113
  end
102
114
 
103
115
  def update
104
- response = Transport::JSON.request :put, url, :body => @properties, :expected_status_code => 201
116
+ response = Transport::JSON.request :put, url, authentication_options.merge(:body => @properties, :expected_status_code => 201)
105
117
  self.rev = response["rev"]
106
118
  true
107
- rescue Transport::UnexpectedStatusCodeError
119
+ rescue Transport::UnexpectedStatusCodeError => error
120
+ upgrade_status_error error
108
121
  false
109
122
  end
110
123
 
111
- def upgrade_unexpected_status_error(error)
124
+ def upgrade_status_error(error)
125
+ raise UnauthorizedError if error.status_code == 401
112
126
  raise NotFoundError if error.status_code == 404
113
127
  raise error
114
128
  end
115
129
 
130
+ def authentication_options
131
+ @database.authentication_options
132
+ end
133
+
116
134
  def method_missing(method_name, *arguments, &block)
117
135
  @properties.send method_name, *arguments, &block
118
136
  end
@@ -0,0 +1,55 @@
1
+
2
+ # Abstracts a CouchDB database security document.
3
+ class CouchDB::Security
4
+
5
+ attr_reader :administrators
6
+ attr_reader :readers
7
+
8
+ def initialize(database)
9
+ @database = database
10
+
11
+ @document = CouchDB::Document.new @database
12
+ @document.id = "_security"
13
+ @document.fetch_rev
14
+ @document["admins"] = { }
15
+ @document["readers"] = { }
16
+
17
+ @administrators = UsersAndRolesProxy.new @document["admins"]
18
+ @readers = UsersAndRolesProxy.new @document["readers"]
19
+ end
20
+
21
+ def load
22
+ @document.load
23
+ end
24
+
25
+ def save
26
+ @document.save
27
+ rescue Transport::UnexpectedStatusCodeError => error
28
+ raise error unless error.status_code == 200
29
+ end
30
+
31
+ # Proxy to manipulate an array structure of users and roles.
32
+ class UsersAndRolesProxy
33
+
34
+ attr_reader :names
35
+ attr_reader :roles
36
+
37
+ def initialize(hash)
38
+ @hash = hash
39
+ @names = @hash["names"] = [ ]
40
+ @roles = @hash["roles"] = [ ]
41
+ end
42
+
43
+ def clear!
44
+ @names.clear
45
+ @roles.clear
46
+ end
47
+
48
+ def <<(user_or_role)
49
+ @names << user_or_role.name if user_or_role.is_a?(CouchDB::User)
50
+ @roles << user_or_role if user_or_role.is_a?(String)
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -1,40 +1,66 @@
1
1
 
2
2
  module CouchDB
3
3
 
4
- # The Server class provides methods to retrieve informations and statistics
4
+ # The Server class provides methods to retrieve information and statistics
5
5
  # of a CouchDB server.
6
6
  class Server
7
7
 
8
- attr_reader :host
9
- attr_reader :port
8
+ attr_writer :host
9
+ attr_writer :port
10
+ attr_accessor :username
11
+ attr_accessor :password
10
12
 
11
- def initialize(host = "localhost", port = 5984)
12
- @host, @port = host, port
13
+ attr_accessor :password_salt
14
+
15
+ def initialize(host = nil, port = nil, username = nil, password = nil)
16
+ @host, @port, @username, @password = host, port, username, password
17
+ end
18
+
19
+ def host
20
+ @host || "localhost"
21
+ end
22
+
23
+ def port
24
+ @port || 5984
13
25
  end
14
26
 
15
27
  def ==(other)
16
- other.is_a?(self.class) && @host == other.host && @port == other.port
28
+ other.is_a?(self.class) && self.host == other.host && self.port == other.port
17
29
  end
18
30
 
19
31
  def information
20
- Transport::JSON.request :get, url + "/", :expected_status_code => 200
32
+ Transport::JSON.request :get, url + "/", options
21
33
  end
22
34
 
23
35
  def statistics
24
- Transport::JSON.request :get, url + "/_stats", :expected_status_code => 200
36
+ Transport::JSON.request :get, url + "/_stats", options
25
37
  end
26
38
 
27
39
  def database_names
28
- Transport::JSON.request :get, url + "/_all_dbs", :expected_status_code => 200
40
+ Transport::JSON.request :get, url + "/_all_dbs", options
29
41
  end
30
42
 
31
43
  def uuids(count = 1)
32
- response = Transport::JSON.request :get, url + "/_uuids", :expected_status_code => 200, :parameters => { :count => count }
44
+ response = Transport::JSON.request :get, url + "/_uuids", options.merge(:parameters => { :count => count })
33
45
  response["uuids"]
34
46
  end
35
47
 
48
+ def user_database
49
+ @user_database ||= UserDatabase.new self
50
+ end
51
+
36
52
  def url
37
- "http://#{@host}:#{@port}"
53
+ "http://#{self.host}:#{self.port}"
54
+ end
55
+
56
+ def authentication_options
57
+ self.username && self.password ? { :auth_type => :basic, :username => self.username, :password => self.password } : { }
58
+ end
59
+
60
+ private
61
+
62
+ def options
63
+ authentication_options.merge :expected_status_code => 200
38
64
  end
39
65
 
40
66
  end
@@ -0,0 +1,62 @@
1
+ require 'digest/sha1'
2
+
3
+ # Abstracts a CouchDB user.
4
+ class CouchDB::User
5
+
6
+ attr_reader :user_database
7
+
8
+ attr_accessor :document
9
+
10
+ def initialize(user_database, name)
11
+ @user_database = user_database
12
+
13
+ @document = CouchDB::Document.new @user_database.database
14
+ @document["_id"] = "org.couchdb.user:#{name}"
15
+ @document["type"] = "user"
16
+ @document["name"] = name
17
+ @document["salt"] = @user_database.server.password_salt
18
+ @document["roles"] = [ ]
19
+ end
20
+
21
+ def id
22
+ @document["_id"]
23
+ end
24
+
25
+ def name
26
+ @document["name"]
27
+ end
28
+
29
+ def password=(value)
30
+ @document["password_sha"] = Digest::SHA1.hexdigest(value + @user_database.database.server.password_salt)
31
+ end
32
+
33
+ def password
34
+ @document["password_sha"]
35
+ end
36
+
37
+ def roles=(value)
38
+ @document["roles"] = value || [ ]
39
+ end
40
+
41
+ def roles
42
+ @document["roles"]
43
+ end
44
+
45
+ def ==(other)
46
+ @document == other.document
47
+ end
48
+
49
+ def load
50
+ @document.load
51
+ end
52
+
53
+ def save
54
+ @document.fetch_rev
55
+ @document.save
56
+ end
57
+
58
+ def destroy
59
+ @document.destroy
60
+ end
61
+
62
+ end
@@ -0,0 +1,25 @@
1
+
2
+ # Wraps all methods for the user database.
3
+ class CouchDB::UserDatabase
4
+
5
+ attr_reader :server
6
+ attr_reader :database
7
+
8
+ def initialize(server, name = "_users")
9
+ @server = server
10
+ @database = CouchDB::Database.new @server, name
11
+ end
12
+
13
+ def users
14
+ @database.documents.map do |row|
15
+ if row.id =~ /^org\.couchdb\.user:.+$/
16
+ user = CouchDB::User.new self, row.id.sub(/^org\.couchdb\.user:/, "")
17
+ user.load
18
+ user
19
+ else
20
+ nil
21
+ end
22
+ end.compact
23
+ end
24
+
25
+ end
@@ -1,13 +1,13 @@
1
1
  require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
2
 
3
- describe CouchDB::Database do
3
+ describe "database management" do
4
4
 
5
5
  before :each do
6
- @server = CouchDB::Server.new
7
- @database = described_class.new @server, "test"
6
+ @server = make_test_server
7
+ @database = make_test_database @server
8
8
  end
9
9
 
10
- describe "create!" do
10
+ describe "creating a database" do
11
11
 
12
12
  before :each do
13
13
  @database.delete_if_exists!
@@ -20,7 +20,7 @@ describe CouchDB::Database do
20
20
 
21
21
  end
22
22
 
23
- describe "delete!" do
23
+ describe "deleting a database" do
24
24
 
25
25
  before :each do
26
26
  @database.create_if_missing!
@@ -33,7 +33,7 @@ describe CouchDB::Database do
33
33
 
34
34
  end
35
35
 
36
- describe "information" do
36
+ describe "fetching information about a database" do
37
37
 
38
38
  before :each do
39
39
  @database.create_if_missing!
@@ -45,7 +45,7 @@ describe CouchDB::Database do
45
45
 
46
46
  end
47
47
 
48
- describe "documents" do
48
+ describe "fetching all documents of a database" do
49
49
 
50
50
  it "should return a collection" do
51
51
  @database.documents.should be_instance_of(CouchDB::Collection)
@@ -0,0 +1,106 @@
1
+ require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
+
3
+ describe "database security" do
4
+
5
+ before :each do
6
+ @server = make_test_server
7
+ @server.password_salt = "salt"
8
+
9
+ @user_database = @server.user_database
10
+
11
+ @user = CouchDB::User.new @user_database, "test_user"
12
+ @user.password = "test"
13
+ @user.roles = [ "dummy" ]
14
+ @user.save
15
+
16
+ @database = make_test_database @server
17
+ @database.delete_if_exists!
18
+ @database.create_if_missing!
19
+ @database.security.administrators.clear!
20
+ @database.security.readers.clear!
21
+
22
+ @design = CouchDB::Design.new @database, "test"
23
+ @design.save
24
+ end
25
+
26
+ describe "adding an user to the database administrators" do
27
+
28
+ before :each do
29
+ @database.security.administrators << @user
30
+ @database.security.save
31
+
32
+ @server.username = "test_user"
33
+ @server.password = "test"
34
+ end
35
+
36
+ it "should allow the user to manipulate the database content" do
37
+ result = @design.save
38
+ result.should be_true
39
+ end
40
+
41
+ end
42
+
43
+ describe "adding an user to the database readers" do
44
+
45
+ before :each do
46
+ @database.security.readers << @user
47
+ @database.security.save
48
+
49
+ @server.username = "test_user"
50
+ @server.password = "test"
51
+ end
52
+
53
+ it "should allow the user to read the database content" do
54
+ result = @design.load
55
+ result.should be_true
56
+ end
57
+
58
+ it "should deny the user to manipulate the database content" do
59
+ lambda do
60
+ @design.save
61
+ end.should raise_error(CouchDB::Document::UnauthorizedError)
62
+ end
63
+
64
+ end
65
+
66
+ describe "adding a role to the database administrators" do
67
+
68
+ before :each do
69
+ @database.security.administrators << "dummy"
70
+ @database.security.save
71
+
72
+ @server.username = "test_user"
73
+ @server.password = "test"
74
+ end
75
+
76
+ it "should allow the user to manipulate the database content" do
77
+ result = @design.save
78
+ result.should be_true
79
+ end
80
+
81
+ end
82
+
83
+ describe "adding a role to the database readers" do
84
+
85
+ before :each do
86
+ @database.security.readers << "dummy"
87
+ @database.security.save
88
+
89
+ @server.username = "test_user"
90
+ @server.password = "test"
91
+ end
92
+
93
+ it "should allow the user to read the database content" do
94
+ result = @design.load
95
+ result.should be_true
96
+ end
97
+
98
+ it "should deny the user to manipulate the database content" do
99
+ lambda do
100
+ @design.save
101
+ end.should raise_error(CouchDB::Document::UnauthorizedError)
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -1,14 +1,14 @@
1
1
  require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
2
 
3
- describe CouchDB::Document do
3
+ describe "document handling" do
4
4
 
5
5
  before :each do
6
- @server = CouchDB::Server.new
7
- @database = CouchDB::Database.new @server, "test"
6
+ @server = make_test_server
7
+ @database = make_test_database @server
8
8
  @database.delete_if_exists!
9
9
  @database.create_if_missing!
10
10
 
11
- @document = described_class.new @database, "_id" => "test_document_1", "test" => "test value"
11
+ @document = CouchDB::Document.new @database, "_id" => "test_document_1", "test" => "test value"
12
12
  @document.save
13
13
  end
14
14
 
@@ -16,7 +16,7 @@ describe CouchDB::Document do
16
16
  @document.destroy
17
17
  end
18
18
 
19
- describe "load" do
19
+ describe "loading" do
20
20
 
21
21
  it "should load the document's properties" do
22
22
  @document["test"] = nil
@@ -26,9 +26,9 @@ describe CouchDB::Document do
26
26
 
27
27
  end
28
28
 
29
- describe "save" do
29
+ describe "saving" do
30
30
 
31
- context "on a new model" do
31
+ context "of a new model" do
32
32
 
33
33
  before :each do
34
34
  begin
@@ -46,7 +46,7 @@ describe CouchDB::Document do
46
46
 
47
47
  end
48
48
 
49
- context "on an existing model" do
49
+ context "of an existing model" do
50
50
 
51
51
  it "should update the document" do
52
52
  lambda do
@@ -59,7 +59,7 @@ describe CouchDB::Document do
59
59
 
60
60
  end
61
61
 
62
- describe "destroy" do
62
+ describe "destroying" do
63
63
 
64
64
  it "should destroy the document" do
65
65
  lambda do
@@ -1,12 +1,12 @@
1
1
  require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
2
 
3
- describe CouchDB::Server do
3
+ describe "server" do
4
4
 
5
5
  before :each do
6
- @server = described_class.new
6
+ @server = make_test_server
7
7
  end
8
8
 
9
- describe "information" do
9
+ describe "fetching information" do
10
10
 
11
11
  it "should return some information about the server" do
12
12
  @server.information.should == { "couchdb" => "Welcome", "version" => "1.0.1" }
@@ -14,7 +14,7 @@ describe CouchDB::Server do
14
14
 
15
15
  end
16
16
 
17
- describe "statistics" do
17
+ describe "fetching statistics" do
18
18
 
19
19
  it "should return some statistics about the server" do
20
20
  @server.statistics.should be_instance_of(Hash)
@@ -22,7 +22,7 @@ describe CouchDB::Server do
22
22
 
23
23
  end
24
24
 
25
- describe "database_names" do
25
+ describe "fetching database_names" do
26
26
 
27
27
  it "should return the names of all databases" do
28
28
  @server.database_names.should be_instance_of(Array)
@@ -30,7 +30,7 @@ describe CouchDB::Server do
30
30
 
31
31
  end
32
32
 
33
- describe "uuids" do
33
+ describe "fetching uuids" do
34
34
 
35
35
  it "should return the given number of generated uuids" do
36
36
  uuids = @server.uuids 4
@@ -0,0 +1,84 @@
1
+ require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
+
3
+ describe "user management" do
4
+
5
+ before :each do
6
+ @server = make_test_server
7
+ @server.password_salt = "salt"
8
+
9
+ @user_database = @server.user_database
10
+ end
11
+
12
+ describe "creating an user" do
13
+
14
+ before :each do
15
+ @user = CouchDB::User.new @user_database, "test_user"
16
+ @user.password = "test"
17
+ @user.roles = [ "dummy" ]
18
+ end
19
+
20
+ it "should be indicated by a #save method that returns true" do
21
+ result = @user.save
22
+ result.should be_true
23
+ end
24
+
25
+ it "should create the user" do
26
+ @user.save
27
+ @user_database.users.should include(@user)
28
+ end
29
+
30
+ it "should store all attributes" do
31
+ @user.save
32
+ @user.load
33
+ @user.name.should == "test_user"
34
+ @user.password.should == "f438229716cab43569496f3a3630b3727524b81b"
35
+ @user.roles.should == [ "dummy" ]
36
+ end
37
+
38
+ end
39
+
40
+ describe "updating an user" do
41
+
42
+ before :each do
43
+ @user = CouchDB::User.new @user_database, "test_user"
44
+ @user.password = "test"
45
+ @user.roles = [ "dummy" ]
46
+ @user.save
47
+ @user.password = "another_test"
48
+ end
49
+
50
+ it "should be indicated by a #save method that returns true" do
51
+ result = @user.save
52
+ result.should be_true
53
+ end
54
+
55
+ it "should update all attributes" do
56
+ @user.save
57
+ @user.load
58
+ @user.password.should == "9ab52af5e5eb1cac7c2ff6eac610872bf0e6ab5c"
59
+ end
60
+
61
+ end
62
+
63
+ describe "destroying an user" do
64
+
65
+ before :each do
66
+ @user = CouchDB::User.new @user_database, "test_user"
67
+ @user.password = "test"
68
+ @user.roles = [ "dummy" ]
69
+ @user.save
70
+ end
71
+
72
+ it "should be indicated by a #destroy method that returns true" do
73
+ result = @user.destroy
74
+ result.should be_true
75
+ end
76
+
77
+ it "should remove the user" do
78
+ @user.destroy
79
+ @user_database.users.should_not include(@user)
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -3,19 +3,21 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
3
3
  describe "views" do
4
4
 
5
5
  before :each do
6
- @server = CouchDB::Server.new
7
- @database = CouchDB::Database.new @server, "test"
6
+ @server = make_test_server
7
+ @database = make_test_database @server
8
8
  @database.delete_if_exists!
9
9
  @database.create_if_missing!
10
10
 
11
11
  @document_one = CouchDB::Document.new @database, "_id" => "test_document_1", "category" => "one"
12
12
  @document_one.save
13
- @document_two = CouchDB::Document.new @database, "_id" => "test_document_2", "category" => "two"
13
+ @document_two = CouchDB::Document.new @database, "_id" => "test_document_2", "category" => "one"
14
14
  @document_two.save
15
+ @document_three = CouchDB::Document.new @database, "_id" => "test_document_3", "category" => "two"
16
+ @document_three.save
15
17
 
16
18
  @design = CouchDB::Design.new @database, "design_1"
17
19
  @view = CouchDB::Design::View.new @design, "view_1",
18
- "function(document) { emit([ document['category'], document['_id'] ]); }"
20
+ "function(document) { emit([ document['category'], document['_id'] ], 1); }"
19
21
  @design.save
20
22
  end
21
23
 
@@ -34,16 +36,39 @@ describe "views" do
34
36
 
35
37
  it "should return a collection including the right rows" do
36
38
  collection = @view.collection :startkey => [ "one", nil ], :endkey => [ "one", { } ]
37
- collection.size.should == 1
39
+ collection.size.should == 2
38
40
  collection[0].id.should == "test_document_1"
39
41
  collection[0].key.should == [ "one", "test_document_1" ]
40
- collection[0].value.should be_nil
42
+ collection[0].value.should == 1
43
+ collection[1].id.should == "test_document_2"
44
+ collection[1].key.should == [ "one", "test_document_2" ]
45
+ collection[1].value.should == 1
41
46
  end
42
47
 
43
48
  it "should return a collection including the right documents" do
44
49
  collection = @view.collection :startkey => [ "one", nil ], :endkey => [ "one", { } ]
45
50
  collection.documents.should include(@document_one)
46
- collection.documents.should_not include(@document_two)
51
+ collection.documents.should include(@document_two)
52
+ collection.documents.should_not include(@document_three)
53
+ end
54
+
55
+ end
56
+
57
+ describe "reduced collection" do
58
+
59
+ before :each do
60
+ @view = CouchDB::Design::View.new @design, "view_2",
61
+ "function(document) { emit(document['category'], 1); }",
62
+ "function(key, values, rereduce) { return sum(values); }"
63
+ @design.save
64
+ end
65
+
66
+ it "should return a collection including the right rows" do
67
+ collection = @view.collection :key => "one", :group => true
68
+ collection.size.should == 1
69
+ collection[0].id.should be_nil
70
+ collection[0].key.should == "one"
71
+ collection[0].value.should == 2
47
72
  end
48
73
 
49
74
  end
@@ -52,7 +77,7 @@ describe "views" do
52
77
 
53
78
  it "should return a collection with all documents of the database" do
54
79
  collection = @database.documents
55
- collection.size.should == 3 # two documents plus the design
80
+ collection.size.should == 4 # three documents plus the design
56
81
  end
57
82
 
58
83
  end
@@ -4,7 +4,7 @@ describe CouchDB::Collection do
4
4
 
5
5
  before :each do
6
6
  Transport::JSON.stub(:request)
7
- @database = mock CouchDB::Database
7
+ @database = mock CouchDB::Database, :authentication_options => { }
8
8
 
9
9
  @collection = described_class.new @database, "http://host:1234/test/_all_docs"
10
10
  end
@@ -3,8 +3,11 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_hel
3
3
  describe CouchDB::Database do
4
4
 
5
5
  before :each do
6
- Transport::JSON.stub(:request)
7
- @server = mock CouchDB::Server, :url => "http://host:1234", :database_names => [ "test" ]
6
+ Transport::JSON.stub :request => nil
7
+ @server = mock CouchDB::Server,
8
+ :url => "http://host:1234",
9
+ :database_names => [ "test" ],
10
+ :authentication_options => { }
8
11
 
9
12
  @database = CouchDB::Database.new @server, "test"
10
13
  end
@@ -4,7 +4,9 @@ describe CouchDB::Document do
4
4
 
5
5
  before :each do
6
6
  Transport::JSON.stub(:request)
7
- @database = mock CouchDB::Database, :url => "http://host:1234/test"
7
+ @database = mock CouchDB::Database,
8
+ :url => "http://host:1234/test",
9
+ :authentication_options => { }
8
10
  @document = described_class.new @database, "_id" => "test_document_1"
9
11
  end
10
12
 
@@ -182,9 +184,11 @@ describe CouchDB::Document do
182
184
  @document.rev.should == 1
183
185
  end
184
186
 
185
- it "should return false on wrong status code" do
186
- Transport::JSON.stub(:request).and_raise(Transport::UnexpectedStatusCodeError.new(404))
187
- @document.save.should be_false
187
+ it "should upgrade some status errors" do
188
+ Transport::JSON.stub(:request).and_raise(Transport::UnexpectedStatusCodeError.new(401))
189
+ lambda do
190
+ @document.save
191
+ end.should raise_error(CouchDB::Document::UnauthorizedError)
188
192
  end
189
193
 
190
194
  end
@@ -219,9 +223,11 @@ describe CouchDB::Document do
219
223
  @document.rev.should == 2
220
224
  end
221
225
 
222
- it "should return false on wrong status code" do
223
- Transport::JSON.stub!(:request).and_raise(Transport::UnexpectedStatusCodeError.new(404))
224
- @document.save.should be_false
226
+ it "should upgrade some status errors" do
227
+ Transport::JSON.stub(:request).and_raise(Transport::UnexpectedStatusCodeError.new(401))
228
+ lambda do
229
+ @document.save
230
+ end.should raise_error(CouchDB::Document::UnauthorizedError)
225
231
  end
226
232
 
227
233
  end
@@ -3,11 +3,12 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_hel
3
3
  describe CouchDB::Server do
4
4
 
5
5
  before :each do
6
- Transport::JSON.stub(:request)
7
- @server = CouchDB::Server.new "host", 1234
6
+ Transport::JSON.stub :request => nil
7
+
8
+ @server = CouchDB::Server.new "host", 1234, "test", "test"
8
9
  end
9
10
 
10
- describe "initialize" do
11
+ describe "#initialize" do
11
12
 
12
13
  it "should set the host" do
13
14
  @server.host.should == "host"
@@ -17,9 +18,17 @@ describe CouchDB::Server do
17
18
  @server.port.should == 1234
18
19
  end
19
20
 
21
+ it "should set the username" do
22
+ @server.username.should == "test"
23
+ end
24
+
25
+ it "should set the password" do
26
+ @server.password.should == "test"
27
+ end
28
+
20
29
  end
21
30
 
22
- describe "==" do
31
+ describe "#==" do
23
32
 
24
33
  it "should be true when comparing two equal servers" do
25
34
  @server.should == described_class.new("host", 1234)
@@ -31,9 +40,22 @@ describe CouchDB::Server do
31
40
 
32
41
  end
33
42
 
34
- describe "information" do
43
+ describe "#information" do
35
44
 
36
45
  it "should request server information" do
46
+ Transport::JSON.should_receive(:request).with(
47
+ :get,
48
+ "http://host:1234/",
49
+ :expected_status_code => 200,
50
+ :auth_type => :basic,
51
+ :username => "test",
52
+ :password => "test"
53
+ ).and_return("result")
54
+ @server.information.should == "result"
55
+ end
56
+
57
+ it "should request server information without authentication if no credentials are given" do
58
+ @server.username = @server.password = nil
37
59
  Transport::JSON.should_receive(:request).with(
38
60
  :get,
39
61
  "http://host:1234/",
@@ -44,39 +66,48 @@ describe CouchDB::Server do
44
66
 
45
67
  end
46
68
 
47
- describe "statistics" do
69
+ describe "#statistics" do
48
70
 
49
71
  it "should request server statistics" do
50
72
  Transport::JSON.should_receive(:request).with(
51
73
  :get,
52
74
  "http://host:1234/_stats",
53
- :expected_status_code => 200
75
+ :expected_status_code => 200,
76
+ :auth_type => :basic,
77
+ :username => "test",
78
+ :password => "test"
54
79
  ).and_return("result")
55
80
  @server.statistics.should == "result"
56
81
  end
57
82
 
58
83
  end
59
84
 
60
- describe "database_names" do
85
+ describe "#database_names" do
61
86
 
62
87
  it "should request the names of all databases" do
63
88
  Transport::JSON.should_receive(:request).with(
64
89
  :get,
65
90
  "http://host:1234/_all_dbs",
66
- :expected_status_code => 200
91
+ :expected_status_code => 200,
92
+ :auth_type => :basic,
93
+ :username => "test",
94
+ :password => "test"
67
95
  ).and_return("result")
68
96
  @server.database_names.should == "result"
69
97
  end
70
98
 
71
99
  end
72
100
 
73
- describe "uuids" do
101
+ describe "#uuids" do
74
102
 
75
103
  it "should request a given number of uuids" do
76
104
  Transport::JSON.should_receive(:request).with(
77
105
  :get,
78
106
  "http://host:1234/_uuids",
79
107
  :expected_status_code => 200,
108
+ :auth_type => :basic,
109
+ :username => "test",
110
+ :password => "test",
80
111
  :parameters => { :count => 3 }
81
112
  ).and_return({ "uuids" => "result" })
82
113
  @server.uuids(3).should == "result"
@@ -3,3 +3,11 @@ gem 'rspec', '>= 2'
3
3
  require 'rspec'
4
4
 
5
5
  require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "couchdb"))
6
+
7
+ def make_test_server
8
+ CouchDB::Server.new "localhost", 5984, "test", "test"
9
+ end
10
+
11
+ def make_test_database(server)
12
+ CouchDB::Database.new server, "test"
13
+ end
metadata CHANGED
@@ -1,137 +1,122 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: couchdb
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 1
8
- - 3
9
- version: 0.1.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
12
- - "Philipp Br\xC3\xBCll"
7
+ authors:
8
+ - Philipp Brüll
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2011-02-21 00:00:00 +01:00
12
+ date: 2011-08-26 00:00:00.000000000 +02:00
18
13
  default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
21
16
  name: transport
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: &20665540 !ruby/object:Gem::Requirement
24
18
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 1
30
- - 0
31
- - 1
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
32
22
  version: 1.0.1
33
23
  type: :runtime
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: rspec
37
24
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: *20665540
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &20664860 !ruby/object:Gem::Requirement
39
29
  none: false
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- segments:
44
- - 2
45
- version: "2"
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '2'
46
34
  type: :development
47
- version_requirements: *id002
48
- - !ruby/object:Gem::Dependency
49
- name: reek
50
35
  prerelease: false
51
- requirement: &id003 !ruby/object:Gem::Requirement
36
+ version_requirements: *20664860
37
+ - !ruby/object:Gem::Dependency
38
+ name: reek
39
+ requirement: &20664200 !ruby/object:Gem::Requirement
52
40
  none: false
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- segments:
57
- - 1
58
- - 2
59
- version: "1.2"
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '1.2'
60
45
  type: :development
61
- version_requirements: *id003
62
- description: A straight-forward client for CouchDB REST API. The resources exposed by the API are simply wrapped into classes.
46
+ prerelease: false
47
+ version_requirements: *20664200
48
+ description: A straight-forward client for CouchDB REST API. The resources exposed
49
+ by the API are simply wrapped into classes.
63
50
  email: b.phifty@gmail.com
64
51
  executables: []
65
-
66
52
  extensions: []
67
-
68
- extra_rdoc_files:
53
+ extra_rdoc_files:
69
54
  - README.rdoc
70
- files:
55
+ files:
71
56
  - README.rdoc
72
57
  - LICENSE
73
58
  - Rakefile
74
- - lib/couchdb/server.rb
75
- - lib/couchdb/design/view.rb
76
59
  - lib/couchdb/design.rb
77
60
  - lib/couchdb/database.rb
78
61
  - lib/couchdb/row.rb
79
- - lib/couchdb/collection.rb
62
+ - lib/couchdb/user_database.rb
63
+ - lib/couchdb/user.rb
80
64
  - lib/couchdb/document.rb
65
+ - lib/couchdb/security.rb
66
+ - lib/couchdb/design/view.rb
67
+ - lib/couchdb/collection.rb
68
+ - lib/couchdb/server.rb
81
69
  - lib/couchdb.rb
82
- - spec/lib/couchdb/design/view_spec.rb
83
- - spec/lib/couchdb/collection_spec.rb
84
70
  - spec/lib/couchdb/row_spec.rb
85
- - spec/lib/couchdb/document_spec.rb
86
71
  - spec/lib/couchdb/database_spec.rb
87
- - spec/lib/couchdb/server_spec.rb
72
+ - spec/lib/couchdb/document_spec.rb
88
73
  - spec/lib/couchdb/design_spec.rb
74
+ - spec/lib/couchdb/collection_spec.rb
75
+ - spec/lib/couchdb/server_spec.rb
76
+ - spec/lib/couchdb/design/view_spec.rb
89
77
  - spec/spec_helper.rb
90
- - spec/acceptance/document_spec.rb
91
- - spec/acceptance/database_spec.rb
92
78
  - spec/acceptance/views_spec.rb
79
+ - spec/acceptance/user_management_spec.rb
80
+ - spec/acceptance/database_management_spec.rb
93
81
  - spec/acceptance/server_spec.rb
82
+ - spec/acceptance/database_security_spec.rb
83
+ - spec/acceptance/document_handling_spec.rb
94
84
  has_rdoc: true
95
85
  homepage: http://github.com/phifty/couchdb
96
86
  licenses: []
97
-
98
87
  post_install_message:
99
88
  rdoc_options: []
100
-
101
- require_paths:
89
+ require_paths:
102
90
  - lib
103
- required_ruby_version: !ruby/object:Gem::Requirement
91
+ required_ruby_version: !ruby/object:Gem::Requirement
104
92
  none: false
105
- requirements:
106
- - - ">="
107
- - !ruby/object:Gem::Version
108
- segments:
109
- - 0
110
- version: "0"
111
- required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
98
  none: false
113
- requirements:
114
- - - ">="
115
- - !ruby/object:Gem::Version
116
- segments:
117
- - 0
118
- version: "0"
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
119
103
  requirements: []
120
-
121
104
  rubyforge_project: couchdb
122
- rubygems_version: 1.3.7
105
+ rubygems_version: 1.6.2
123
106
  signing_key:
124
107
  specification_version: 3
125
108
  summary: A straight-forward client for CouchDB REST API.
126
- test_files:
127
- - spec/lib/couchdb/design/view_spec.rb
128
- - spec/lib/couchdb/collection_spec.rb
109
+ test_files:
129
110
  - spec/lib/couchdb/row_spec.rb
130
- - spec/lib/couchdb/document_spec.rb
131
111
  - spec/lib/couchdb/database_spec.rb
132
- - spec/lib/couchdb/server_spec.rb
112
+ - spec/lib/couchdb/document_spec.rb
133
113
  - spec/lib/couchdb/design_spec.rb
134
- - spec/acceptance/document_spec.rb
135
- - spec/acceptance/database_spec.rb
114
+ - spec/lib/couchdb/collection_spec.rb
115
+ - spec/lib/couchdb/server_spec.rb
116
+ - spec/lib/couchdb/design/view_spec.rb
136
117
  - spec/acceptance/views_spec.rb
118
+ - spec/acceptance/user_management_spec.rb
119
+ - spec/acceptance/database_management_spec.rb
137
120
  - spec/acceptance/server_spec.rb
121
+ - spec/acceptance/database_security_spec.rb
122
+ - spec/acceptance/document_handling_spec.rb