activerecord-cockroachdb-adapter 8.0.3 → 8.1.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.
Files changed (239) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/CONTRIBUTING.md +10 -17
  4. data/Gemfile +2 -1
  5. data/Rakefile +0 -19
  6. data/lib/active_record/connection_adapters/cockroachdb/column.rb +66 -24
  7. data/lib/active_record/connection_adapters/cockroachdb/database_statements.rb +13 -3
  8. data/lib/active_record/connection_adapters/cockroachdb/database_tasks.rb +1 -1
  9. data/lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb +34 -19
  10. data/lib/active_record/connection_adapters/cockroachdb/quoting.rb +19 -3
  11. data/lib/active_record/connection_adapters/cockroachdb/referential_integrity.rb +87 -55
  12. data/lib/active_record/connection_adapters/cockroachdb/schema_statements.rb +181 -102
  13. data/lib/active_record/connection_adapters/cockroachdb_adapter.rb +39 -21
  14. data/lib/version.rb +1 -1
  15. data/test/cases/adapter_test.rb +98 -0
  16. data/test/cases/adapters/cockroachdb/referential_integrity_test.rb +51 -0
  17. data/test/cases/adapters/postgresql/active_schema_test.rb +71 -0
  18. data/test/cases/adapters/postgresql/change_schema_test.rb +75 -0
  19. data/test/cases/adapters/postgresql/connection_test.rb +46 -0
  20. data/test/cases/adapters/postgresql/ddl_test.rb +326 -0
  21. data/test/cases/adapters/postgresql/interval_test.rb +131 -0
  22. data/test/cases/adapters/postgresql/nested_class_test.rb +22 -0
  23. data/test/cases/adapters/postgresql/numeric_test.rb +28 -0
  24. data/test/cases/adapters/postgresql/postgis_test.rb +185 -0
  25. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +115 -0
  26. data/test/cases/adapters/postgresql/quoting_test.rb +30 -0
  27. data/test/cases/adapters/postgresql/schema_statements_test.rb +29 -0
  28. data/test/cases/adapters/postgresql/serial_test.rb +199 -0
  29. data/test/cases/adapters/postgresql/spatial_queries_test.rb +118 -0
  30. data/test/cases/adapters/postgresql/spatial_setup_test.rb +18 -0
  31. data/test/cases/adapters/postgresql/spatial_type_test.rb +41 -0
  32. data/test/cases/adapters/postgresql/timestamp_test.rb +58 -0
  33. data/test/cases/adapters/postgresql/virtual_column_test.rb +39 -0
  34. data/test/cases/associations/eager_load_nested_include_test.rb +111 -0
  35. data/test/cases/associations/left_outer_join_association_test.rb +30 -0
  36. data/test/cases/associations_test.rb +108 -0
  37. data/test/cases/base_test.rb +31 -0
  38. data/test/cases/comment_test.rb +75 -0
  39. data/test/cases/connection_adapters/type_test.rb +28 -0
  40. data/test/cases/database_configurations/resolver_test.rb +24 -0
  41. data/test/cases/defaults_test.rb +45 -0
  42. data/test/cases/dirty_test.rb +24 -0
  43. data/test/cases/fixtures_test.rb +541 -0
  44. data/test/cases/helper_cockroachdb.rb +232 -0
  45. data/test/cases/inheritance_test.rb +42 -0
  46. data/test/cases/invertible_migration_test.rb +73 -0
  47. data/test/cases/marshal_serialization_test.rb +45 -0
  48. data/test/cases/migration/change_schema_test.rb +140 -0
  49. data/test/cases/migration/check_constraint_test.rb +125 -0
  50. data/test/cases/migration/columns_test.rb +50 -0
  51. data/test/cases/migration/create_join_table_test.rb +66 -0
  52. data/test/cases/migration/foreign_key_test.rb +390 -0
  53. data/test/cases/migration/hidden_column_test.rb +70 -0
  54. data/test/cases/migration/references_foreign_key_test.rb +124 -0
  55. data/test/cases/migration_test.rb +120 -0
  56. data/test/cases/persistence_test.rb +33 -0
  57. data/test/cases/primary_keys_test.rb +134 -0
  58. data/test/cases/relation/aost_test.rb +57 -0
  59. data/test/cases/relation/or_test.rb +26 -0
  60. data/test/cases/relation/table_hints_test.rb +124 -0
  61. data/test/cases/relation_test.rb +26 -0
  62. data/test/cases/relations_test.rb +29 -0
  63. data/test/cases/schema_dumper_test.rb +221 -0
  64. data/test/cases/show_create_test.rb +14 -0
  65. data/test/cases/strict_loading_test.rb +34 -0
  66. data/test/cases/tasks/cockroachdb_rake_test.rb +113 -0
  67. data/test/cases/test_fixtures_test.rb +57 -0
  68. data/test/cases/transactions_test.rb +51 -0
  69. data/test/cases/unsafe_raw_sql_test.rb +22 -0
  70. data/test/config.yml +23 -0
  71. data/test/excludes/ActiveRecord/AdapterTest.rb +3 -0
  72. data/test/excludes/ActiveRecord/AdapterTestWithoutTransaction.rb +25 -0
  73. data/test/excludes/ActiveRecord/ConnectionAdapters/PoolConfig/ResolverTest.rb +1 -0
  74. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/BindParameterTest.rb +15 -0
  75. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/QuotingTest.rb +22 -0
  76. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapterPreventWritesLegacyTest.rb +1 -0
  77. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapterPreventWritesTest.rb +1 -0
  78. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapterTest.rb +40 -0
  79. data/test/excludes/ActiveRecord/ConnectionAdapters/RegistrationIsolatedTest.rb +14 -0
  80. data/test/excludes/ActiveRecord/Encryption/EncryptionPerformanceTest.rb +1 -0
  81. data/test/excludes/ActiveRecord/Encryption/EnvelopeEncryptionPerformanceTest.rb +1 -0
  82. data/test/excludes/ActiveRecord/Encryption/ExtendedDeterministicQueriesPerformanceTest.rb +1 -0
  83. data/test/excludes/ActiveRecord/Encryption/StoragePerformanceTest.rb +2 -0
  84. data/test/excludes/ActiveRecord/InstrumentationTest.rb +16 -0
  85. data/test/excludes/ActiveRecord/InvertibleMigrationTest.rb +2 -0
  86. data/test/excludes/ActiveRecord/Migration/ChangeSchemaTest.rb +7 -0
  87. data/test/excludes/ActiveRecord/Migration/CheckConstraintTest.rb +6 -0
  88. data/test/excludes/ActiveRecord/Migration/ColumnsTest.rb +4 -0
  89. data/test/excludes/ActiveRecord/Migration/CompatibilityTest.rb +50 -0
  90. data/test/excludes/ActiveRecord/Migration/CompositeForeignKeyTest.rb +2 -0
  91. data/test/excludes/ActiveRecord/Migration/CreateJoinTableTest.rb +2 -0
  92. data/test/excludes/ActiveRecord/Migration/ForeignKeyInCreateTest.rb +1 -0
  93. data/test/excludes/ActiveRecord/Migration/ForeignKeyTest.rb +35 -0
  94. data/test/excludes/ActiveRecord/Migration/InvalidOptionsTest.rb +14 -0
  95. data/test/excludes/ActiveRecord/Migration/PGChangeSchemaTest.rb +8 -0
  96. data/test/excludes/ActiveRecord/Migration/ReferencesForeignKeyTest.rb +7 -0
  97. data/test/excludes/ActiveRecord/Migration/ReferencesIndexTest.rb +7 -0
  98. data/test/excludes/ActiveRecord/Migration/ReferencesStatementsTest.rb +3 -0
  99. data/test/excludes/ActiveRecord/MysqlDBCreateWithInvalidPermissionsTest.rb +1 -0
  100. data/test/excludes/ActiveRecord/OrTest.rb +1 -0
  101. data/test/excludes/ActiveRecord/PostgreSQLStructureDumpTest.rb +10 -0
  102. data/test/excludes/ActiveRecord/PostgresqlConnectionTest.rb +12 -0
  103. data/test/excludes/ActiveRecord/PostgresqlTransactionNestedTest.rb +14 -0
  104. data/test/excludes/ActiveRecord/PostgresqlTransactionTest.rb +4 -0
  105. data/test/excludes/ActiveRecord/RelationTest.rb +2 -0
  106. data/test/excludes/ActiveRecord/TooManyOrTest.rb +1 -0
  107. data/test/excludes/ActiveSupportSubclassWithFixturesTest.rb +1 -0
  108. data/test/excludes/AssociationDeprecationTest/NotifyModeTest.rb +2 -0
  109. data/test/excludes/AssociationDeprecationTest/RaiseBacktraceModeTest.rb +2 -0
  110. data/test/excludes/AssociationDeprecationTest/RaiseModeTest.rb +2 -0
  111. data/test/excludes/AssociationDeprecationTest/WarnBacktraceModeTest.rb +2 -0
  112. data/test/excludes/AssociationDeprecationTest/WarnModeTest.rb +2 -0
  113. data/test/excludes/AssociationDeprecationTest/fix_backtrace_cleaner.rb +10 -0
  114. data/test/excludes/BasicsTest.rb +1 -0
  115. data/test/excludes/BulkAlterTableMigrationsTest.rb +7 -0
  116. data/test/excludes/CalculationsTest.rb +4 -0
  117. data/test/excludes/CommentTest.rb +2 -0
  118. data/test/excludes/CoreTest.rb +1 -0
  119. data/test/excludes/CreateOrFindByWithinTransactions.rb +3 -0
  120. data/test/excludes/DefaultsUsingMultipleSchemasAndDomainTest.rb +7 -0
  121. data/test/excludes/DirtyTest.rb +3 -0
  122. data/test/excludes/EachTest.rb +8 -0
  123. data/test/excludes/EagerLoadPolyAssocsTest.rb +1 -0
  124. data/test/excludes/ExplicitlyNamedIndexMigrationTest.rb +1 -0
  125. data/test/excludes/FixturesResetPkSequenceTest.rb +3 -0
  126. data/test/excludes/FixturesTest.rb +21 -0
  127. data/test/excludes/FixturesWithForeignKeyViolationsTest.rb +2 -0
  128. data/test/excludes/ForeignTableTest.rb +10 -0
  129. data/test/excludes/InheritanceComputeTypeTest.rb +1 -0
  130. data/test/excludes/LeftOuterJoinAssociationTest.rb +2 -0
  131. data/test/excludes/LegacyPrimaryKeyTest/V4_2.rb +6 -0
  132. data/test/excludes/LegacyPrimaryKeyTest/V5_0.rb +6 -0
  133. data/test/excludes/MarshalSerializationTest.rb +4 -0
  134. data/test/excludes/MaterializedViewTest.rb +13 -0
  135. data/test/excludes/MigrationTest.rb +2 -0
  136. data/test/excludes/MultiDbMigratorTest.rb +2 -0
  137. data/test/excludes/NestedRelationScopingTest.rb +1 -0
  138. data/test/excludes/OrTest.rb +1 -0
  139. data/test/excludes/PersistenceTest.rb +3 -0
  140. data/test/excludes/PessimisticLockingTest.rb +1 -0
  141. data/test/excludes/PostgreSQLExplainTest.rb +7 -0
  142. data/test/excludes/PostgreSQLGeometricLineTest.rb +3 -0
  143. data/test/excludes/PostgreSQLGeometricTypesTest.rb +7 -0
  144. data/test/excludes/PostgreSQLPartitionsTest.rb +1 -0
  145. data/test/excludes/PostgreSQLReferentialIntegrityTest.rb +14 -0
  146. data/test/excludes/PostgresqlArrayTest.rb +21 -0
  147. data/test/excludes/PostgresqlBigSerialTest.rb +7 -0
  148. data/test/excludes/PostgresqlBitStringTest.rb +2 -0
  149. data/test/excludes/PostgresqlByteaTest.rb +1 -0
  150. data/test/excludes/PostgresqlCitextTest.rb +7 -0
  151. data/test/excludes/PostgresqlCollationTest.rb +5 -0
  152. data/test/excludes/PostgresqlCompositeTest.rb +2 -0
  153. data/test/excludes/PostgresqlCompositeWithCustomOIDTest.rb +2 -0
  154. data/test/excludes/PostgresqlDataTypeTest.rb +9 -0
  155. data/test/excludes/PostgresqlDefaultExpressionTest.rb +1 -0
  156. data/test/excludes/PostgresqlDeferredConstraintsTest.rb +3 -0
  157. data/test/excludes/PostgresqlDomainTest.rb +2 -0
  158. data/test/excludes/PostgresqlExtensionMigrationTest.rb +5 -0
  159. data/test/excludes/PostgresqlFullTextTest.rb +3 -0
  160. data/test/excludes/PostgresqlGeometricTest.rb +4 -0
  161. data/test/excludes/PostgresqlHstoreTest.rb +45 -0
  162. data/test/excludes/PostgresqlInfinityTest.rb +5 -0
  163. data/test/excludes/PostgresqlIntervalTest.rb +1 -0
  164. data/test/excludes/PostgresqlJSONBTest.rb +27 -0
  165. data/test/excludes/PostgresqlJSONTest.rb +27 -0
  166. data/test/excludes/PostgresqlLtreeTest.rb +4 -0
  167. data/test/excludes/PostgresqlMoneyTest.rb +12 -0
  168. data/test/excludes/PostgresqlNetworkTest.rb +69 -0
  169. data/test/excludes/PostgresqlNumberTest.rb +1 -0
  170. data/test/excludes/PostgresqlPointTest.rb +15 -0
  171. data/test/excludes/PostgresqlRangeTest.rb +3 -0
  172. data/test/excludes/PostgresqlRenameTableTest.rb +2 -0
  173. data/test/excludes/PostgresqlSerialTest.rb +7 -0
  174. data/test/excludes/PostgresqlTimestampFixtureTest.rb +2 -0
  175. data/test/excludes/PostgresqlTimestampMigrationTest.rb +3 -0
  176. data/test/excludes/PostgresqlTypeLookupTest.rb +2 -0
  177. data/test/excludes/PostgresqlUUIDGenerationTest.rb +7 -0
  178. data/test/excludes/PostgresqlUUIDTest.rb +1 -0
  179. data/test/excludes/PostgresqlVirtualColumnTest.rb +17 -0
  180. data/test/excludes/PostgresqlXMLTest.rb +5 -0
  181. data/test/excludes/PrimaryKeyIntegerNilDefaultTest.rb +1 -0
  182. data/test/excludes/PrimaryKeyIntegerTest.rb +3 -0
  183. data/test/excludes/PrimaryKeysTest.rb +2 -0
  184. data/test/excludes/RelationMergingTest.rb +15 -0
  185. data/test/excludes/RelationTest.rb +3 -0
  186. data/test/excludes/ReservedWordsMigrationTest.rb +1 -0
  187. data/test/excludes/SameNameDifferentDatabaseFixturesTest.rb +1 -0
  188. data/test/excludes/SanitizeTest.rb +13 -0
  189. data/test/excludes/SchemaAuthorizationTest.rb +8 -0
  190. data/test/excludes/SchemaCreateTableOptionsTest.rb +2 -0
  191. data/test/excludes/SchemaDumperDefaultsTest.rb +1 -0
  192. data/test/excludes/SchemaDumperTest.rb +11 -0
  193. data/test/excludes/SchemaForeignKeyTest.rb +1 -0
  194. data/test/excludes/SchemaIndexNullsOrderTest.rb +2 -0
  195. data/test/excludes/SchemaIndexOpclassTest.rb +3 -0
  196. data/test/excludes/SchemaTest.rb +49 -0
  197. data/test/excludes/SequenceNameDetectionTestCases/CollidedSequenceNameTest.rb +1 -0
  198. data/test/excludes/SequenceNameDetectionTestCases/LongerSequenceNameDetectionTest.rb +1 -0
  199. data/test/excludes/StrictLoadingFixturesTest.rb +1 -0
  200. data/test/excludes/TestFixturesTest.rb +1 -0
  201. data/test/excludes/TransactionInstrumentationTest.rb +1 -0
  202. data/test/excludes/TransactionIsolationTest.rb +1 -0
  203. data/test/excludes/TypeTest.rb +1 -0
  204. data/test/excludes/UniquenessValidationTest.rb +2 -0
  205. data/test/excludes/UnloggedTablesTest.rb +3 -0
  206. data/test/excludes/UnsafeRawSqlTest.rb +2 -0
  207. data/test/excludes/UpdateableViewTest.rb +5 -0
  208. data/test/excludes/WithAnnotationsTest.rb +6 -0
  209. data/test/models/building.rb +4 -0
  210. data/test/models/spatial_model.rb +5 -0
  211. data/test/schema/cockroachdb_specific_schema.rb +218 -0
  212. data/test/support/copy_cat.rb +83 -0
  213. data/test/support/exclude_from_transactional_tests.rb +33 -0
  214. data/test/support/paths_cockroachdb.rb +46 -0
  215. data/test/support/rake_helpers.rb +37 -0
  216. data/test/support/sql_logger.rb +55 -0
  217. data/test/support/template_creator.rb +114 -0
  218. metadata +422 -34
  219. data/.editorconfig +0 -7
  220. data/.github/issue_template.md +0 -46
  221. data/.github/reproduction_scripts/migrations.rb +0 -60
  222. data/.github/reproduction_scripts/models_and_database.rb +0 -49
  223. data/.github/workflows/ci.yml +0 -96
  224. data/.github/workflows/docker.yml +0 -57
  225. data/.gitignore +0 -18
  226. data/.gitmodules +0 -0
  227. data/activerecord-cockroachdb-adapter.gemspec +0 -38
  228. data/bin/console +0 -36
  229. data/bin/console_schemas/default.rb +0 -11
  230. data/bin/console_schemas/schemas.rb +0 -23
  231. data/bin/setup +0 -8
  232. data/bin/start-cockroachdb +0 -33
  233. data/build/Dockerfile +0 -14
  234. data/build/config.teamcity.yml +0 -31
  235. data/build/local-test.sh +0 -32
  236. data/build/teamcity-test.sh +0 -76
  237. data/docker.sh +0 -35
  238. data/lib/active_record/connection_adapters/cockroachdb/spatial_column_info.rb +0 -60
  239. data/setup.sql +0 -18
@@ -0,0 +1,232 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ module ExcludeMessage
5
+ VALIDATE_BUG = "CockcroachDB bug, see https://github.com/cockroachdb/cockroach/blob/dd1e0e0164cb3d5859ea4bb23498863d1eebc0af/pkg/sql/alter_table.go#L458-L467"
6
+ NO_HSTORE = "Extension \"hstore\" is not yet supported by CRDB. See https://github.com/cockroachdb/cockroach/issues/41284"
7
+ end
8
+
9
+ require "minitest/excludes"
10
+
11
+ # This gives great visibility on schema dump related tests, but
12
+ # some rails specific messages are then ignored.
13
+ Minitest::Test.make_my_diffs_pretty! if ENV['VERBOSE']
14
+
15
+ # Override the load_schema_helper for the
16
+ # two ENV variables COCKROACH_LOAD_FROM_TEMPLATE
17
+ # and COCKROACH_SKIP_LOAD_SCHEMA that can
18
+ # skip this step
19
+ require "support/load_schema_helper"
20
+
21
+ module LoadSchemaHelperExt
22
+ # Load the CockroachDB specific schema. It replaces ActiveRecord's PostgreSQL
23
+ # specific schema.
24
+ def load_cockroachdb_specific_schema
25
+ # silence verbose schema loading
26
+ shh do
27
+ load "schema/cockroachdb_specific_schema.rb"
28
+
29
+ ActiveRecord::FixtureSet.reset_cache
30
+ end
31
+ end
32
+
33
+ def load_schema
34
+ return if ENV['COCKROACH_SKIP_LOAD_SCHEMA']
35
+ return load_from_template { super } if ENV['COCKROACH_LOAD_FROM_TEMPLATE']
36
+
37
+ print "Loading schema..."
38
+ t0 = Time.now
39
+ super
40
+ load_cockroachdb_specific_schema
41
+ puts format(" %.2fs", Time.now - t0)
42
+ return
43
+ end
44
+
45
+ private def load_from_template(&)
46
+ require 'support/template_creator'
47
+
48
+ if TemplateCreator.template_exists?
49
+ print "Loading schema from template..."
50
+ else
51
+ print "Generating and caching template schema..."
52
+ end
53
+
54
+ t0 = Time.now
55
+
56
+ TemplateCreator.load_from_template do
57
+ yield
58
+ load_cockroachdb_specific_schema
59
+ end
60
+
61
+ puts format(" %.2fs", Time.now - t0)
62
+
63
+ # reconnect to activerecord_unittest
64
+ shh { ARTest.connect }
65
+ end
66
+
67
+ private def shh
68
+ original_stdout = $stdout
69
+ $stdout = StringIO.new
70
+ yield
71
+ ensure
72
+ $stdout = original_stdout
73
+ end
74
+ end
75
+ LoadSchemaHelper.prepend(LoadSchemaHelperExt)
76
+
77
+ require "activerecord-cockroachdb-adapter"
78
+
79
+ # Load ActiveRecord test helper
80
+ require "cases/helper"
81
+
82
+ require "support/exclude_from_transactional_tests"
83
+
84
+ # Allow exclusion of tests by name using #exclude_from_transactional_tests(test_name)
85
+ ActiveRecord::TestCase.prepend(ExcludeFromTransactionalTests)
86
+
87
+ require 'timeout'
88
+
89
+ module TestTimeoutHelper
90
+ def time_it
91
+ t0 = Minitest.clock_time
92
+
93
+ timeout_mins = ENV.fetch("TEST_TIMEOUT", 5).to_i
94
+ Timeout.timeout(timeout_mins * 60, Timeout::Error, "Test took over #{timeout_mins} minutes to finish") do
95
+ yield
96
+ end
97
+ ensure
98
+ self.time = Minitest.clock_time - t0
99
+ end
100
+ end
101
+
102
+ module ActiveSupport
103
+ class TestCase
104
+ include TestTimeoutHelper
105
+
106
+ def postgis_version
107
+ @postgis_version ||= ActiveRecord::Base.lease_connection.select_value('SELECT postgis_lib_version()')
108
+ end
109
+
110
+ def factory
111
+ RGeo::Cartesian.preferred_factory(srid: 3857)
112
+ end
113
+
114
+ def geographic_factory
115
+ RGeo::Geographic.spherical_factory(srid: 4326)
116
+ end
117
+
118
+ def spatial_factory_store
119
+ RGeo::ActiveRecord::SpatialFactoryStore.instance
120
+ end
121
+ end
122
+ end
123
+
124
+ module SetDatetimeInCockroachDBAdapter
125
+ def with_postgresql_datetime_type(type)
126
+ adapter = ActiveRecord::ConnectionAdapters::CockroachDBAdapter
127
+ adapter.remove_instance_variable(:@native_database_types) if adapter.instance_variable_defined?(:@native_database_types)
128
+ datetime_type_was = adapter.datetime_type
129
+ adapter.datetime_type = type
130
+ yield
131
+ ensure
132
+ adapter = ActiveRecord::ConnectionAdapters::CockroachDBAdapter
133
+ adapter.datetime_type = datetime_type_was
134
+ adapter.remove_instance_variable(:@native_database_types) if adapter.instance_variable_defined?(:@native_database_types)
135
+ end
136
+ alias :with_cockroachdb_datetime_type :with_postgresql_datetime_type
137
+ end
138
+
139
+ ActiveRecord::TestCase.prepend(SetDatetimeInCockroachDBAdapter)
140
+
141
+ if ENV["JSON_REPORTER"]
142
+ puts "Generating JSON report: #{ENV["JSON_REPORTER"]}"
143
+ module Minitest
144
+ class JSONReporter < StatisticsReporter
145
+ def report
146
+ super
147
+ io.write(
148
+ {
149
+ seed: Minitest.seed,
150
+ assertions: assertions,
151
+ count: count,
152
+ failed_tests: results.reject(&:skipped?),
153
+ total_time: total_time,
154
+ failures: failures,
155
+ errors: errors,
156
+ warnings: warnings,
157
+ skips: skips,
158
+ }.to_json
159
+ )
160
+ end
161
+ end
162
+
163
+ def self.plugin_json_reporter_init(*)
164
+ reporter << JSONReporter.new(File.open(ENV["JSON_REPORTER"], "w"))
165
+ end
166
+
167
+ self.extensions << "json_reporter"
168
+ end
169
+ end
170
+
171
+ # Using '--fail-fast' may cause the rails plugin to raise Interrupt when recording
172
+ # a test. This would prevent other plugins from recording it. Hence we make sure
173
+ # that rails plugin is loaded last.
174
+ Minitest.load_plugins
175
+ if Minitest.extensions.include?("rails")
176
+ Minitest.extensions.delete("rails")
177
+ Minitest.extensions << "rails"
178
+ end
179
+
180
+ if ENV['TRACE_LIB']
181
+ module TraceLibPlugin
182
+ def after_setup
183
+ super
184
+ @tl_plugin__already_showed = {}
185
+ @tl_plugin__trace = TracePoint.new(:call) do |tp|
186
+ next unless tp.path.include?("activerecord-cockroachdb-adapter/lib")
187
+ full_path = "#{tp.path}:#{tp.lineno}"
188
+ next if @tl_plugin__already_showed[full_path]
189
+ @tl_plugin__already_showed[full_path] = true
190
+ puts "==> #{tp.defined_class}##{tp.method_id} at #{full_path}"
191
+ end
192
+ @tl_plugin__trace.enable
193
+ end
194
+
195
+ def before_teardown
196
+ @tl_plugin__trace.disable
197
+ super
198
+ end
199
+ end
200
+ Minitest::Test.include(TraceLibPlugin)
201
+ end
202
+
203
+ # Log all SQL queries and print total time spent in SQL.
204
+ if ENV["AR_LOG"]
205
+ require "support/sql_logger"
206
+ case ENV["AR_LOG"].strip
207
+ when "stdout" then SQLLogger.stdout_log
208
+ when "summary" then SQLLogger.summary_log
209
+ else
210
+ SQLLogger.stdout_log
211
+ SQLLogger.summary_log
212
+ end
213
+
214
+ end
215
+
216
+ # Remove the header from the schema dump to clarify tests outputs.
217
+ module NoHeaderExt
218
+ def header(stream)
219
+ with_comments = StringIO.new
220
+ super(with_comments)
221
+ stream.print with_comments.string.gsub(/^(:?#.*)?\n/, '')
222
+ end
223
+ end
224
+
225
+ ActiveRecord::SchemaDumper.prepend(NoHeaderExt)
226
+
227
+ # CRDB does not support ALTER COLUMN TYPE inside a transaction
228
+ # NOTE: This would be better in an exclude test, however this base
229
+ # class is used by a lot of inherited tests. We repeat less here.
230
+ class BaseCompatibilityTest < ActiveRecord::TestCase
231
+ self.use_transactional_tests = false
232
+ end
@@ -0,0 +1,42 @@
1
+ require "cases/helper_cockroachdb"
2
+
3
+ # Load dependencies from ActiveRecord test suite
4
+ require "models/company"
5
+
6
+ module CockroachDB
7
+ class InheritanceComputeTypeTest < ActiveRecord::TestCase
8
+
9
+ # This replaces the same test that's been excluded from
10
+ # InheritanceComputeTypeTest. New, unsaved records won't have
11
+ # string default values if the default has been changed in the database.
12
+ # This happens because once a column default is changed in CockroachDB, the
13
+ # type information on the value is missing.
14
+ # We can still verify the desired behavior by persisting the test records.
15
+ # When ActiveRecord fetches the records from the database, they'll have
16
+ # their default values.
17
+ # See test/excludes/InheritanceComputeTypeTest.rb
18
+ def test_inheritance_new_with_subclass_as_default
19
+ original_type = Company.columns_hash["type"].default
20
+ ActiveRecord::Base.lease_connection.change_column_default :companies, :type, "Firm"
21
+ Company.reset_column_information
22
+
23
+ # Instead of using an unsaved Company record, persist one and fetch it
24
+ # from the database to get the new default value for type.
25
+ Company.create!(name: "Acme Co.", firm_name: "Shri Hans Plastic") # with arguments
26
+ firm = Company.last
27
+ assert_equal "Firm", firm.type
28
+ assert_instance_of Firm, firm
29
+
30
+ client = Client.new
31
+ assert_equal "Client", client.type
32
+ assert_instance_of Client, client
33
+
34
+ firm = Company.new(type: "Client") # overwrite the default type
35
+ assert_equal "Client", firm.type
36
+ assert_instance_of Client, firm
37
+ ensure
38
+ ActiveRecord::Base.lease_connection.change_column_default :companies, :type, original_type
39
+ Company.reset_column_information
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,73 @@
1
+ require "cases/helper_cockroachdb"
2
+
3
+ module CockroachDB
4
+ class Horse < ActiveRecord::Base
5
+ end
6
+
7
+ class InvertibleMigrationTest < ActiveRecord::TestCase
8
+ class SilentMigration < ActiveRecord::Migration::Current
9
+ def write(text = "")
10
+ # sssshhhhh!!
11
+ end
12
+ end
13
+
14
+ class ChangeColumnDefault1 < SilentMigration
15
+ def change
16
+ create_table("horses") do |t|
17
+ t.column :name, :string, default: "Sekitoba"
18
+ end
19
+ end
20
+ end
21
+
22
+ class ChangeColumnDefault2 < SilentMigration
23
+ def change
24
+ change_column_default :horses, :name, from: "Sekitoba", to: "Diomed"
25
+ end
26
+ end
27
+
28
+ self.use_transactional_tests = false
29
+
30
+ setup do
31
+ @verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false
32
+ end
33
+
34
+ teardown do
35
+ %w[horses new_horses].each do |table|
36
+ if ActiveRecord::Base.lease_connection.table_exists?(table)
37
+ ActiveRecord::Base.lease_connection.drop_table(table)
38
+ end
39
+ end
40
+ ActiveRecord::Migration.verbose = @verbose_was
41
+ end
42
+
43
+ # This replaces the same test that's been excluded from
44
+ # ActiveRecord::InvertibleMigrationTest. New, unsaved records won't have
45
+ # string default values if the default has been changed in the database.
46
+ # This happens because once a column default is changed in CockroachDB, the
47
+ # type information on the value is missing.
48
+ # We can still verify the desired behavior by persisting the test records.
49
+ # When ActiveRecord fetches the records from the database, they'll have
50
+ # their default values.
51
+ # See test/excludes/ActiveRecord/InvertibleMigrationTest.rb
52
+ def test_migrate_revert_change_column_default
53
+ migration1 = ChangeColumnDefault1.new
54
+ migration1.migrate(:up)
55
+ assert_equal "Sekitoba", Horse.new.name
56
+
57
+ # Instead of using an unsaved Horse record, persist one and fetch it from
58
+ # the database to get the new default value for name.
59
+ migration2 = ChangeColumnDefault2.new
60
+ migration2.migrate(:up)
61
+ Horse.reset_column_information
62
+ Horse.create!
63
+ assert_equal "Diomed", Horse.last.name
64
+
65
+ # Instead of using an unsaved Horse record, persist one and fetch it from
66
+ # the database to get the new default value for name.
67
+ migration2.migrate(:down)
68
+ Horse.reset_column_information
69
+ Horse.create!
70
+ assert_equal "Sekitoba", Horse.last.name
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper"
4
+ require "models/topic"
5
+ require "models/reply"
6
+ require "support/paths_cockroachdb"
7
+
8
+ module CockroachDB
9
+ class MarshalSerializationTest < ActiveRecord::TestCase
10
+ # This test file is identical to the one in Rails, except that
11
+ # the marshal_fixture_path method specifies to use the PostgreSQL
12
+ # directory instead of using the adapter name.
13
+ fixtures :topics
14
+
15
+ def test_deserializing_rails_6_1_marshal_basic
16
+ topic = Marshal.load(marshal_fixture("rails_6_1_topic"))
17
+
18
+ assert_not_predicate topic, :new_record?
19
+ assert_equal 1, topic.id
20
+ assert_equal "The First Topic", topic.title
21
+ assert_equal "Have a nice day", topic.content
22
+ end
23
+
24
+ def test_deserializing_rails_6_1_marshal_with_loaded_association_cache
25
+ topic = Marshal.load(marshal_fixture("rails_6_1_topic_associations"))
26
+
27
+ assert_not_predicate topic, :new_record?
28
+ assert_equal 1, topic.id
29
+ assert_equal "The First Topic", topic.title
30
+ assert_equal "Have a nice day", topic.content
31
+ end
32
+
33
+ private
34
+ def marshal_fixture(file_name)
35
+ File.binread(marshal_fixture_path(file_name))
36
+ end
37
+
38
+ def marshal_fixture_path(file_name)
39
+ File.expand_path(
40
+ "support/marshal_compatibility_fixtures/PostgreSQL/#{file_name}.dump",
41
+ ARTest::CockroachDB.root_activerecord_test
42
+ )
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper_cockroachdb"
4
+
5
+ module ActiveRecord
6
+ module CockroachDB
7
+ class Migration
8
+ class ChangeSchemaTest < ActiveRecord::TestCase
9
+ attr_reader :connection, :table_name
10
+
11
+ self.use_transactional_tests = false
12
+
13
+ def setup
14
+ super
15
+ @connection = ActiveRecord::Base.lease_connection
16
+ @table_name = :testings
17
+ end
18
+
19
+ teardown do
20
+ connection.drop_table :testings, if_exists: true
21
+ ActiveRecord::Base.primary_key_prefix_type = nil
22
+ ActiveRecord::Base.clear_cache!
23
+ end
24
+
25
+ # This test is identical to the one in Rails, except here we are running
26
+ # it with transactions turned off so that we can properly assert on
27
+ # database changes. See https://www.cockroachlabs.com/docs/v19.2/transactions.html
28
+ def test_drop_table_if_exists
29
+ connection.create_table(:testings)
30
+ assert connection.table_exists?(:testings)
31
+ connection.drop_table(:testings, if_exists: true)
32
+ assert_not connection.table_exists?(:testings)
33
+ end
34
+
35
+ # This test is identical to the one in Rails, except here we are running
36
+ # it with transactions turned off so that we can properly assert on
37
+ # database changes. See https://www.cockroachlabs.com/docs/v19.2/transactions.html
38
+ def test_keeping_default_and_notnull_constraints_on_change
39
+ connection.create_table :testings do |t|
40
+ t.column :title, :string
41
+ end
42
+ person_klass = Class.new(ActiveRecord::Base)
43
+ person_klass.table_name = "testings"
44
+
45
+ person_klass.lease_connection.add_column "testings", "wealth", :integer, null: false, default: 99
46
+ person_klass.reset_column_information
47
+ assert_equal 99, person_klass.column_defaults["wealth"]
48
+ assert_equal false, person_klass.columns_hash["wealth"].null
49
+ assert_nothing_raised { person_klass.lease_connection.execute("insert into testings (title) values ('tester')") }
50
+
51
+ # change column default to see that column doesn't lose its not null definition
52
+ person_klass.lease_connection.change_column_default "testings", "wealth", 100
53
+ person_klass.reset_column_information
54
+ assert_equal 100, person_klass.column_defaults["wealth"]
55
+ assert_equal false, person_klass.columns_hash["wealth"].null
56
+
57
+ # rename column to see that column doesn't lose its not null and/or default definition
58
+ person_klass.lease_connection.rename_column "testings", "wealth", "money"
59
+ person_klass.reset_column_information
60
+ assert_nil person_klass.columns_hash["wealth"]
61
+ assert_equal 100, person_klass.column_defaults["money"]
62
+ assert_equal false, person_klass.columns_hash["money"].null
63
+
64
+ # change column
65
+ person_klass.lease_connection.change_column "testings", "money", :integer, null: false, default: 1000
66
+ person_klass.reset_column_information
67
+ assert_equal 1000, person_klass.column_defaults["money"]
68
+ assert_equal false, person_klass.columns_hash["money"].null
69
+
70
+ # change column, make it nullable and clear default
71
+ person_klass.lease_connection.change_column "testings", "money", :integer, null: true, default: nil
72
+ person_klass.reset_column_information
73
+ assert_nil person_klass.columns_hash["money"].default
74
+ assert_equal true, person_klass.columns_hash["money"].null
75
+
76
+ # change_column_null, make it not nullable and set null values to a default value
77
+ person_klass.lease_connection.execute("UPDATE testings SET money = NULL")
78
+ person_klass.lease_connection.change_column_null "testings", "money", false, 2000
79
+ person_klass.reset_column_information
80
+ assert_nil person_klass.columns_hash["money"].default
81
+ assert_equal false, person_klass.columns_hash["money"].null
82
+ assert_equal 2000, connection.select_values("SELECT money FROM testings").first.to_i
83
+ end
84
+
85
+ # This test is identical to the one in Rails, except here we are running
86
+ # it with transactions turned off so that we can properly assert on
87
+ # database changes. See https://www.cockroachlabs.com/docs/v19.2/transactions.html
88
+ def test_change_column_null
89
+ testing_table_with_only_foo_attribute do
90
+ notnull_migration = Class.new(ActiveRecord::Migration::Current) do
91
+ def change
92
+ change_column_null :testings, :foo, false
93
+ end
94
+ end
95
+ notnull_migration.new.suppress_messages do
96
+ notnull_migration.migrate(:up)
97
+ assert_equal false, connection.columns(:testings).find { |c| c.name == "foo" }.null
98
+ notnull_migration.migrate(:down)
99
+ assert connection.columns(:testings).find { |c| c.name == "foo" }.null
100
+ end
101
+ end
102
+ end
103
+
104
+ def test_create_table_with_limits
105
+ connection.create_table :testings do |t|
106
+ t.column :foo, :string, limit: 255
107
+
108
+ t.column :default_int, :integer
109
+
110
+ t.column :one_int, :integer, limit: 1
111
+ t.column :four_int, :integer, limit: 4
112
+ t.column :eight_int, :integer, limit: 8
113
+ end
114
+
115
+ columns = connection.columns(:testings)
116
+ foo = columns.detect { |c| c.name == "foo" }
117
+ assert_equal 255, foo.limit
118
+
119
+ default = columns.detect { |c| c.name == "default_int" }
120
+ one = columns.detect { |c| c.name == "one_int" }
121
+ four = columns.detect { |c| c.name == "four_int" }
122
+ eight = columns.detect { |c| c.name == "eight_int" }
123
+
124
+ assert_equal "bigint", default.sql_type #This differs from PG, whose default type is integer
125
+ assert_equal "smallint", one.sql_type
126
+ assert_equal "integer", four.sql_type
127
+ assert_equal "bigint", eight.sql_type
128
+ end
129
+
130
+ private
131
+ def testing_table_with_only_foo_attribute
132
+ connection.create_table :testings, id: false do |t|
133
+ t.column :foo, :string
134
+ end
135
+ yield
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper"
4
+ require "support/schema_dumping_helper"
5
+
6
+ if ActiveRecord::Base.lease_connection.supports_check_constraints?
7
+ module ActiveRecord
8
+ module CockroachDB
9
+ class Migration
10
+ class CheckConstraintTest < ActiveRecord::TestCase
11
+ include SchemaDumpingHelper
12
+ self.use_transactional_tests = false
13
+
14
+ class Trade < ActiveRecord::Base
15
+ end
16
+
17
+ setup do
18
+ @connection = ActiveRecord::Base.lease_connection
19
+ @connection.create_table "trades", force: true do |t|
20
+ t.integer :price
21
+ t.integer :quantity
22
+ end
23
+ end
24
+
25
+ teardown do
26
+ @connection.drop_table "trades", if_exists: true
27
+ end
28
+
29
+ if ActiveRecord::Base.lease_connection.supports_validate_constraints?
30
+ # keep
31
+ def test_validate_check_constraint_by_name
32
+ @connection.add_check_constraint :trades, "quantity > 0", name: "quantity_check", validate: false
33
+ assert_not_predicate @connection.check_constraints("trades").first, :validated?
34
+
35
+ @connection.validate_check_constraint :trades, name: "quantity_check"
36
+ assert_predicate @connection.check_constraints("trades").first, :validated?
37
+ end
38
+ end
39
+
40
+ # ExcludeMessage::VALIDATE_BUG
41
+ # def test_schema_dumping_with_validate_false
42
+ # @connection.add_check_constraint :trades, "quantity > 0", name: "quantity_check", validate: false
43
+
44
+ # output = dump_table_schema "trades"
45
+
46
+ # assert_match %r{\s+t.check_constraint "(quantity > 0)", name: "quantity_check", validate: false$}, output
47
+ # end
48
+
49
+ def test_schema_dumping_with_validate_true
50
+ @connection.add_check_constraint :trades, "quantity > 0", name: "quantity_check", validate: true
51
+
52
+ output = dump_table_schema "trades"
53
+
54
+ assert_match %r{\s+t.check_constraint "\(quantity > 0\)", name: "quantity_check"$}, output
55
+ end
56
+
57
+ # keep
58
+ def test_remove_check_constraint
59
+ @connection.add_check_constraint :trades, "price > 0", name: "price_check"
60
+ @connection.add_check_constraint :trades, "quantity > 0", name: "quantity_check"
61
+
62
+ assert_equal 2, @connection.check_constraints("trades").size
63
+ @connection.remove_check_constraint :trades, name: "quantity_check"
64
+ assert_equal 1, @connection.check_constraints("trades").size
65
+
66
+ constraint = @connection.check_constraints("trades").first
67
+ assert_equal "trades", constraint.table_name
68
+ assert_equal "price_check", constraint.name
69
+
70
+ if current_adapter?(:Mysql2Adapter)
71
+ assert_equal "`price` > 0", constraint.expression
72
+ else
73
+ assert_equal "(price > 0)", constraint.expression
74
+ end
75
+ end
76
+
77
+ def test_check_constraints
78
+ check_constraints = @connection.check_constraints("products")
79
+ assert_equal 1, check_constraints.size
80
+
81
+ constraint = check_constraints.first
82
+ assert_equal "products", constraint.table_name
83
+ assert_equal "products_price_check", constraint.name
84
+
85
+ if current_adapter?(:Mysql2Adapter)
86
+ assert_equal "`price` > `discounted_price`", constraint.expression
87
+ else
88
+ assert_equal "(price > discounted_price)", constraint.expression
89
+ end
90
+
91
+ if current_adapter?(:PostgreSQLAdapter)
92
+ begin
93
+ # Test that complex expression is correctly parsed from the database
94
+ @connection.add_check_constraint(:trades,
95
+ "CASE WHEN price IS NOT NULL THEN true ELSE false END", name: "price_is_required")
96
+
97
+ constraint = @connection.check_constraints("trades").find { |c| c.name == "price_is_required" }
98
+ assert_includes constraint.expression, "WHEN price IS NOT NULL"
99
+ ensure
100
+ @connection.remove_check_constraint(:trades, name: "price_is_required")
101
+ end
102
+ end
103
+ end
104
+
105
+ def test_add_check_constraint
106
+ @connection.add_check_constraint :trades, "quantity > 0"
107
+
108
+ check_constraints = @connection.check_constraints("trades")
109
+ assert_equal 1, check_constraints.size
110
+
111
+ constraint = check_constraints.first
112
+ assert_equal "trades", constraint.table_name
113
+ assert_equal "chk_rails_2189e9f96c", constraint.name
114
+
115
+ if current_adapter?(:Mysql2Adapter)
116
+ assert_equal "`quantity` > 0", constraint.expression
117
+ else
118
+ assert_equal "(quantity > 0)", constraint.expression
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end