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