activerecord_authorails 1.0.0
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/CHANGELOG +3043 -0
- data/README +360 -0
- data/RUNNING_UNIT_TESTS +64 -0
- data/Rakefile +226 -0
- data/examples/associations.png +0 -0
- data/examples/associations.rb +87 -0
- data/examples/shared_setup.rb +15 -0
- data/examples/validation.rb +85 -0
- data/install.rb +30 -0
- data/lib/active_record.rb +85 -0
- data/lib/active_record/acts/list.rb +244 -0
- data/lib/active_record/acts/nested_set.rb +211 -0
- data/lib/active_record/acts/tree.rb +89 -0
- data/lib/active_record/aggregations.rb +191 -0
- data/lib/active_record/associations.rb +1637 -0
- data/lib/active_record/associations/association_collection.rb +190 -0
- data/lib/active_record/associations/association_proxy.rb +158 -0
- data/lib/active_record/associations/belongs_to_association.rb +56 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +169 -0
- data/lib/active_record/associations/has_many_association.rb +210 -0
- data/lib/active_record/associations/has_many_through_association.rb +247 -0
- data/lib/active_record/associations/has_one_association.rb +80 -0
- data/lib/active_record/attribute_methods.rb +75 -0
- data/lib/active_record/base.rb +2164 -0
- data/lib/active_record/calculations.rb +270 -0
- data/lib/active_record/callbacks.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +279 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +58 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +343 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +161 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +228 -0
- data/lib/active_record/connection_adapters/firebird_adapter.rb +728 -0
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +414 -0
- data/lib/active_record/connection_adapters/openbase_adapter.rb +350 -0
- data/lib/active_record/connection_adapters/oracle_adapter.rb +689 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +584 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +407 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +591 -0
- data/lib/active_record/connection_adapters/sybase_adapter.rb +662 -0
- data/lib/active_record/deprecated_associations.rb +104 -0
- data/lib/active_record/deprecated_finders.rb +44 -0
- data/lib/active_record/fixtures.rb +628 -0
- data/lib/active_record/locking/optimistic.rb +106 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/migration.rb +394 -0
- data/lib/active_record/observer.rb +178 -0
- data/lib/active_record/query_cache.rb +64 -0
- data/lib/active_record/reflection.rb +222 -0
- data/lib/active_record/schema.rb +58 -0
- data/lib/active_record/schema_dumper.rb +149 -0
- data/lib/active_record/timestamp.rb +51 -0
- data/lib/active_record/transactions.rb +136 -0
- data/lib/active_record/validations.rb +843 -0
- data/lib/active_record/vendor/db2.rb +362 -0
- data/lib/active_record/vendor/mysql.rb +1214 -0
- data/lib/active_record/vendor/simple.rb +693 -0
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record/wrappers/yaml_wrapper.rb +15 -0
- data/lib/active_record/wrappings.rb +58 -0
- data/lib/active_record/xml_serialization.rb +308 -0
- data/test/aaa_create_tables_test.rb +59 -0
- data/test/abstract_unit.rb +77 -0
- data/test/active_schema_test_mysql.rb +31 -0
- data/test/adapter_test.rb +87 -0
- data/test/adapter_test_sqlserver.rb +81 -0
- data/test/aggregations_test.rb +95 -0
- data/test/all.sh +8 -0
- data/test/ar_schema_test.rb +33 -0
- data/test/association_inheritance_reload.rb +14 -0
- data/test/associations/callbacks_test.rb +126 -0
- data/test/associations/cascaded_eager_loading_test.rb +138 -0
- data/test/associations/eager_test.rb +393 -0
- data/test/associations/extension_test.rb +42 -0
- data/test/associations/join_model_test.rb +497 -0
- data/test/associations_test.rb +1809 -0
- data/test/attribute_methods_test.rb +49 -0
- data/test/base_test.rb +1586 -0
- data/test/binary_test.rb +37 -0
- data/test/calculations_test.rb +219 -0
- data/test/callbacks_test.rb +377 -0
- data/test/class_inheritable_attributes_test.rb +32 -0
- data/test/column_alias_test.rb +17 -0
- data/test/connection_test_firebird.rb +8 -0
- data/test/connections/native_db2/connection.rb +25 -0
- data/test/connections/native_firebird/connection.rb +26 -0
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +24 -0
- data/test/connections/native_openbase/connection.rb +21 -0
- data/test/connections/native_oracle/connection.rb +27 -0
- data/test/connections/native_postgresql/connection.rb +23 -0
- data/test/connections/native_sqlite/connection.rb +34 -0
- data/test/connections/native_sqlite3/connection.rb +34 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
- data/test/connections/native_sqlserver/connection.rb +23 -0
- data/test/connections/native_sqlserver_odbc/connection.rb +25 -0
- data/test/connections/native_sybase/connection.rb +23 -0
- data/test/copy_table_sqlite.rb +64 -0
- data/test/datatype_test_postgresql.rb +52 -0
- data/test/default_test_firebird.rb +16 -0
- data/test/defaults_test.rb +60 -0
- data/test/deprecated_associations_test.rb +396 -0
- data/test/deprecated_finder_test.rb +151 -0
- data/test/empty_date_time_test.rb +25 -0
- data/test/finder_test.rb +504 -0
- data/test/fixtures/accounts.yml +28 -0
- data/test/fixtures/author.rb +99 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +7 -0
- data/test/fixtures/auto_id.rb +4 -0
- data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
- data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
- data/test/fixtures/bad_fixtures/blank_line +3 -0
- data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
- data/test/fixtures/bad_fixtures/missing_value +1 -0
- data/test/fixtures/binary.rb +2 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +23 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +17 -0
- data/test/fixtures/category.rb +20 -0
- data/test/fixtures/column_name.rb +3 -0
- data/test/fixtures/comment.rb +23 -0
- data/test/fixtures/comments.yml +59 -0
- data/test/fixtures/companies.yml +55 -0
- data/test/fixtures/company.rb +107 -0
- data/test/fixtures/company_in_module.rb +59 -0
- data/test/fixtures/computer.rb +3 -0
- data/test/fixtures/computers.yml +4 -0
- data/test/fixtures/course.rb +3 -0
- data/test/fixtures/courses.yml +7 -0
- data/test/fixtures/customer.rb +55 -0
- data/test/fixtures/customers.yml +17 -0
- data/test/fixtures/db_definitions/db2.drop.sql +32 -0
- data/test/fixtures/db_definitions/db2.sql +231 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +5 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +63 -0
- data/test/fixtures/db_definitions/firebird.sql +304 -0
- data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
- data/test/fixtures/db_definitions/firebird2.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +32 -0
- data/test/fixtures/db_definitions/frontbase.sql +268 -0
- data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase2.sql +4 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +32 -0
- data/test/fixtures/db_definitions/mysql.sql +234 -0
- data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql2.sql +5 -0
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +302 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/oracle.drop.sql +65 -0
- data/test/fixtures/db_definitions/oracle.sql +325 -0
- data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +37 -0
- data/test/fixtures/db_definitions/postgresql.sql +263 -0
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +5 -0
- data/test/fixtures/db_definitions/schema.rb +60 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +32 -0
- data/test/fixtures/db_definitions/sqlite.sql +215 -0
- data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite2.sql +5 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +34 -0
- data/test/fixtures/db_definitions/sqlserver.sql +243 -0
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +34 -0
- data/test/fixtures/db_definitions/sybase.sql +218 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/default.rb +2 -0
- data/test/fixtures/developer.rb +52 -0
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/developers_projects/david_action_controller +3 -0
- data/test/fixtures/developers_projects/david_active_record +3 -0
- data/test/fixtures/developers_projects/jamis_active_record +2 -0
- data/test/fixtures/edge.rb +5 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/entrant.rb +3 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/joke.rb +6 -0
- data/test/fixtures/keyboard.rb +3 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
- data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
- data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
- data/test/fixtures/mixed_case_monkey.rb +3 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixin.rb +63 -0
- data/test/fixtures/mixins.yml +127 -0
- data/test/fixtures/movie.rb +5 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/order.rb +4 -0
- data/test/fixtures/people.yml +3 -0
- data/test/fixtures/person.rb +4 -0
- data/test/fixtures/post.rb +58 -0
- data/test/fixtures/posts.yml +48 -0
- data/test/fixtures/project.rb +27 -0
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +37 -0
- data/test/fixtures/subject.rb +4 -0
- data/test/fixtures/subscriber.rb +6 -0
- data/test/fixtures/subscribers/first +2 -0
- data/test/fixtures/subscribers/second +2 -0
- data/test/fixtures/tag.rb +7 -0
- data/test/fixtures/tagging.rb +6 -0
- data/test/fixtures/taggings.yml +18 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/task.rb +3 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/topic.rb +25 -0
- data/test/fixtures/topics.yml +22 -0
- data/test/fixtures/vertex.rb +9 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures_test.rb +401 -0
- data/test/inheritance_test.rb +205 -0
- data/test/lifecycle_test.rb +137 -0
- data/test/locking_test.rb +190 -0
- data/test/method_scoping_test.rb +416 -0
- data/test/migration_test.rb +768 -0
- data/test/migration_test_firebird.rb +124 -0
- data/test/mixin_nested_set_test.rb +196 -0
- data/test/mixin_test.rb +550 -0
- data/test/modules_test.rb +34 -0
- data/test/multiple_db_test.rb +60 -0
- data/test/pk_test.rb +104 -0
- data/test/readonly_test.rb +107 -0
- data/test/reflection_test.rb +159 -0
- data/test/schema_authorization_test_postgresql.rb +75 -0
- data/test/schema_dumper_test.rb +96 -0
- data/test/schema_test_postgresql.rb +64 -0
- data/test/synonym_test_oracle.rb +17 -0
- data/test/table_name_test_sqlserver.rb +23 -0
- data/test/threaded_connections_test.rb +48 -0
- data/test/transactions_test.rb +230 -0
- data/test/unconnected_test.rb +32 -0
- data/test/validations_test.rb +1097 -0
- data/test/xml_serialization_test.rb +125 -0
- metadata +365 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
require 'abstract_unit'
|
|
2
|
+
require 'fixtures/company'
|
|
3
|
+
require 'fixtures/project'
|
|
4
|
+
require 'fixtures/subscriber'
|
|
5
|
+
|
|
6
|
+
class InheritanceTest < Test::Unit::TestCase
|
|
7
|
+
fixtures :companies, :projects, :subscribers, :accounts
|
|
8
|
+
|
|
9
|
+
def test_a_bad_type_column
|
|
10
|
+
#SQLServer need to turn Identity Insert On before manually inserting into the Identity column
|
|
11
|
+
if current_adapter?(:SQLServerAdapter, :SybaseAdapter)
|
|
12
|
+
Company.connection.execute "SET IDENTITY_INSERT companies ON"
|
|
13
|
+
end
|
|
14
|
+
Company.connection.insert "INSERT INTO companies (id, #{QUOTED_TYPE}, name) VALUES(100, 'bad_class!', 'Not happening')"
|
|
15
|
+
|
|
16
|
+
#We then need to turn it back Off before continuing.
|
|
17
|
+
if current_adapter?(:SQLServerAdapter, :SybaseAdapter)
|
|
18
|
+
Company.connection.execute "SET IDENTITY_INSERT companies OFF"
|
|
19
|
+
end
|
|
20
|
+
assert_raises(ActiveRecord::SubclassNotFound) { Company.find(100) }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_inheritance_find
|
|
24
|
+
assert Company.find(1).kind_of?(Firm), "37signals should be a firm"
|
|
25
|
+
assert Firm.find(1).kind_of?(Firm), "37signals should be a firm"
|
|
26
|
+
assert Company.find(2).kind_of?(Client), "Summit should be a client"
|
|
27
|
+
assert Client.find(2).kind_of?(Client), "Summit should be a client"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_alt_inheritance_find
|
|
31
|
+
switch_to_alt_inheritance_column
|
|
32
|
+
test_inheritance_find
|
|
33
|
+
switch_to_default_inheritance_column
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_inheritance_find_all
|
|
37
|
+
companies = Company.find(:all, :order => 'id')
|
|
38
|
+
assert companies[0].kind_of?(Firm), "37signals should be a firm"
|
|
39
|
+
assert companies[1].kind_of?(Client), "Summit should be a client"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_alt_inheritance_find_all
|
|
43
|
+
switch_to_alt_inheritance_column
|
|
44
|
+
test_inheritance_find_all
|
|
45
|
+
switch_to_default_inheritance_column
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_inheritance_save
|
|
49
|
+
firm = Firm.new
|
|
50
|
+
firm.name = "Next Angle"
|
|
51
|
+
firm.save
|
|
52
|
+
|
|
53
|
+
next_angle = Company.find(firm.id)
|
|
54
|
+
assert next_angle.kind_of?(Firm), "Next Angle should be a firm"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_alt_inheritance_save
|
|
58
|
+
switch_to_alt_inheritance_column
|
|
59
|
+
test_inheritance_save
|
|
60
|
+
switch_to_default_inheritance_column
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_inheritance_condition
|
|
64
|
+
assert_equal 9, Company.count
|
|
65
|
+
assert_equal 2, Firm.count
|
|
66
|
+
assert_equal 3, Client.count
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_alt_inheritance_condition
|
|
70
|
+
switch_to_alt_inheritance_column
|
|
71
|
+
test_inheritance_condition
|
|
72
|
+
switch_to_default_inheritance_column
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_finding_incorrect_type_data
|
|
76
|
+
assert_raises(ActiveRecord::RecordNotFound) { Firm.find(2) }
|
|
77
|
+
assert_nothing_raised { Firm.find(1) }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_alt_finding_incorrect_type_data
|
|
81
|
+
switch_to_alt_inheritance_column
|
|
82
|
+
test_finding_incorrect_type_data
|
|
83
|
+
switch_to_default_inheritance_column
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def test_update_all_within_inheritance
|
|
87
|
+
Client.update_all "name = 'I am a client'"
|
|
88
|
+
assert_equal "I am a client", Client.find(:all).first.name
|
|
89
|
+
assert_equal "37signals", Firm.find(:all).first.name
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_alt_update_all_within_inheritance
|
|
93
|
+
switch_to_alt_inheritance_column
|
|
94
|
+
test_update_all_within_inheritance
|
|
95
|
+
switch_to_default_inheritance_column
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_destroy_all_within_inheritance
|
|
99
|
+
Client.destroy_all
|
|
100
|
+
assert_equal 0, Client.count
|
|
101
|
+
assert_equal 2, Firm.count
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def test_alt_destroy_all_within_inheritance
|
|
105
|
+
switch_to_alt_inheritance_column
|
|
106
|
+
test_destroy_all_within_inheritance
|
|
107
|
+
switch_to_default_inheritance_column
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_find_first_within_inheritance
|
|
111
|
+
assert_kind_of Firm, Company.find(:first, :conditions => "name = '37signals'")
|
|
112
|
+
assert_kind_of Firm, Firm.find(:first, :conditions => "name = '37signals'")
|
|
113
|
+
assert_nil Client.find(:first, :conditions => "name = '37signals'")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_alt_find_first_within_inheritance
|
|
117
|
+
switch_to_alt_inheritance_column
|
|
118
|
+
test_find_first_within_inheritance
|
|
119
|
+
switch_to_default_inheritance_column
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_complex_inheritance
|
|
123
|
+
very_special_client = VerySpecialClient.create("name" => "veryspecial")
|
|
124
|
+
assert_equal very_special_client, VerySpecialClient.find(:first, :conditions => "name = 'veryspecial'")
|
|
125
|
+
assert_equal very_special_client, SpecialClient.find(:first, :conditions => "name = 'veryspecial'")
|
|
126
|
+
assert_equal very_special_client, Company.find(:first, :conditions => "name = 'veryspecial'")
|
|
127
|
+
assert_equal very_special_client, Client.find(:first, :conditions => "name = 'veryspecial'")
|
|
128
|
+
assert_equal 1, Client.find(:all, :conditions => "name = 'Summit'").size
|
|
129
|
+
assert_equal very_special_client, Client.find(very_special_client.id)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def test_alt_complex_inheritance
|
|
133
|
+
switch_to_alt_inheritance_column
|
|
134
|
+
test_complex_inheritance
|
|
135
|
+
switch_to_default_inheritance_column
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_eager_load_belongs_to_something_inherited
|
|
139
|
+
account = Account.find(1, :include => :firm)
|
|
140
|
+
assert_not_nil account.instance_variable_get("@firm"), "nil proves eager load failed"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def test_alt_eager_loading
|
|
144
|
+
switch_to_alt_inheritance_column
|
|
145
|
+
test_eager_load_belongs_to_something_inherited
|
|
146
|
+
switch_to_default_inheritance_column
|
|
147
|
+
ActiveRecord::Base.logger.debug "cocksucker"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def test_inheritance_without_mapping
|
|
151
|
+
assert_kind_of SpecialSubscriber, SpecialSubscriber.find("webster132")
|
|
152
|
+
assert_nothing_raised { s = SpecialSubscriber.new("name" => "And breaaaaathe!"); s.id = 'roger'; s.save }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
private
|
|
156
|
+
def switch_to_alt_inheritance_column
|
|
157
|
+
# we don't want misleading test results, so get rid of the values in the type column
|
|
158
|
+
Company.find(:all, :order => 'id').each do |c|
|
|
159
|
+
c['type'] = nil
|
|
160
|
+
c.save
|
|
161
|
+
end
|
|
162
|
+
[ Company, Firm, Client].each { |klass| klass.reset_column_information }
|
|
163
|
+
Company.set_inheritance_column('ruby_type')
|
|
164
|
+
end
|
|
165
|
+
def switch_to_default_inheritance_column
|
|
166
|
+
[ Company, Firm, Client].each { |klass| klass.reset_column_information }
|
|
167
|
+
Company.set_inheritance_column('type')
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class InheritanceComputeTypeTest < Test::Unit::TestCase
|
|
173
|
+
fixtures :companies
|
|
174
|
+
|
|
175
|
+
def setup
|
|
176
|
+
Dependencies.log_activity = true
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def teardown
|
|
180
|
+
Dependencies.log_activity = false
|
|
181
|
+
self.class.const_remove :FirmOnTheFly rescue nil
|
|
182
|
+
Firm.const_remove :FirmOnTheFly rescue nil
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def test_instantiation_doesnt_try_to_require_corresponding_file
|
|
186
|
+
foo = Firm.find(:first).clone
|
|
187
|
+
foo.ruby_type = foo.type = 'FirmOnTheFly'
|
|
188
|
+
foo.save!
|
|
189
|
+
|
|
190
|
+
# Should fail without FirmOnTheFly in the type condition.
|
|
191
|
+
assert_raise(ActiveRecord::RecordNotFound) { Firm.find(foo.id) }
|
|
192
|
+
|
|
193
|
+
# Nest FirmOnTheFly in the test case where Dependencies won't see it.
|
|
194
|
+
self.class.const_set :FirmOnTheFly, Class.new(Firm)
|
|
195
|
+
assert_raise(ActiveRecord::SubclassNotFound) { Firm.find(foo.id) }
|
|
196
|
+
|
|
197
|
+
# Nest FirmOnTheFly in Firm where Dependencies will see it.
|
|
198
|
+
# This is analogous to nesting models in a migration.
|
|
199
|
+
Firm.const_set :FirmOnTheFly, Class.new(Firm)
|
|
200
|
+
|
|
201
|
+
# And instantiate will find the existing constant rather than trying
|
|
202
|
+
# to require firm_on_the_fly.
|
|
203
|
+
assert_nothing_raised { assert_kind_of Firm::FirmOnTheFly, Firm.find(foo.id) }
|
|
204
|
+
end
|
|
205
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
require 'abstract_unit'
|
|
2
|
+
require 'fixtures/topic'
|
|
3
|
+
require 'fixtures/developer'
|
|
4
|
+
require 'fixtures/reply'
|
|
5
|
+
|
|
6
|
+
class Topic; def after_find() end end
|
|
7
|
+
class Developer; def after_find() end end
|
|
8
|
+
class SpecialDeveloper < Developer; end
|
|
9
|
+
|
|
10
|
+
class TopicManualObserver
|
|
11
|
+
include Singleton
|
|
12
|
+
|
|
13
|
+
attr_reader :action, :object, :callbacks
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
Topic.add_observer(self)
|
|
17
|
+
@callbacks = []
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def update(callback_method, object)
|
|
21
|
+
@callbacks << { "callback_method" => callback_method, "object" => object }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def has_been_notified?
|
|
25
|
+
!@callbacks.empty?
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class TopicaObserver < ActiveRecord::Observer
|
|
30
|
+
def self.observed_class() Topic end
|
|
31
|
+
|
|
32
|
+
attr_reader :topic
|
|
33
|
+
|
|
34
|
+
def after_find(topic)
|
|
35
|
+
@topic = topic
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class TopicObserver < ActiveRecord::Observer
|
|
40
|
+
attr_reader :topic
|
|
41
|
+
|
|
42
|
+
def after_find(topic)
|
|
43
|
+
@topic = topic
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class MultiObserver < ActiveRecord::Observer
|
|
48
|
+
attr_reader :record
|
|
49
|
+
|
|
50
|
+
def self.observed_class() [ Topic, Developer ] end
|
|
51
|
+
|
|
52
|
+
cattr_reader :last_inherited
|
|
53
|
+
@@last_inherited = nil
|
|
54
|
+
|
|
55
|
+
def observed_class_inherited_with_testing(subclass)
|
|
56
|
+
observed_class_inherited_without_testing(subclass)
|
|
57
|
+
@@last_inherited = subclass
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
alias_method_chain :observed_class_inherited, :testing
|
|
61
|
+
|
|
62
|
+
def after_find(record)
|
|
63
|
+
@record = record
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class LifecycleTest < Test::Unit::TestCase
|
|
68
|
+
fixtures :topics, :developers
|
|
69
|
+
|
|
70
|
+
def test_before_destroy
|
|
71
|
+
assert_equal 2, Topic.count
|
|
72
|
+
Topic.find(1).destroy
|
|
73
|
+
assert_equal 0, Topic.count
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_after_save
|
|
77
|
+
ActiveRecord::Base.observers = :topic_manual_observer
|
|
78
|
+
ActiveRecord::Base.instantiate_observers
|
|
79
|
+
|
|
80
|
+
topic = Topic.find(1)
|
|
81
|
+
topic.title = "hello"
|
|
82
|
+
topic.save
|
|
83
|
+
|
|
84
|
+
assert TopicManualObserver.instance.has_been_notified?
|
|
85
|
+
assert_equal :after_save, TopicManualObserver.instance.callbacks.last["callback_method"]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def test_observer_update_on_save
|
|
89
|
+
ActiveRecord::Base.observers = TopicManualObserver
|
|
90
|
+
ActiveRecord::Base.instantiate_observers
|
|
91
|
+
|
|
92
|
+
topic = Topic.find(1)
|
|
93
|
+
assert TopicManualObserver.instance.has_been_notified?
|
|
94
|
+
assert_equal :after_find, TopicManualObserver.instance.callbacks.first["callback_method"]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_auto_observer
|
|
98
|
+
topic_observer = TopicaObserver.instance
|
|
99
|
+
|
|
100
|
+
topic = Topic.find(1)
|
|
101
|
+
assert_equal topic.title, topic_observer.topic.title
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def test_inferred_auto_observer
|
|
105
|
+
topic_observer = TopicObserver.instance
|
|
106
|
+
|
|
107
|
+
topic = Topic.find(1)
|
|
108
|
+
assert_equal topic.title, topic_observer.topic.title
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def test_observing_two_classes
|
|
112
|
+
multi_observer = MultiObserver.instance
|
|
113
|
+
|
|
114
|
+
topic = Topic.find(1)
|
|
115
|
+
assert_equal topic.title, multi_observer.record.title
|
|
116
|
+
|
|
117
|
+
developer = Developer.find(1)
|
|
118
|
+
assert_equal developer.name, multi_observer.record.name
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def test_observing_subclasses
|
|
122
|
+
multi_observer = MultiObserver.instance
|
|
123
|
+
|
|
124
|
+
developer = SpecialDeveloper.find(1)
|
|
125
|
+
assert_equal developer.name, multi_observer.record.name
|
|
126
|
+
|
|
127
|
+
klass = Class.new(Developer)
|
|
128
|
+
assert_equal klass, multi_observer.last_inherited
|
|
129
|
+
|
|
130
|
+
developer = klass.find(1)
|
|
131
|
+
assert_equal developer.name, multi_observer.record.name
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def test_invalid_observer
|
|
135
|
+
assert_raise(ArgumentError) { Topic.observers = Object.new; Topic.instantiate_observers }
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
require 'abstract_unit'
|
|
2
|
+
require 'fixtures/person'
|
|
3
|
+
require 'fixtures/legacy_thing'
|
|
4
|
+
|
|
5
|
+
class LockWithoutDefault < ActiveRecord::Base; end
|
|
6
|
+
|
|
7
|
+
class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
|
|
8
|
+
set_table_name :lock_without_defaults_cust
|
|
9
|
+
set_locking_column :custom_lock_version
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class OptimisticLockingTest < Test::Unit::TestCase
|
|
13
|
+
fixtures :people, :legacy_things
|
|
14
|
+
|
|
15
|
+
def test_lock_existing
|
|
16
|
+
p1 = Person.find(1)
|
|
17
|
+
p2 = Person.find(1)
|
|
18
|
+
assert_equal 0, p1.lock_version
|
|
19
|
+
assert_equal 0, p2.lock_version
|
|
20
|
+
|
|
21
|
+
p1.save!
|
|
22
|
+
assert_equal 1, p1.lock_version
|
|
23
|
+
assert_equal 0, p2.lock_version
|
|
24
|
+
|
|
25
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_lock_new
|
|
29
|
+
p1 = Person.new(:first_name => 'anika')
|
|
30
|
+
assert_equal 0, p1.lock_version
|
|
31
|
+
|
|
32
|
+
p1.save!
|
|
33
|
+
p2 = Person.find(p1.id)
|
|
34
|
+
assert_equal 0, p1.lock_version
|
|
35
|
+
assert_equal 0, p2.lock_version
|
|
36
|
+
|
|
37
|
+
p1.save!
|
|
38
|
+
assert_equal 1, p1.lock_version
|
|
39
|
+
assert_equal 0, p2.lock_version
|
|
40
|
+
|
|
41
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_lock_column_name_existing
|
|
45
|
+
t1 = LegacyThing.find(1)
|
|
46
|
+
t2 = LegacyThing.find(1)
|
|
47
|
+
assert_equal 0, t1.version
|
|
48
|
+
assert_equal 0, t2.version
|
|
49
|
+
|
|
50
|
+
t1.save!
|
|
51
|
+
assert_equal 1, t1.version
|
|
52
|
+
assert_equal 0, t2.version
|
|
53
|
+
|
|
54
|
+
assert_raises(ActiveRecord::StaleObjectError) { t2.save! }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_lock_column_is_mass_assignable
|
|
58
|
+
p1 = Person.create(:first_name => 'bianca')
|
|
59
|
+
assert_equal 0, p1.lock_version
|
|
60
|
+
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
|
61
|
+
|
|
62
|
+
p1.save!
|
|
63
|
+
assert_equal 1, p1.lock_version
|
|
64
|
+
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def test_lock_without_default_sets_version_to_zero
|
|
68
|
+
t1 = LockWithoutDefault.new
|
|
69
|
+
assert_equal 0, t1.lock_version
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_lock_with_custom_column_without_default_sets_version_to_zero
|
|
73
|
+
t1 = LockWithCustomColumnWithoutDefault.new
|
|
74
|
+
assert_equal 0, t1.custom_lock_version
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# TODO: test against the generated SQL since testing locking behavior itself
|
|
80
|
+
# is so cumbersome. Will deadlock Ruby threads if the underlying db.execute
|
|
81
|
+
# blocks, so separate script called by Kernel#system is needed.
|
|
82
|
+
# (See exec vs. async_exec in the PostgreSQL adapter.)
|
|
83
|
+
|
|
84
|
+
# TODO: The SQL Server and Sybase adapters currently have no support for pessimistic locking
|
|
85
|
+
|
|
86
|
+
unless current_adapter?(:SQLServerAdapter, :SybaseAdapter)
|
|
87
|
+
class PessimisticLockingTest < Test::Unit::TestCase
|
|
88
|
+
self.use_transactional_fixtures = false
|
|
89
|
+
fixtures :people, :readers
|
|
90
|
+
|
|
91
|
+
def setup
|
|
92
|
+
# Avoid introspection queries during tests.
|
|
93
|
+
Person.columns; Reader.columns
|
|
94
|
+
|
|
95
|
+
@allow_concurrency = ActiveRecord::Base.allow_concurrency
|
|
96
|
+
ActiveRecord::Base.allow_concurrency = true
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def teardown
|
|
100
|
+
ActiveRecord::Base.allow_concurrency = @allow_concurrency
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Test typical find.
|
|
104
|
+
def test_sane_find_with_lock
|
|
105
|
+
assert_nothing_raised do
|
|
106
|
+
Person.transaction do
|
|
107
|
+
Person.find 1, :lock => true
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Test scoped lock.
|
|
113
|
+
def test_sane_find_with_scoped_lock
|
|
114
|
+
assert_nothing_raised do
|
|
115
|
+
Person.transaction do
|
|
116
|
+
Person.with_scope(:find => { :lock => true }) do
|
|
117
|
+
Person.find 1
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# PostgreSQL protests SELECT ... FOR UPDATE on an outer join.
|
|
124
|
+
unless current_adapter?(:PostgreSQLAdapter)
|
|
125
|
+
# Test locked eager find.
|
|
126
|
+
def test_eager_find_with_lock
|
|
127
|
+
assert_nothing_raised do
|
|
128
|
+
Person.transaction do
|
|
129
|
+
Person.find 1, :include => :readers, :lock => true
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Locking a record reloads it.
|
|
136
|
+
def test_sane_lock_method
|
|
137
|
+
assert_nothing_raised do
|
|
138
|
+
Person.transaction do
|
|
139
|
+
person = Person.find 1
|
|
140
|
+
old, person.first_name = person.first_name, 'fooman'
|
|
141
|
+
person.lock!
|
|
142
|
+
assert_equal old, person.first_name
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
|
|
148
|
+
def test_no_locks_no_wait
|
|
149
|
+
first, second = duel { Person.find 1 }
|
|
150
|
+
assert first.end > second.end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def test_second_lock_waits
|
|
154
|
+
assert [0.2, 1, 5].any? { |zzz|
|
|
155
|
+
first, second = duel(zzz) { Person.find 1, :lock => true }
|
|
156
|
+
second.end > first.end
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
protected
|
|
161
|
+
def duel(zzz = 5)
|
|
162
|
+
t0, t1, t2, t3 = nil, nil, nil, nil
|
|
163
|
+
|
|
164
|
+
a = Thread.new do
|
|
165
|
+
t0 = Time.now
|
|
166
|
+
Person.transaction do
|
|
167
|
+
yield
|
|
168
|
+
sleep zzz # block thread 2 for zzz seconds
|
|
169
|
+
end
|
|
170
|
+
t1 = Time.now
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
b = Thread.new do
|
|
174
|
+
sleep zzz / 2.0 # ensure thread 1 tx starts first
|
|
175
|
+
t2 = Time.now
|
|
176
|
+
Person.transaction { yield }
|
|
177
|
+
t3 = Time.now
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
a.join
|
|
181
|
+
b.join
|
|
182
|
+
|
|
183
|
+
assert t1 > t0 + zzz
|
|
184
|
+
assert t2 > t0
|
|
185
|
+
assert t3 > t2
|
|
186
|
+
[t0.to_f..t1.to_f, t2.to_f..t3.to_f]
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|