summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml13
-rw-r--r--Gemfile.lock6
-rw-r--r--Rakefile2
-rwxr-xr-xbin/tapicero13
-rw-r--r--lib/tapicero.rb26
-rw-r--r--lib/tapicero/user_database.rb53
-rw-r--r--lib/tapicero/user_event_handler.rb44
-rw-r--r--lib/tapicero/version.rb3
-rw-r--r--lib/tapicero_daemon.rb26
-rw-r--r--test/config.yaml19
-rw-r--r--test/config/config.yaml5
-rw-r--r--test/integration/tapicero_test.rb37
-rw-r--r--test/integration/test_setup_test.rb15
-rw-r--r--test/setup_couch.sh13
-rw-r--r--test/support/integration_test.rb39
-rw-r--r--test/test_helper.rb15
-rw-r--r--test/unit/couch_changes_test.rb32
-rw-r--r--test/unit/couch_stream_test.rb29
18 files changed, 249 insertions, 141 deletions
diff --git a/.travis.yml b/.travis.yml
index 984e24a..3fd27a7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,2 +1,15 @@
+rvm:
+ - "1.9.3"
services:
- couchdb
+notifications:
+ email: false
+before_script:
+ - "/bin/bash test/setup_couch.sh"
+ - "touch /tmp/tapicero_test.log"
+ - "bundle exec bin/tapicero start test/config.yaml"
+ - "bundle exec bin/tapicero status"
+ - "cat /tmp/tapicero_test.log"
+after_script:
+ - "cat /tmp/tapicero_test.log"
+ - "cat /tmp/tapicero_test.seq"
diff --git a/Gemfile.lock b/Gemfile.lock
index afbb265..917a4f7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,9 +1,9 @@
PATH
remote: .
specs:
- tapicero (0.3.1)
+ tapicero (0.3.2)
couchrest (~> 1.1.3)
- couchrest_changes (~> 0.0.4)
+ couchrest_changes (~> 0.0.5)
daemons
syslog_logger (~> 2.0.0)
yajl-ruby (~> 1.1.0)
@@ -15,7 +15,7 @@ GEM
mime-types (~> 1.15)
multi_json (~> 1.0)
rest-client (~> 1.6.1)
- couchrest_changes (0.0.4)
+ couchrest_changes (0.0.5)
couchrest (~> 1.1.3)
syslog_logger (~> 2.0.0)
yajl-ruby
diff --git a/Rakefile b/Rakefile
index 7293cb2..6137fc1 100644
--- a/Rakefile
+++ b/Rakefile
@@ -76,7 +76,7 @@ end
##
Rake::TestTask.new do |t|
- t.pattern = "test/unit/*_test.rb"
+ t.pattern = "test/*/*_test.rb"
end
task :default => :test
diff --git a/bin/tapicero b/bin/tapicero
index c20a114..72f974b 100755
--- a/bin/tapicero
+++ b/bin/tapicero
@@ -1,10 +1,10 @@
-#!/usr/bin/ruby
+#!/usr/bin/env ruby
-require 'pathname'
#
# Tapicero Daemon
#
+require 'pathname'
BASE_DIR = Pathname.new(__FILE__).realpath + '../..'
begin
@@ -46,7 +46,8 @@ end
# --overwrite-security overwrite existing couch security settings
# TODO: not implemented yet:
# --overwrite-designs overwrite existing design documents
-Tapicero::FLAGS.concat ARGV.grep(/--.*/)
+Tapicero::FLAGS.concat ARGV.grep(/--.*/)
+Tapicero::CONFIGS.concat ARGV.grep(/\.ya?ml$/)
# if flags have been set but an action is missing we assume
# tapicero should run in foreground.
@@ -59,7 +60,6 @@ end
#
# Start the daemon
#
-require 'tapicero' # so we can use Tapicero.logger below.
require 'daemons'
if ENV["USER"] == "root"
options = {:app_name => 'tapicero', :dir_mode => :system} # this will put the pid file in /var/run
@@ -70,7 +70,6 @@ begin
Daemons.run("#{BASE_DIR}/lib/tapicero_daemon.rb", options)
rescue SystemExit
rescue Exception => exc
- Tapicero.logger.error "Uncaught exception. Daemon will die."
- Tapicero.logger.error exc.class.name + ": " + exc.to_s
- Tapicero.logger.error exc.backtrace.join("\n")
+ puts exc.class.name + exc.to_s
+ puts exc.backtrace.join("\n")
end
diff --git a/lib/tapicero.rb b/lib/tapicero.rb
index e2a8f38..a098287 100644
--- a/lib/tapicero.rb
+++ b/lib/tapicero.rb
@@ -1,9 +1,6 @@
unless defined? BASE_DIR
BASE_DIR = Pathname.new(__FILE__) + '../..'
end
-unless defined? TAPICERO_CONFIG
- TAPICERO_CONFIG = '/etc/leap/tapicero.yaml'
-end
module Tapicero
class <<self
@@ -11,27 +8,24 @@ module Tapicero
attr_accessor :config
end
-
+ # reraise exceptions instead of retrying
+ # used in tests
+ unless defined? RERAISE
+ RERAISE = false
+ end
#
# Load Config
# this must come first, because CouchRest needs the connection
# defined before the models are defined.
#
require 'couchrest/changes'
- configs = ['config/default.yaml', TAPICERO_CONFIG, ARGV.grep(/\.ya?ml$/).first]
- self.config = CouchRest::Changes::Config.load(BASE_DIR, *configs)
+ self.config = CouchRest::Changes::Config.load(BASE_DIR, *CONFIGS)
self.logger = CouchRest::Changes::Config.logger
# hand flags over to CouchRest::Changes
- config.flags = FLAGS
- puts "flags: #{FLAGS}" if FLAGS.any?
-
- #
- # Load Tapicero Parts
- #
- require 'tapicero/user_database'
-
- def self.user_database(id)
- UserDatabase.new(config.couch_host, config.options[:db_prefix] + id)
+ if defined? FLAGS
+ config.flags = FLAGS
+ puts "flags: #{FLAGS}" if FLAGS.any?
end
+
end
diff --git a/lib/tapicero/user_database.rb b/lib/tapicero/user_database.rb
index 3cfdd70..26d013d 100644
--- a/lib/tapicero/user_database.rb
+++ b/lib/tapicero/user_database.rb
@@ -4,16 +4,8 @@ require 'json'
module Tapicero
class UserDatabase
- def initialize(host, name)
- @host = host
- @name = name
- end
-
- def prepare(config)
- create
- secure(config.options[:security])
- add_design_docs
- Tapicero.logger.info "Prepared storage " + name
+ def initialize(user_id)
+ @db = couch.database(config.options[:db_prefix] + user_id)
end
def create
@@ -22,7 +14,8 @@ module Tapicero
end
end
- def secure(security)
+ def secure(security = nil)
+ security ||= config.options[:security]
# let's not overwrite if we have a security doc already
return if secured? && !Tapicero::FLAGS.include?('--overwrite-security')
retry_request_once "Writing security to" do
@@ -42,9 +35,9 @@ module Tapicero
end
def upload_design_doc(file)
- url = design_url(file.basename('.json'))
- CouchRest.put url, JSON.parse(file.read)
- rescue RestClient::Conflict
+ old = CouchRest.get design_url(file.basename('.json'))
+ rescue RestClient::ResourceNotFound
+ CouchRest.put design_url(file.basename('.json')), JSON.parse(file.read)
end
@@ -54,28 +47,33 @@ module Tapicero
end
end
+ def name
+ db.name
+ end
+
protected
def create_db
- CouchRest.new(host).create_db(name)
- rescue RestClient::PreconditionFailed # database already existed
+ db.info # test if db exists
+ rescue RestClient::ResourceNotFound
+ couch.create_db(db.name)
end
def delete_db
- db = CouchRest.new(host).database(name)
db.delete! if db
rescue RestClient::ResourceNotFound # no database found
end
def retry_request_once(action)
second_try ||= false
- Tapicero.logger.debug "#{action} #{name}"
+ Tapicero.logger.debug "#{action} #{db.name}"
yield
rescue RestClient::Exception => exc
+ raise exc if Tapicero::RERAISE
if second_try
- log_error "#{action} #{name} failed twice due to:", exc
+ log_error "#{action} #{db.name} failed twice due to:", exc
else
- log_error "#{action} #{name} failed due to:", exc
+ log_error "#{action} #{db.name} failed due to:", exc
sleep 5
second_try = true
retry
@@ -95,13 +93,22 @@ module Tapicero
end
def security_url
- "#{host}/#{name}/_security"
+ db.root + "/_security"
end
def design_url(doc_name)
- "#{host}/#{name}/_design/#{doc_name}"
+ db.root + "/_design/#{doc_name}"
+ end
+
+ attr_reader :db
+
+ def couch
+ @couch ||= CouchRest.new(config.couch_host)
+ end
+
+ def config
+ Tapicero.config
end
- attr_reader :host, :name
end
end
diff --git a/lib/tapicero/user_event_handler.rb b/lib/tapicero/user_event_handler.rb
new file mode 100644
index 0000000..38cf8f8
--- /dev/null
+++ b/lib/tapicero/user_event_handler.rb
@@ -0,0 +1,44 @@
+require 'tapicero/user_database'
+module Tapicero
+ class UserEventHandler
+ def initialize(users)
+ users.created do |hash|
+ prepare_db(hash['id'])
+ end
+
+ # Sometimes changes log starts with rev 2. So the
+ # detection of is currently not working properly
+ # Working around this until a new version of
+ # couchrest changes takes this into account.
+ users.updated do |hash|
+ prepare_db(hash['id'])
+ end
+
+ users.deleted do |hash|
+ destroy_db(hash['id'])
+ end
+ end
+
+ protected
+
+ def prepare_db(id)
+ db = user_database(id)
+ db.create
+ db.secure
+ db.add_design_docs
+ logger.info "Prepared storage " + db.name
+ end
+
+ def destroy_db(id)
+ user_database(id).destroy
+ end
+
+ def logger
+ Tapicero.logger
+ end
+
+ def user_database(id)
+ UserDatabase.new(id)
+ end
+ end
+end
diff --git a/lib/tapicero/version.rb b/lib/tapicero/version.rb
index 1d372e5..8b7a6b0 100644
--- a/lib/tapicero/version.rb
+++ b/lib/tapicero/version.rb
@@ -1,5 +1,6 @@
module Tapicero
- VERSION = "0.3.2"
+ VERSION = "0.4.0"
REQUIRE_PATHS = ['lib']
FLAGS = []
+ CONFIGS = ['config/default.yaml', '/etc/leap/tapicero.yaml']
end
diff --git a/lib/tapicero_daemon.rb b/lib/tapicero_daemon.rb
index 23248e3..89566de 100644
--- a/lib/tapicero_daemon.rb
+++ b/lib/tapicero_daemon.rb
@@ -4,30 +4,14 @@
#
# Daemons.run('tapicero_daemon.rb')
#
-
require 'tapicero'
module Tapicero
- users = CouchRest::Changes.new('users')
-
- users.created do |hash|
- logger.debug "Created user " + hash['id']
- user_database(hash['id']).prepare(config)
- end
+ module Daemon
+ require 'tapicero/user_event_handler'
+ users = CouchRest::Changes.new('users')
+ UserEventHandler.new(users)
+ users.listen
- # Sometimes changes log starts with rev 2. So the
- # detection of is currently not working properly
- # Working around this until a new version of
- # couchrest changes takes this into account.
- users.updated do |hash|
- logger.debug "Updated user " + hash['id']
- user_database(hash['id']).prepare(config)
end
-
- users.deleted do |hash|
- logger.debug "Deleted user " + hash['id']
- user_database(hash['id']).destroy
- end
-
- users.listen
end
diff --git a/test/config.yaml b/test/config.yaml
new file mode 100644
index 0000000..e59b4de
--- /dev/null
+++ b/test/config.yaml
@@ -0,0 +1,19 @@
+#
+# Default configuration options for Tapicero
+#
+
+# couch connection configuration
+connection:
+ protocol: "http"
+ host: "localhost"
+ port: 5984
+ username: anna
+ password: secret
+ prefix: "tapicero_test"
+ suffix: ""
+
+# file to store the last processed user record in so we can resume after
+# a restart:
+seq_file: "/tmp/tapicero_test.seq"
+log_file: "/tmp/tapicero_test.log"
+log_level: debug
diff --git a/test/config/config.yaml b/test/config/config.yaml
deleted file mode 100644
index ee10fe6..0000000
--- a/test/config/config.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# testing configuration options
-#
-
-db_prefix: "tapicero_test-"
diff --git a/test/integration/tapicero_test.rb b/test/integration/tapicero_test.rb
new file mode 100644
index 0000000..88e3715
--- /dev/null
+++ b/test/integration/tapicero_test.rb
@@ -0,0 +1,37 @@
+require_relative '../test_helper.rb'
+
+class TapiceroTest < Tapicero::IntegrationTest
+
+ def setup
+ create_user
+ end
+
+ def teardown
+ delete_user(true)
+ end
+
+ def test_creates_user_db
+ assert user_database
+ assert user_database.name.start_with?(config.options[:db_prefix])
+ assert user_database.info # ensure db exists in couch.
+ end
+
+ def test_configures_security
+ assert_equal config.options[:security], user_database.get('_security')
+ end
+
+ def test_stores_design_docs
+ assert_equal ['_design/docs', '_design/syncs', '_design/transactions'],
+ design_docs(user_database).map{|doc| doc["id"]}.sort
+ end
+
+ def test_cleares_user_db
+ assert user_database.info # ensure db exists in couch.
+ delete_user
+ assert !host.databases.include?(user_database.name)
+ end
+
+ def design_docs(db)
+ db.documents(startkey: '_design', endkey: '_design'.succ)["rows"]
+ end
+end
diff --git a/test/integration/test_setup_test.rb b/test/integration/test_setup_test.rb
new file mode 100644
index 0000000..525c14d
--- /dev/null
+++ b/test/integration/test_setup_test.rb
@@ -0,0 +1,15 @@
+require_relative '../test_helper.rb'
+
+class TestSetupTest < Tapicero::IntegrationTest
+
+ def test_loads_config
+ assert_equal "tapicero_test", config.connection[:prefix]
+ assert_equal "debug", config.send(:log_level)
+ end
+
+ def test_database_exists
+ assert database
+ assert_equal "tapicero_test_users", database.name
+ end
+
+end
diff --git a/test/setup_couch.sh b/test/setup_couch.sh
new file mode 100644
index 0000000..c11993d
--- /dev/null
+++ b/test/setup_couch.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+HOST="http://localhost:5984"
+echo "couch version :"
+curl -X GET $HOST
+echo "creating unprivileged user :"
+curl -HContent-Type:application/json -XPUT $HOST/_users/org.couchdb.user:me --data-binary '{"_id": "org.couchdb.user:me","name": "me","roles": [],"type": "user","password": "pwd"}'
+echo "creating database to watch:"
+curl -X PUT $HOST/tapicero_test_users
+echo "restricting database access :"
+curl -X PUT $HOST/tapicero_test_users/_security -Hcontent-type:application/json --data-binary '{"admins":{"names":[],"roles":[]},"members":{"names":["me"],"roles":[]}}'
+echo "adding admin :"
+curl -X PUT $HOST/_config/admins/anna -d '"secret"'
diff --git a/test/support/integration_test.rb b/test/support/integration_test.rb
new file mode 100644
index 0000000..b28c0e1
--- /dev/null
+++ b/test/support/integration_test.rb
@@ -0,0 +1,39 @@
+module Tapicero
+ class IntegrationTest < MiniTest::Unit::TestCase
+
+ def create_user(fast = false)
+ result = database.save_doc :some => :content
+ raise RuntimeError.new(result.inspect) unless result['ok']
+ sleep 1 unless fast # allow tapicero to do its job
+ @user = {'_id' => result["id"], '_rev' => result["rev"]}
+ end
+
+ def delete_user(fast = false)
+ return if @user.nil? or @user['_deleted']
+ result = database.delete_doc @user
+ raise RuntimeError.new(result.inspect) unless result['ok']
+ @user['_deleted'] = true
+ sleep 1 unless fast # allow tapicero to do its job
+ end
+
+ def user_database
+ host.database(config.options[:db_prefix] + @user['_id'])
+ end
+
+ def database
+ @database ||= host.database(database_name)
+ end
+
+ def database_name
+ config.complete_db_name('users')
+ end
+
+ def host
+ @host ||= CouchRest.new(config.couch_host)
+ end
+
+ def config
+ Tapicero.config
+ end
+ end
+end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 3857e2c..5a3b509 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -1,10 +1,19 @@
require 'rubygems'
require 'minitest/autorun'
+require 'pathname'
-BASE_DIR = File.expand_path('../..', __FILE__)
-$:.unshift File.expand_path('lib', BASE_DIR)
+unless defined? BASE_DIR
+ BASE_DIR = Pathname.new(__FILE__) + '../..'
+end
+
+$:.unshift BASE_DIR + 'lib'
require 'mocha/setup'
-TAPICERO_CONFIG = "test/config/config.yaml"
+require 'tapicero/version'
+Tapicero::CONFIGS << "test/config.yaml"
+Tapicero::RERAISE = true
require 'tapicero'
+
+
+require_relative 'support/integration_test'
diff --git a/test/unit/couch_changes_test.rb b/test/unit/couch_changes_test.rb
deleted file mode 100644
index 043caf1..0000000
--- a/test/unit/couch_changes_test.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require File.expand_path('../../test_helper.rb', __FILE__)
-require 'tapicero/couch_changes'
-
-class CouchChangesTest < MiniTest::Unit::TestCase
-
- LAST_SEQ = 12
-
- def setup
- @stream = mock()
- @changes = Tapicero::CouchChanges.new(@stream)
- end
-
- def test_last_seq
- @stream.expects(:get).
- with('_changes', {:limit => 1, :descending => true}).
- yields(:last_seq => LAST_SEQ)
- assert_equal LAST_SEQ, @changes.last_seq
- end
-
- def test_follow
- stub_entry = {:new => :result}
- @stream.expects(:get).
- with('_changes', {:limit => 1, :descending => true}).
- yields(:last_seq => LAST_SEQ)
- @stream.expects(:get).
- with('_changes', {:feed => :continuous, :since => LAST_SEQ}).
- yields(stub_entry)
- @changes.follow do |hash|
- assert_equal stub_entry, hash
- end
- end
-end
diff --git a/test/unit/couch_stream_test.rb b/test/unit/couch_stream_test.rb
deleted file mode 100644
index a9de21f..0000000
--- a/test/unit/couch_stream_test.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require File.expand_path('../../test_helper.rb', __FILE__)
-require 'tapicero/couch_stream'
-
-class CouchStreamTest < MiniTest::Unit::TestCase
-
- def setup
- @root = "http://server/database"
- @stream = Tapicero::CouchStream.new(@root)
- @url = @root + "/_changes?a=b&c=d"
- @path = "_changes"
- @options = {:a => :b, :c => :d}
- end
-
- def test_get
- Tapicero::JsonStream.expects(:get).
- with(@url, :symbolize_keys => true).
- yields(stub_hash = stub)
- @stream.get(@path, @options) do |hash|
- assert_equal stub_hash, hash
- end
- end
-
- # internal
- def test_url_creation
- assert_equal "http://server/database/", @stream.send(:url_for, "")
- assert_equal @url, @stream.send(:url_for, @path, @options)
- end
-
-end