couchdb 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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