sp-squealer 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,166 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/./spec_helper_dbms')
2
+
3
+ describe Squealer::Database do
4
+ it "is a singleton" do
5
+ Squealer::Database.respond_to?(:instance).should be_true
6
+ end
7
+
8
+ describe "import" do
9
+ let(:databases) { Squealer::Database.instance }
10
+
11
+
12
+ it "takes an import database" do
13
+ databases.send(:instance_variable_get, '@import_dbc').should be_a_kind_of(Mongo::DB)
14
+ end
15
+
16
+ it "returns a squealer connection object" do
17
+ databases.import.should be_a_kind_of(Squealer::Database::Connection)
18
+ end
19
+
20
+ it "delegates eval to Mongo" do
21
+ databases.send(:instance_variable_get, '@import_dbc').eval('db.getName()').should == $db_name
22
+ databases.import.eval('db.getName()').should == $db_name
23
+ end
24
+ end
25
+
26
+ describe "source" do
27
+ let(:databases) { Squealer::Database.instance }
28
+
29
+ before { databases.import_from('localhost', 27017, $db_name) }
30
+
31
+ it "returns a Source" do
32
+ databases.import.source('foo').should be_a_kind_of(Squealer::Database::Source)
33
+ end
34
+
35
+ describe "Source::cursor" do
36
+ it "returns a databases cursor" do
37
+ databases.import.source('foo').cursor.should be_a_kind_of(Mongo::Cursor)
38
+ end
39
+ end
40
+
41
+ context "an empty collection" do
42
+ subject { databases.import.source('foo') }
43
+
44
+ it "counts a total of zero" do
45
+ subject.counts[:total].should == 0
46
+ end
47
+
48
+ it "counts zero imported" do
49
+ subject.counts[:imported].should == 0
50
+ end
51
+
52
+ it "counts zero exported" do
53
+ subject.counts[:exported].should == 0
54
+ end
55
+ end
56
+
57
+ context "a collection with two documents" do
58
+ let(:mongo) { Squealer::Database.instance.import.send(:instance_variable_get, '@dbc') }
59
+
60
+ subject do
61
+ mongo.collection('foo').save({'name' => 'Bar'});
62
+ mongo.collection('foo').save({'name' => 'Baz'});
63
+ source = databases.import.source('foo') # activate the counter
64
+ source.send(:instance_variable_set, :@progress_bar, nil)
65
+ Squealer::ProgressBar.send(:class_variable_set, :@@progress_bar, nil)
66
+ source
67
+ end
68
+
69
+ after do
70
+ mongo.collection('foo').drop
71
+ end
72
+
73
+ it "returns a Source" do
74
+ subject.should be_a_kind_of(Squealer::Database::Source)
75
+ end
76
+
77
+ it "counts a total of two" do
78
+ subject.counts[:total].should == 2
79
+ end
80
+
81
+ context "before iterating" do
82
+ it "counts zero imported" do
83
+ subject.counts[:imported].should == 0
84
+ end
85
+
86
+ it "counts zero exported" do
87
+ subject.counts[:exported].should == 0
88
+ end
89
+ end
90
+
91
+ context "after iterating" do
92
+ before do
93
+ subject.each {}
94
+ end
95
+
96
+ it "counts two imported" do
97
+ subject.counts[:imported].should == 2
98
+ end
99
+
100
+ it "counts two exported" do
101
+ subject.counts[:exported].should == 2
102
+ end
103
+ end
104
+
105
+ context "real squeal" do
106
+ # before { pending "interactive_view" }
107
+ it "exports that stuff to SQL" do
108
+ databases.export_to($do_adapter, 'localhost', $do_user, $do_pass, $db_name)
109
+ databases.import.source("users").each do |user|
110
+ target(:user) do |target|
111
+ target.instance_variable_get('@row_id').should == user['_id'].to_s
112
+ assign(:organization_id)
113
+ assign(:name)
114
+
115
+ #TODO: Update README to highlight that all embedded docs should have an _id
116
+ # as all Ruby mappers for MongoDB make one. (according to Durran)
117
+ user.activities.each do |activity|
118
+ target(:activity) do |target|
119
+ assign(:user_id)
120
+ assign(:name)
121
+ assign(:due_date)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ end
130
+
131
+ end
132
+
133
+ describe "export" do
134
+ let(:databases) { Squealer::Database.instance }
135
+
136
+ it "creates a DataObjects connection to the export database" do
137
+ databases.export_to($do_adapter, 'localhost', $do_user, $do_pass, $db_name)
138
+ databases.instance_variable_get('@export_do').should be_a_kind_of DataObjects::Connection
139
+ end
140
+ end
141
+
142
+ describe "upsertable?" do
143
+ subject { Squealer::Database.instance }
144
+
145
+ if defined?(DataObjects::Mysql)
146
+ context "mysql connection" do
147
+ before do
148
+ subject.export_to('mysql', 'localhost', $do_user, $do_pass, 'mysql')
149
+ end
150
+
151
+ it { should be_upsertable }
152
+ end
153
+ end
154
+
155
+ if defined?(DataObjects::Postgres)
156
+ context "postgres connection" do
157
+ before do
158
+ subject.export_to('postgres', 'localhost', $do_user, $do_pass, 'postgres')
159
+ end
160
+
161
+ it { should_not be_upsertable }
162
+ end
163
+ end
164
+ end
165
+
166
+ end
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+ require File.expand_path(File.dirname(__FILE__) + "/./spec_helper_dbms_#{ENV['EXPORT_DBMS']||'mysql'}")
3
+
4
+ Spec::Runner.configure do |config|
5
+ config.before(:suite) do
6
+ $db_name = "squealer_test_export_#{object_id}"
7
+ create_export_db($db_name)
8
+ create_import_db($db_name)
9
+ end
10
+
11
+ config.after(:suite) do
12
+ DataObjects::Pooling.pools.each {|pool| pool.flush!}
13
+ drop_export_test_db($db_name)
14
+
15
+ drop_mongo
16
+ end
17
+
18
+ config.before(:each) do
19
+ if self.class.example_implementations.first.first.location =~ %r{/spec/integration/}
20
+ Squealer::Database.instance.export_to($do_adapter, $do_host, $do_user, $do_pass, $db_name)
21
+ truncate_export_tables(Squealer::Database.instance.export)
22
+ end
23
+ end
24
+ config.after(:each) do
25
+ if self.class.example_implementations.first.first.location =~ %r{/spec/integration/}
26
+ Squealer::Database.instance.export.release
27
+ end
28
+ end
29
+ end
30
+
31
+ def create_import_db(name)
32
+ Squealer::Database.instance.import_from('localhost', 27017, name)
33
+ @mongo = Squealer::Database.instance.import.instance_variable_get('@dbc')
34
+ drop_mongo
35
+ seed_import
36
+ end
37
+
38
+ def drop_mongo
39
+ @mongo.eval('db.dropDatabase()') if @mongo
40
+ end
41
+
42
+ def seed_import
43
+ hashrocket = @mongo.collection('organizations').save({ :name => 'Hashrocket' })
44
+ zorganization = @mongo.collection('organizations').save({ :name => 'Zorganization', :disabled_date => as_time(Date.today) })
45
+
46
+ users = [
47
+ { :name => 'Josh Graham', :dob => as_time(Date.parse('01-Jan-1971')), :gender => 'M',
48
+ :organization_id => hashrocket,
49
+ :activities => [
50
+ { :_id => id, :name => 'Develop squealer', :due_date => as_time(Date.today + 1) },
51
+ { :_id => id, :name => 'Organize speakerconf.com', :due_date => as_time(Date.today + 30) },
52
+ { :_id => id, :name => 'Hashrocket party', :due_date => as_time(Date.today + 7) }
53
+ ]
54
+ },
55
+ { :name => 'Bernerd Schaefer', :dob => as_time(Date.parse('31-Dec-1985')), :gender => 'M',
56
+ :organization_id => hashrocket,
57
+ :activities => [
58
+ { :_id => id, :name => 'Retype all of the code Josh wrote in squealer', :due_date => as_time(Date.today + 2) },
59
+ { :_id => id, :name => 'Listen to rare Thelonius Monk EP', :due_date => as_time(Date.today) },
60
+ { :_id => id, :name => 'Practice karaoke', :due_date => as_time(Date.today + 7) }
61
+ ]
62
+ },
63
+ { :name => 'Your momma', :dob => as_time(Date.parse('15-Jun-1955')), :gender => 'F',
64
+ :organization_id => zorganization,
65
+ :activities => [
66
+ { :_id => id, :name => 'Cook me some pie', :due_date => as_time(Date.today) },
67
+ { :_id => id, :name => 'Make me a sammich', :due_date => as_time(Date.today) }
68
+ ]
69
+ }
70
+ ]
71
+
72
+ users.each { |user| @mongo.collection('users').save user }
73
+ end
74
+
75
+
76
+ def truncate_export_tables(dbc)
77
+ %w{user activity organization}.each do |t|
78
+ text = %{TRUNCATE TABLE "#{t}"}
79
+ dbc.create_command(text).execute_non_query
80
+ end
81
+ end
82
+
83
+ def non_query(text)
84
+ dbc = do_conn
85
+ dbc.create_command(text).execute_non_query
86
+ dbc.release
87
+ end
88
+
89
+ def drop_export_test_db(name)
90
+ dbc = do_conn_default
91
+ dbc.create_command("DROP DATABASE IF EXISTS #{name}").execute_non_query
92
+ dbc.release
93
+ end
94
+
95
+ def do_conn
96
+ DataObjects::Connection.new("#{$do_adapter}://#{at_host}/#{$db_name}")
97
+ end
98
+
99
+ def do_conn_default
100
+ DataObjects::Connection.new("#{$do_adapter}://#{at_host}/#{$do_adapter}")
101
+ end
102
+
103
+ def at_host
104
+ creds = ""
105
+ creds << $do_user if $do_user
106
+ creds << ":#{$do_pass}" if $do_pass
107
+
108
+ at_host = ""
109
+ at_host << "#{creds}@" unless creds.empty?
110
+ at_host << $do_host
111
+ end
@@ -0,0 +1,50 @@
1
+ require 'do_mysql'
2
+
3
+ $do_adapter = 'mysql'
4
+ $do_host = 'localhost'
5
+ $do_user = 'root'
6
+ $do_pass = ''
7
+
8
+ def create_export_db(name)
9
+ dbc = do_conn_default
10
+ dbc.create_command("DROP DATABASE IF EXISTS #{name}").execute_non_query
11
+ dbc.create_command("CREATE DATABASE #{name}").execute_non_query
12
+ dbc.create_command("SET sql_mode='ANSI_QUOTES'").execute_non_query
13
+ dbc.release
14
+ create_export_tables
15
+ end
16
+
17
+ def create_export_tables
18
+ command = <<-COMMAND.gsub(/\n\s*/, " ")
19
+ CREATE TABLE "user" (
20
+ "id" CHAR(24) NOT NULL ,
21
+ "organization_id" CHAR(24) NOT NULL ,
22
+ "name" VARCHAR(255) NULL ,
23
+ "gender" CHAR(1) NULL ,
24
+ "dob" DATETIME NULL ,
25
+ "foreign" BOOLEAN NULL ,
26
+ "dull" BOOLEAN NULL ,
27
+ "symbolic" VARCHAR(255) NULL ,
28
+ "interests" TEXT NULL ,
29
+ PRIMARY KEY ("id") )
30
+ COMMAND
31
+ non_query(command)
32
+
33
+ command = <<-COMMAND.gsub(/\n\s*/, " ")
34
+ CREATE TABLE "activity" (
35
+ "id" CHAR(24) NOT NULL ,
36
+ "user_id" CHAR(24) NULL ,
37
+ "name" VARCHAR(255) NULL ,
38
+ "due_date" DATETIME NULL ,
39
+ PRIMARY KEY ("id") )
40
+ COMMAND
41
+ non_query(command)
42
+
43
+ command = <<-COMMAND.gsub(/\n\s*/, " ")
44
+ CREATE TABLE "organization" (
45
+ "id" CHAR(24) NOT NULL ,
46
+ "disabled_date" DATETIME NULL ,
47
+ PRIMARY KEY ("id") )
48
+ COMMAND
49
+ non_query(command)
50
+ end
@@ -0,0 +1,49 @@
1
+ require 'do_postgres'
2
+
3
+ $do_adapter = 'postgres'
4
+ $do_host = 'localhost'
5
+ $do_user = nil
6
+ $do_pass = nil
7
+
8
+ def create_export_db(name)
9
+ dbc = do_conn_default
10
+ dbc.create_command("DROP DATABASE IF EXISTS #{name}").execute_non_query
11
+ dbc.create_command("CREATE DATABASE #{name}").execute_non_query
12
+ dbc.release
13
+ create_export_tables
14
+ end
15
+
16
+ def create_export_tables
17
+ command = <<-COMMAND.gsub(/\n\s*/, " ")
18
+ CREATE TABLE "user" (
19
+ "id" CHAR(24) NOT NULL ,
20
+ "organization_id" CHAR(24) NOT NULL ,
21
+ "name" VARCHAR(255) NULL ,
22
+ "gender" CHAR(1) NULL ,
23
+ "dob" TIMESTAMP NULL ,
24
+ "foreign" BOOLEAN NULL ,
25
+ "dull" BOOLEAN NULL ,
26
+ "symbolic" VARCHAR(255) NULL ,
27
+ "interests" TEXT NULL ,
28
+ PRIMARY KEY ("id") )
29
+ COMMAND
30
+ non_query(command)
31
+
32
+ command = <<-COMMAND.gsub(/\n\s*/, " ")
33
+ CREATE TABLE "activity" (
34
+ "id" CHAR(24) NOT NULL ,
35
+ "user_id" CHAR(24) NULL ,
36
+ "name" VARCHAR(255) NULL ,
37
+ "due_date" TIMESTAMP NULL ,
38
+ PRIMARY KEY ("id") )
39
+ COMMAND
40
+ non_query(command)
41
+
42
+ command = <<-COMMAND.gsub(/\n\s*/, " ")
43
+ CREATE TABLE "organization" (
44
+ "id" CHAR(24) NOT NULL ,
45
+ "disabled_date" TIMESTAMP NULL ,
46
+ PRIMARY KEY ("id") )
47
+ COMMAND
48
+ non_query(command)
49
+ end
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format nested
3
+ --drb
@@ -0,0 +1,16 @@
1
+ require 'date'
2
+ require 'time'
3
+ require 'rubygems'
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ require 'squealer'
8
+
9
+ def as_time(date)
10
+ Time.parse(date.to_s)
11
+ end
12
+
13
+ def id
14
+ require 'digest/sha1'
15
+ (Digest::SHA1.hexdigest rand.to_s)[0,24]
16
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Squealer::Database do
4
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe Hash do
4
+
5
+ describe "#method_missing" do
6
+
7
+ it "treats it as a hash key lookup" do
8
+ { "name" => "Josh" }.name.should == "Josh"
9
+ end
10
+
11
+ context "with args" do
12
+
13
+ it "treats it normally" do
14
+ lambda { { "name" => "Josh" }.name(nil) }.should raise_error(NoMethodError)
15
+ end
16
+
17
+ end
18
+
19
+ context "with block" do
20
+
21
+ it "treats it normally" do
22
+ lambda { { "name" => "Josh" }.name {nil} }.should raise_error(NoMethodError)
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ describe NilClass do
4
+
5
+ describe "#each" do
6
+ it "returns an empty array" do
7
+ nil.each.should == [] # because mongo is schema-less
8
+ end
9
+ end
10
+
11
+ describe "#reject" do
12
+ it "returns an empty array" do
13
+ nil.reject{false}.should == [] # because mongo is schema-less
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ describe Object do
20
+ let(:test_table) { {'_id' => 1} }
21
+
22
+ describe "#target" do
23
+
24
+ it "has been defined" do
25
+ Object.new.respond_to?(:target).should be_true
26
+ end
27
+
28
+ it "invokes Squealer::Target.new" do
29
+ Squealer::Target.should_receive(:new)
30
+ target(:test_table) { nil }
31
+ end
32
+
33
+ end
34
+
35
+ describe "#assign" do
36
+
37
+ it "has been defined" do
38
+ Object.new.respond_to?(:assign).should be_true
39
+ end
40
+
41
+ it "invokes assign on the target it is immediately nested within" do
42
+ mock_mysql
43
+ target(:test_table) do |target1|
44
+ target1.should_receive(:assign)
45
+ assign(:colA) { 42 }
46
+
47
+ test_table_2 = test_table
48
+ target(:test_table_2) do |target2|
49
+ target2.should_receive(:assign)
50
+ assign(:colspeak) { 1984 }
51
+ end
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ describe "#import" do
58
+
59
+ it "has been defined" do
60
+ Object.new.respond_to?(:import).should be_true
61
+ end
62
+
63
+ context "with a single argument" do
64
+
65
+ it "invokes Database.import_from" do
66
+ Squealer::Database.instance.should_receive(:import_from)
67
+ import('test_import')
68
+ end
69
+
70
+ end
71
+
72
+ context "with no argment" do
73
+
74
+ it "invokes Database.import" do
75
+ Squealer::Database.instance.should_receive(:import)
76
+ import
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ describe "#export" do
84
+
85
+ it "has been defined" do
86
+ Object.new.respond_to?(:export).should be_true
87
+ end
88
+
89
+ context "with a single argument" do
90
+
91
+ it "invokes Database.export_to" do
92
+ Squealer::Database.instance.should_receive(:export_to)
93
+ export('test_export')
94
+ end
95
+
96
+ end
97
+
98
+ context "with no argment" do
99
+
100
+ it "invokes Database.export" do
101
+ Squealer::Database.instance.should_receive(:export)
102
+ export
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+
109
+ def mock_mysql
110
+ require 'data_objects'
111
+
112
+ my = mock(DataObjects::Connection)
113
+ comm = mock(DataObjects::Command)
114
+ Squealer::Database.instance.should_receive(:export).at_least(:once).and_return(my)
115
+ my.should_receive(:create_command).at_least(:once).and_return(comm)
116
+ comm.should_receive(:execute_non_query).at_least(:once)
117
+ end
118
+
119
+ end