cassandra_integration 0.0.2
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.
- data/.gitignore +5 -0
- data/Gemfile +5 -0
- data/README.md +80 -0
- data/Rakefile +1 -0
- data/cassandra_integration.gemspec +26 -0
- data/lib/cassandra_integration.rb +11 -0
- data/lib/cassandra_integration/base.rb +39 -0
- data/lib/cassandra_integration/config.rb +50 -0
- data/lib/cassandra_integration/proxy.rb +47 -0
- data/lib/cassandra_integration/railtie.rb +18 -0
- data/lib/cassandra_integration/railties/cassandra_integration.rake +80 -0
- data/lib/cassandra_integration/version.rb +3 -0
- data/lib/generators/cassandra_integration_config_generator.rb +10 -0
- data/lib/generators/templates/cassandra_integration.yml +17 -0
- data/spec/base_spec.rb +81 -0
- data/spec/config_spec.rb +55 -0
- data/spec/dummy_class.rb +15 -0
- data/spec/proxy_spec.rb +90 -0
- data/spec/spec_helper.rb +6 -0
- metadata +113 -0
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
Cassandra Integration
|
2
|
+
=====================
|
3
|
+
|
4
|
+
This gem should help you integrate data from models of different Rails apps using Apache Cassandra to replicate them.
|
5
|
+
|
6
|
+
##References
|
7
|
+
|
8
|
+
[Apache Cassandra](http://cassandra.apache.org/)
|
9
|
+
[Apache Cassandra - Wiki](http://wiki.apache.org/cassandra/FrontPage)
|
10
|
+
|
11
|
+
|
12
|
+
##Installation
|
13
|
+
|
14
|
+
Include the gem in your Gemfile:
|
15
|
+
|
16
|
+
gem "cassandra_integration", :git => "git://github.com/dtmconsultoria/cassandra-integration.git"
|
17
|
+
bundle install
|
18
|
+
|
19
|
+
bundle exec rails generate cassandra_integration_config
|
20
|
+
#The generate command will create cassandra_integration.yml file on your config directory
|
21
|
+
|
22
|
+
|
23
|
+
cassandra_integration.yml
|
24
|
+
|
25
|
+
development:
|
26
|
+
host: 192.168.0.1:9160
|
27
|
+
keyspace: keyspace
|
28
|
+
app_id: id_for_this_application
|
29
|
+
other_apps_ids: id_for_other_app1,id_for_other_app2
|
30
|
+
retries: 3
|
31
|
+
timeout: 10
|
32
|
+
connect_timeout: 20
|
33
|
+
|
34
|
+
|
35
|
+
##Quick Start
|
36
|
+
|
37
|
+
On Cassandra, you must create a ColumnFamily:
|
38
|
+
|
39
|
+
**Attention for the last 3 column names. They are the apps identifiers configured on your cassandra_integration.yml**
|
40
|
+
|
41
|
+
create column family your_column_famly_name WITH comparator = UTF8Type
|
42
|
+
AND key_validation_class = UTF8Type
|
43
|
+
AND column_metadata = [
|
44
|
+
{column_name: name, validation_class: UTF8Type, index_type: KEYS},
|
45
|
+
{column_name: birth_date, validation_class: UTF8Type},
|
46
|
+
{column_name: mother_name, validation_class: UTF8Type},
|
47
|
+
|
48
|
+
{column_name: id_for_this_application, validation_class: UTF8Type, index_type: KEYS},
|
49
|
+
{column_name: id_for_other_app1, validation_class: UTF8Type, index_type: KEYS}
|
50
|
+
{column_name: id_for_other_app2, validation_class: UTF8Type, index_type: KEYS}];
|
51
|
+
|
52
|
+
|
53
|
+
You must create a migration for each model you want to sync:
|
54
|
+
|
55
|
+
add_column :your_model_name, :cassandra_sync_identifier, :string
|
56
|
+
|
57
|
+
On each model:
|
58
|
+
|
59
|
+
class User < ActiveRecord::Base
|
60
|
+
extend CassandraIntegration::Base
|
61
|
+
|
62
|
+
#Here goes the ColumnFamily name used to sync this model data
|
63
|
+
self.cassandra_column_family = 'people'
|
64
|
+
|
65
|
+
def to_cassandra_sync_identifier
|
66
|
+
#Here goes your unique identifier for all systems
|
67
|
+
#That will be the Cassandra's key identifier
|
68
|
+
"#{name.parameterize}##{mother.parameterize}##{birthdate}"
|
69
|
+
end
|
70
|
+
|
71
|
+
#Here goes the fields you want to sync
|
72
|
+
#The hash key is the column name on Cassandra and
|
73
|
+
#the hash value is the attribute name on your model
|
74
|
+
self.cassandra_columns_values_hash = {
|
75
|
+
:name => 'name',
|
76
|
+
:mother_name => 'mother',
|
77
|
+
:birth_date => 'birthdate'
|
78
|
+
}
|
79
|
+
|
80
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cassandra_integration/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "cassandra_integration"
|
7
|
+
s.version = CassandraIntegration::VERSION
|
8
|
+
s.authors = ["Marcelo Murad"]
|
9
|
+
s.email = ["marcelo.murad@dtmconsultoria.com"]
|
10
|
+
s.homepage = "https://github.com/dtmconsultoria/cassandra-Integration"
|
11
|
+
s.summary = %q{Permits integrate models from diferent apps using Cassandra for sync}
|
12
|
+
s.description = %q{Permits integrate models from diferent apps using Cassandra for sync}
|
13
|
+
|
14
|
+
s.rubyforge_project = "cassandra_integration"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
s.add_development_dependency "activemodel"
|
24
|
+
s.add_runtime_dependency "cassandra", ">= 0.12.1"
|
25
|
+
s.add_runtime_dependency "thrift_client", "~> 0.7.0"
|
26
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "cassandra_integration/version"
|
2
|
+
require "cassandra_integration/base"
|
3
|
+
require "cassandra_integration/proxy"
|
4
|
+
require "cassandra_integration/config"
|
5
|
+
|
6
|
+
module CassandraIntegration
|
7
|
+
end
|
8
|
+
|
9
|
+
if defined?(Rails)
|
10
|
+
require 'cassandra_integration/railtie'
|
11
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module CassandraIntegration::Base
|
2
|
+
|
3
|
+
attr_accessor :cassandra_column_family, :cassandra_columns_values_hash
|
4
|
+
|
5
|
+
def self.extended(base)
|
6
|
+
base.after_save :replicate
|
7
|
+
base.before_validation :set_cassandra_sync_identifier
|
8
|
+
|
9
|
+
CassandraIntegration::Config.extended_models=base.name
|
10
|
+
|
11
|
+
base.class_eval do
|
12
|
+
include InstanceMethods
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module InstanceMethods
|
17
|
+
|
18
|
+
attr_accessor :coming_from_cassandra
|
19
|
+
|
20
|
+
def coming_from_cassandra?
|
21
|
+
!self.coming_from_cassandra.blank?
|
22
|
+
end
|
23
|
+
|
24
|
+
def replicate
|
25
|
+
CassandraIntegration::Proxy.new(self).sync
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_cassandra_sync_identifier
|
29
|
+
raise 'Your model does not have cassandra_sync_identifier column.' unless self.respond_to? :cassandra_sync_identifier
|
30
|
+
self.cassandra_sync_identifier = to_cassandra_sync_identifier if self.cassandra_sync_identifier.blank?
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_cassandra_sync_identifier
|
34
|
+
raise 'Method to_cassandra_sync_identifier is not implemented!'
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
class CassandraIntegration::Config
|
3
|
+
|
4
|
+
@@extended_models = []
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def configure(yaml)
|
9
|
+
@@config = YAML::load(File.read(yaml))
|
10
|
+
end
|
11
|
+
|
12
|
+
def host
|
13
|
+
@@config[RAILS_ENV]['host']
|
14
|
+
end
|
15
|
+
|
16
|
+
def keyspace
|
17
|
+
@@config[RAILS_ENV]['keyspace']
|
18
|
+
end
|
19
|
+
|
20
|
+
def app_id
|
21
|
+
@@config[RAILS_ENV]['app_id']
|
22
|
+
end
|
23
|
+
|
24
|
+
def other_apps_ids
|
25
|
+
@@config[RAILS_ENV]['other_apps_ids']
|
26
|
+
end
|
27
|
+
|
28
|
+
def retries
|
29
|
+
@@config[RAILS_ENV]['retries'] || 3
|
30
|
+
end
|
31
|
+
|
32
|
+
def timeout
|
33
|
+
@@config[RAILS_ENV]['timeout'] || 10
|
34
|
+
end
|
35
|
+
|
36
|
+
def connect_timeout
|
37
|
+
@@config[RAILS_ENV]['connect_timeout'] || 10
|
38
|
+
end
|
39
|
+
|
40
|
+
def extended_models
|
41
|
+
@@extended_models
|
42
|
+
end
|
43
|
+
|
44
|
+
def extended_models=(value)
|
45
|
+
@@extended_models << value
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'cassandra'
|
2
|
+
class CassandraIntegration::Proxy
|
3
|
+
|
4
|
+
attr_reader :instance
|
5
|
+
|
6
|
+
def initialize(instance)
|
7
|
+
@instance = instance
|
8
|
+
end
|
9
|
+
|
10
|
+
def sync
|
11
|
+
self.class.connect.insert(@instance.class.cassandra_column_family,
|
12
|
+
@instance.cassandra_sync_identifier,
|
13
|
+
cassandra_columns_values_hash.merge(CassandraIntegration::Proxy.set_apps_to_update)) unless record_exists?
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.set_apps_to_update
|
17
|
+
data = Hash.new
|
18
|
+
CassandraIntegration::Config.other_apps_ids.split(',').each do |app|
|
19
|
+
data[app.to_s] = app.to_s
|
20
|
+
end
|
21
|
+
data
|
22
|
+
end
|
23
|
+
|
24
|
+
def record_exists?
|
25
|
+
!self.class.connect.get(@instance.class.cassandra_column_family, @instance.cassandra_sync_identifier).blank?
|
26
|
+
end
|
27
|
+
|
28
|
+
def cassandra_columns_values_hash
|
29
|
+
data = Hash.new
|
30
|
+
@instance.class.cassandra_columns_values_hash.each do |key, value|
|
31
|
+
data[key.to_s] = @instance.send(value).to_s
|
32
|
+
end
|
33
|
+
return data
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.connect
|
37
|
+
@@cassandra ||= Cassandra.new(CassandraIntegration::Config.keyspace,
|
38
|
+
CassandraIntegration::Config.host,
|
39
|
+
:retires => CassandraIntegration::Config.retries,
|
40
|
+
:timeout => CassandraIntegration::Config.timeout,
|
41
|
+
:connect_timeout => CassandraIntegration::Config.connect_timeout)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.cassandra
|
45
|
+
self.connect
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rails
|
2
|
+
|
3
|
+
module Cassandraintegration
|
4
|
+
if Rails.const_defined?(:Railtie)
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
initializer "load CassandraIntegraion config file" do
|
7
|
+
CassandraIntegration::Config.configure(Rails.root.join('config', 'cassandra_integration.yml'))
|
8
|
+
end
|
9
|
+
|
10
|
+
rake_tasks do
|
11
|
+
load 'cassandra_integration/railties/cassandra_integration.rake'
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
namespace :cassandra_integration do
|
3
|
+
# desc 'Update cassandra second index'
|
4
|
+
# task :update_second_indexes => :environment do
|
5
|
+
# Dir.glob(Rails.root.join('app/models/**/*.rb')).each { |path| require path }
|
6
|
+
#
|
7
|
+
# proxy = CassandraIntegration::Proxy
|
8
|
+
#
|
9
|
+
# CassandraIntegration::Config.extended_models.uniq.compact.each do |model|
|
10
|
+
# cf = eval(model).cassandra_column_family
|
11
|
+
# proxy.set_apps_to_update.each do |key,_|
|
12
|
+
# proxy.cassandra.insert(cf, 'temp_index_to_rake_task', {key => key})
|
13
|
+
# sleep(3)
|
14
|
+
# puts "Creating second index for CF #{cf} key #{key}."
|
15
|
+
# proxy.cassandra.create_index(CassandraIntegration::Config.keyspace, cf, key, 'UTF8Type')
|
16
|
+
# end
|
17
|
+
# key = CassandraIntegration::Config.app_id
|
18
|
+
# proxy.cassandra.insert(cf, 'temp_index_to_rake_task', {key => key})
|
19
|
+
# sleep(3)
|
20
|
+
# puts "Creating second index for CF #{cf} key #{key}."
|
21
|
+
# proxy.cassandra.create_index(CassandraIntegration::Config.keyspace, cf, key, 'UTF8Type')
|
22
|
+
#
|
23
|
+
# end
|
24
|
+
# puts 'Indexes created!'
|
25
|
+
# end
|
26
|
+
|
27
|
+
desc 'Update models with cassandra data'
|
28
|
+
task :update_models_with_cassandra => :environment do
|
29
|
+
Dir.glob(Rails.root.join('app/models/**/*.rb')).each { |path| require path }
|
30
|
+
|
31
|
+
CassandraIntegration::Config.extended_models.uniq.compact.each do |model_name|
|
32
|
+
model = eval(model_name)
|
33
|
+
cf = model.cassandra_column_family
|
34
|
+
app_id = CassandraIntegration::Config.app_id
|
35
|
+
|
36
|
+
proxy = CassandraIntegration::Proxy
|
37
|
+
search = [{ :column_name => app_id, :value => app_id, :comparison => '==' }]
|
38
|
+
records_to_update = proxy.cassandra.get_indexed_slices(cf, search, :key_count => 250)
|
39
|
+
puts "Records to update: #{records_to_update.length}"
|
40
|
+
records_to_update.each do |key,_|
|
41
|
+
|
42
|
+
puts '=================================='
|
43
|
+
puts "cassandra_sync_identifier: #{key}"
|
44
|
+
|
45
|
+
if model.find_by_cassandra_sync_identifier(key).blank?
|
46
|
+
cassandra_record = proxy.cassandra.get(cf, key)
|
47
|
+
obj = model.new
|
48
|
+
|
49
|
+
model.cassandra_columns_values_hash.each do |cassandra_col, model_col|
|
50
|
+
obj[model_col] = cassandra_record[cassandra_col.to_s]
|
51
|
+
end
|
52
|
+
obj[:cassandra_sync_identifier] = key
|
53
|
+
obj.coming_from_cassandra = true
|
54
|
+
|
55
|
+
if obj.save!
|
56
|
+
puts 'SUCCESS: Record created!'
|
57
|
+
proxy.cassandra.remove(cf, key, app_id)
|
58
|
+
puts "Removing #{app_id} from #{key} to CF #{cf}."
|
59
|
+
else
|
60
|
+
puts "ERROR: Fail to save record."
|
61
|
+
puts "key: #{key}"
|
62
|
+
puts "model: #{model.name}"
|
63
|
+
puts "CF: #{cf}"
|
64
|
+
end
|
65
|
+
|
66
|
+
else
|
67
|
+
|
68
|
+
puts "WARNING: key already exists on DB."
|
69
|
+
proxy.cassandra.remove(cf, key, app_id)
|
70
|
+
puts "Removing #{app_id} from #{key} to CF #{cf}."
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class CassandraIntegrationConfigGenerator < Rails::Generators::Base
|
2
|
+
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
|
5
|
+
desc "Generate CassandraIntegration config file"
|
6
|
+
def create_cassandra_integration_config_file
|
7
|
+
copy_file 'cassandra_integration.yml', 'config/cassandra_integration.yml'
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
development:
|
2
|
+
host: 192.168.0.1:9160
|
3
|
+
keyspace: keyspace
|
4
|
+
app_id: id_for_this_application
|
5
|
+
other_apps_ids: id_for_other_app1,id_for_other_app2
|
6
|
+
retries: 3
|
7
|
+
timeout: 10
|
8
|
+
connect_timeout: 20
|
9
|
+
|
10
|
+
production:
|
11
|
+
host: 192.168.0.1:9160
|
12
|
+
keyspace: keyspace
|
13
|
+
app_id: id_for_this_application
|
14
|
+
other_apps_ids: id_for_other_app1,id_for_other_app2
|
15
|
+
retries: 3
|
16
|
+
timeout: 10
|
17
|
+
connect_timeout: 20
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'dummy_class'
|
3
|
+
|
4
|
+
describe CassandraIntegration::Base do
|
5
|
+
|
6
|
+
let(:dummy) {DummyClass.new}
|
7
|
+
|
8
|
+
it 'should let set and get cassandra_column_family' do
|
9
|
+
DummyClass.cassandra_column_family = 'cassandra_column_family'
|
10
|
+
DummyClass.cassandra_column_family.should eq('cassandra_column_family')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should let set and get cassandra_columns_values_hash' do
|
14
|
+
DummyClass.cassandra_columns_values_hash = 'cassandra_columns_values_hash'
|
15
|
+
DummyClass.cassandra_columns_values_hash.should eq('cassandra_columns_values_hash')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'cassandra_columns_values_hash should be a Hash' do
|
19
|
+
DummyClass.cassandra_columns_values_hash = {}
|
20
|
+
DummyClass.cassandra_columns_values_hash.should be_an_instance_of Hash
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should call replicate callback method when create is called' do
|
24
|
+
dummy.should_receive(:replicate)
|
25
|
+
dummy.save
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should call set_cassandra_sync_identifier callback method when validation is called' do
|
29
|
+
dummy.should_receive(:set_cassandra_sync_identifier)
|
30
|
+
dummy.valid?
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#coming_from_cassandra?' do
|
34
|
+
it 'should let set coming_from_cassandra' do
|
35
|
+
dummy.coming_from_cassandra?.should be false
|
36
|
+
dummy.coming_from_cassandra = true
|
37
|
+
dummy.coming_from_cassandra?.should be true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#replicate' do
|
42
|
+
|
43
|
+
it 'should create a Proxy passing extended class object as argument' do
|
44
|
+
CassandraIntegration::Proxy.should_receive(:new).with(dummy).and_return(mock(:sync => true))
|
45
|
+
dummy.replicate
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should call Proxy sync method' do
|
49
|
+
proxy = mock(:proxy)
|
50
|
+
proxy.should_receive(:sync)
|
51
|
+
CassandraIntegration::Proxy.stub!(:new).and_return(proxy)
|
52
|
+
dummy.replicate
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#set_cassandra_sync_identifier' do
|
58
|
+
|
59
|
+
it "should raise exception if cassandra_sync_identifier attribute was not created on extended class" do
|
60
|
+
expect { dummy.set_cassandra_sync_identifier }.to raise_error('Your model does not have cassandra_sync_identifier column.')
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should verify if cassandra_sync_identifier was created on extended class" do
|
64
|
+
class DummyClass
|
65
|
+
attr_accessor :cassandra_sync_identifier
|
66
|
+
end
|
67
|
+
dummy.stub!(:to_cassandra_sync_identifier).and_return('to_cassandra_sync_identifier')
|
68
|
+
dummy.set_cassandra_sync_identifier.should eq('to_cassandra_sync_identifier')
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#to_cassandra_sync_identifier' do
|
74
|
+
|
75
|
+
it "should raise 'not implemented'" do
|
76
|
+
expect { dummy.to_cassandra_sync_identifier }.to raise_error('Method to_cassandra_sync_identifier is not implemented!')
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
3
|
+
|
4
|
+
describe CassandraIntegration::Config do
|
5
|
+
|
6
|
+
it "should let set any models to extended_models" do
|
7
|
+
CassandraIntegration::Config.extended_models = 'person'
|
8
|
+
CassandraIntegration::Config.extended_models = 'person2'
|
9
|
+
CassandraIntegration::Config.extended_models.should include('person2','person')
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ".configure" do
|
13
|
+
|
14
|
+
it "should parse yaml file" do
|
15
|
+
m = mock(:yaml_file)
|
16
|
+
File.stub!(:read).and_return(m)
|
17
|
+
YAML.should_receive(:load).with(m)
|
18
|
+
CassandraIntegration::Config.configure(mock)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should read the development config file" do
|
22
|
+
RAILS_ENV='development'
|
23
|
+
file = Tempfile.new('config')
|
24
|
+
file.write("development:\n")
|
25
|
+
file.write(" host: test.com\n")
|
26
|
+
file.write(" keyspace: keyspace\n")
|
27
|
+
file.write(" app_id: app_id\n")
|
28
|
+
file.write(" other_apps_ids: app2_id,app3_id\n")
|
29
|
+
file.write(" retries: 3\n")
|
30
|
+
file.write(" timeout: 10\n")
|
31
|
+
file.write(" connect_timeout: 20\n")
|
32
|
+
file.write("\n")
|
33
|
+
file.write("production:\n")
|
34
|
+
file.write(" host: test.com\n")
|
35
|
+
file.write(" keyspace: keyspace\n")
|
36
|
+
file.write(" app_id: app_id\n")
|
37
|
+
file.write(" other_apps_ids: app2_id,app3_id\n")
|
38
|
+
file.write(" retries: 3\n")
|
39
|
+
file.write(" timeout: 10\n")
|
40
|
+
file.write(" connect_timeout: 20\n")
|
41
|
+
file.flush
|
42
|
+
|
43
|
+
CassandraIntegration::Config.configure(file.path)
|
44
|
+
CassandraIntegration::Config.host.should eq('test.com')
|
45
|
+
CassandraIntegration::Config.keyspace.should eq('keyspace')
|
46
|
+
CassandraIntegration::Config.app_id.should eq('app_id')
|
47
|
+
CassandraIntegration::Config.other_apps_ids.should eq('app2_id,app3_id')
|
48
|
+
CassandraIntegration::Config.retries.should eq(3)
|
49
|
+
CassandraIntegration::Config.timeout.should eq(10)
|
50
|
+
CassandraIntegration::Config.connect_timeout.should eq(20)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/spec/dummy_class.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class DummyClass
|
2
|
+
extend ActiveModel::Callbacks
|
3
|
+
include ActiveModel::Validations
|
4
|
+
include ActiveModel::Validations::Callbacks
|
5
|
+
define_model_callbacks :save
|
6
|
+
|
7
|
+
extend CassandraIntegration::Base
|
8
|
+
|
9
|
+
def save
|
10
|
+
run_callbacks :save do
|
11
|
+
# Your save action methods here
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/proxy_spec.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe CassandraIntegration::Proxy do
|
4
|
+
|
5
|
+
describe ".connect" do
|
6
|
+
it "should set a Cassandra object connection" do
|
7
|
+
CassandraIntegration::Proxy.connect.should be_an_instance_of Cassandra
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should set instance variable" do
|
11
|
+
m = mock
|
12
|
+
CassandraIntegration::Proxy.new(m).instance.should be_an_instance_of m.class
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".cassandra" do
|
17
|
+
it "should return a Cassandra object connection" do
|
18
|
+
CassandraIntegration::Proxy.cassandra.should be_an_instance_of Cassandra
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#sync" do
|
23
|
+
|
24
|
+
it "should sync user to Cassandra" do
|
25
|
+
cassandra = mock(:cassandra)
|
26
|
+
CassandraIntegration::Proxy.stub(:connect => cassandra)
|
27
|
+
CassandraIntegration::Proxy.any_instance.stub(:record_exists? => false)
|
28
|
+
CassandraIntegration::Proxy.stub(:set_apps_to_update => {})
|
29
|
+
cassandra.should_receive(:insert).with('cassandra_column_family', 'cassandra_sync_identifier', hash_values_to_cassandra)
|
30
|
+
CassandraIntegration::Proxy.new(extended_method_mock).sync
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ".set_apps_to_update" do
|
36
|
+
|
37
|
+
it "should return a Hash of apps that need to be updated" do
|
38
|
+
CassandraIntegration::Config.stub(:other_apps_ids=>'app1,app2')
|
39
|
+
CassandraIntegration::Proxy.stub(:connect)
|
40
|
+
CassandraIntegration::Proxy.set_apps_to_update.should eq({'app1'=>'app1', 'app2'=>'app2'})
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#record_exists?" do
|
46
|
+
|
47
|
+
it "should verify if method exists" do
|
48
|
+
CassandraIntegration::Proxy.any_instance.should_receive(:record_exists?)
|
49
|
+
CassandraIntegration::Proxy.new(mock).record_exists?
|
50
|
+
end
|
51
|
+
|
52
|
+
it "Cassandra get should return true" do
|
53
|
+
CassandraIntegration::Proxy.stub(:connect => stub(:get => true))
|
54
|
+
CassandraIntegration::Proxy.connect.should_receive(:get).and_return(true)
|
55
|
+
|
56
|
+
p = CassandraIntegration::Proxy.new(extended_method_mock)
|
57
|
+
p.record_exists?.should be true
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#cassandra_coloumns_values_hash" do
|
63
|
+
|
64
|
+
it "should return a hash containing cassandra columns and their values for instance object based on cassandra_coloumns_values_hash defined on extended model" do
|
65
|
+
CassandraIntegration::Proxy.any_instance.stub(:connect)
|
66
|
+
CassandraIntegration::Proxy.new(extended_method_mock).cassandra_columns_values_hash.should eq(hash_values_to_cassandra)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def hash_values_to_cassandra
|
75
|
+
{ 'name' => 'name',
|
76
|
+
'mother_name' => 'mother',
|
77
|
+
'birth_date' => 'birthdate',
|
78
|
+
'app_id' => 'app_id' }
|
79
|
+
end
|
80
|
+
|
81
|
+
def extended_method_mock
|
82
|
+
mock(
|
83
|
+
:class => mock(:cassandra_column_family => 'cassandra_column_family', :cassandra_columns_values_hash => hash_values_to_cassandra),
|
84
|
+
:cassandra_sync_identifier => 'cassandra_sync_identifier',
|
85
|
+
:name => 'name',
|
86
|
+
:mother => 'mother',
|
87
|
+
:birthdate => 'birthdate',
|
88
|
+
:app_id => 'app_id'
|
89
|
+
)
|
90
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cassandra_integration
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Marcelo Murad
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-12 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &70101999453700 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70101999453700
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activemodel
|
27
|
+
requirement: &70101999453280 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70101999453280
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: cassandra
|
38
|
+
requirement: &70101999452780 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.12.1
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70101999452780
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: thrift_client
|
49
|
+
requirement: &70101999452280 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.7.0
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70101999452280
|
58
|
+
description: Permits integrate models from diferent apps using Cassandra for sync
|
59
|
+
email:
|
60
|
+
- marcelo.murad@dtmconsultoria.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- .gitignore
|
66
|
+
- Gemfile
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- cassandra_integration.gemspec
|
70
|
+
- lib/cassandra_integration.rb
|
71
|
+
- lib/cassandra_integration/base.rb
|
72
|
+
- lib/cassandra_integration/config.rb
|
73
|
+
- lib/cassandra_integration/proxy.rb
|
74
|
+
- lib/cassandra_integration/railtie.rb
|
75
|
+
- lib/cassandra_integration/railties/cassandra_integration.rake
|
76
|
+
- lib/cassandra_integration/version.rb
|
77
|
+
- lib/generators/cassandra_integration_config_generator.rb
|
78
|
+
- lib/generators/templates/cassandra_integration.yml
|
79
|
+
- spec/base_spec.rb
|
80
|
+
- spec/config_spec.rb
|
81
|
+
- spec/dummy_class.rb
|
82
|
+
- spec/proxy_spec.rb
|
83
|
+
- spec/spec_helper.rb
|
84
|
+
homepage: https://github.com/dtmconsultoria/cassandra-Integration
|
85
|
+
licenses: []
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project: cassandra_integration
|
104
|
+
rubygems_version: 1.8.10
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: Permits integrate models from diferent apps using Cassandra for sync
|
108
|
+
test_files:
|
109
|
+
- spec/base_spec.rb
|
110
|
+
- spec/config_spec.rb
|
111
|
+
- spec/dummy_class.rb
|
112
|
+
- spec/proxy_spec.rb
|
113
|
+
- spec/spec_helper.rb
|