caruby-core 1.5.5 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. data/Gemfile +9 -0
  2. data/History.md +5 -1
  3. data/lib/caruby.rb +3 -5
  4. data/lib/caruby/caruby-src.tar.gz +0 -0
  5. data/lib/caruby/database.rb +53 -69
  6. data/lib/caruby/database/application_service.rb +25 -0
  7. data/lib/caruby/database/cache.rb +60 -0
  8. data/lib/caruby/database/fetched_matcher.rb +52 -38
  9. data/lib/caruby/database/lazy_loader.rb +4 -4
  10. data/lib/caruby/database/operation.rb +34 -0
  11. data/lib/caruby/database/persistable.rb +171 -86
  12. data/lib/caruby/database/persistence_service.rb +32 -34
  13. data/lib/caruby/database/persistifier.rb +100 -43
  14. data/lib/caruby/database/reader.rb +107 -85
  15. data/lib/caruby/database/reader_template_builder.rb +60 -0
  16. data/lib/caruby/database/saved_matcher.rb +3 -3
  17. data/lib/caruby/database/sql_executor.rb +88 -17
  18. data/lib/caruby/database/writer.rb +213 -177
  19. data/lib/caruby/database/writer_template_builder.rb +334 -0
  20. data/lib/caruby/{util → helpers}/controlled_value.rb +0 -0
  21. data/lib/caruby/{util → helpers}/coordinate.rb +4 -4
  22. data/lib/caruby/{util → helpers}/person.rb +3 -3
  23. data/lib/caruby/{util → helpers}/properties.rb +7 -9
  24. data/lib/caruby/{util → helpers}/roman.rb +2 -2
  25. data/lib/caruby/{util → helpers}/version.rb +1 -1
  26. data/lib/caruby/json/deserializer.rb +2 -2
  27. data/lib/caruby/json/serializer.rb +49 -7
  28. data/lib/caruby/metadata.rb +30 -0
  29. data/lib/caruby/metadata/java_property.rb +21 -0
  30. data/lib/caruby/metadata/propertied.rb +191 -0
  31. data/lib/caruby/metadata/property.rb +22 -0
  32. data/lib/caruby/metadata/property_characteristics.rb +201 -0
  33. data/lib/caruby/migration/migratable.rb +11 -182
  34. data/lib/caruby/rdbi/driver/jdbc.rb +446 -0
  35. data/lib/caruby/resource.rb +20 -823
  36. data/lib/caruby/version.rb +1 -1
  37. data/test/lib/caruby/database/cache_test.rb +54 -0
  38. data/test/lib/caruby/{util → helpers}/controlled_value_test.rb +3 -5
  39. data/test/lib/caruby/{util → helpers}/person_test.rb +4 -6
  40. data/test/lib/caruby/helpers/properties_test.rb +34 -0
  41. data/test/lib/caruby/{util → helpers}/roman_test.rb +2 -3
  42. data/test/lib/caruby/{util → helpers}/version_test.rb +2 -3
  43. data/test/lib/helper.rb +7 -0
  44. metadata +161 -214
  45. data/lib/caruby/cli/application.rb +0 -36
  46. data/lib/caruby/cli/command.rb +0 -202
  47. data/lib/caruby/csv/csv_mapper.rb +0 -159
  48. data/lib/caruby/csv/csvio.rb +0 -203
  49. data/lib/caruby/database/search_template_builder.rb +0 -56
  50. data/lib/caruby/database/store_template_builder.rb +0 -278
  51. data/lib/caruby/domain.rb +0 -193
  52. data/lib/caruby/domain/attribute.rb +0 -584
  53. data/lib/caruby/domain/attributes.rb +0 -628
  54. data/lib/caruby/domain/dependency.rb +0 -225
  55. data/lib/caruby/domain/id_alias.rb +0 -22
  56. data/lib/caruby/domain/importer.rb +0 -183
  57. data/lib/caruby/domain/introspection.rb +0 -176
  58. data/lib/caruby/domain/inverse.rb +0 -172
  59. data/lib/caruby/domain/inversible.rb +0 -90
  60. data/lib/caruby/domain/java_attribute.rb +0 -173
  61. data/lib/caruby/domain/merge.rb +0 -185
  62. data/lib/caruby/domain/metadata.rb +0 -142
  63. data/lib/caruby/domain/mixin.rb +0 -35
  64. data/lib/caruby/domain/properties.rb +0 -95
  65. data/lib/caruby/domain/reference_visitor.rb +0 -428
  66. data/lib/caruby/domain/uniquify.rb +0 -50
  67. data/lib/caruby/import/java.rb +0 -387
  68. data/lib/caruby/migration/migrator.rb +0 -918
  69. data/lib/caruby/migration/resource_module.rb +0 -9
  70. data/lib/caruby/migration/uniquify.rb +0 -17
  71. data/lib/caruby/util/attribute_path.rb +0 -44
  72. data/lib/caruby/util/cache.rb +0 -56
  73. data/lib/caruby/util/class.rb +0 -149
  74. data/lib/caruby/util/collection.rb +0 -1152
  75. data/lib/caruby/util/domain_extent.rb +0 -46
  76. data/lib/caruby/util/file_separator.rb +0 -65
  77. data/lib/caruby/util/inflector.rb +0 -27
  78. data/lib/caruby/util/log.rb +0 -95
  79. data/lib/caruby/util/math.rb +0 -12
  80. data/lib/caruby/util/merge.rb +0 -59
  81. data/lib/caruby/util/module.rb +0 -18
  82. data/lib/caruby/util/options.rb +0 -97
  83. data/lib/caruby/util/partial_order.rb +0 -35
  84. data/lib/caruby/util/pretty_print.rb +0 -204
  85. data/lib/caruby/util/stopwatch.rb +0 -74
  86. data/lib/caruby/util/topological_sync_enumerator.rb +0 -62
  87. data/lib/caruby/util/transitive_closure.rb +0 -55
  88. data/lib/caruby/util/tree.rb +0 -48
  89. data/lib/caruby/util/trie.rb +0 -37
  90. data/lib/caruby/util/uniquifier.rb +0 -30
  91. data/lib/caruby/util/validation.rb +0 -20
  92. data/lib/caruby/util/visitor.rb +0 -365
  93. data/lib/caruby/util/weak_hash.rb +0 -36
  94. data/test/lib/caruby/csv/csv_mapper_test.rb +0 -40
  95. data/test/lib/caruby/csv/csvio_test.rb +0 -69
  96. data/test/lib/caruby/database/persistable_test.rb +0 -92
  97. data/test/lib/caruby/domain/domain_test.rb +0 -112
  98. data/test/lib/caruby/domain/inversible_test.rb +0 -99
  99. data/test/lib/caruby/domain/reference_visitor_test.rb +0 -130
  100. data/test/lib/caruby/import/java_test.rb +0 -80
  101. data/test/lib/caruby/import/mixed_case_test.rb +0 -14
  102. data/test/lib/caruby/migration/test_case.rb +0 -102
  103. data/test/lib/caruby/test_case.rb +0 -230
  104. data/test/lib/caruby/util/cache_test.rb +0 -23
  105. data/test/lib/caruby/util/class_test.rb +0 -61
  106. data/test/lib/caruby/util/collection_test.rb +0 -398
  107. data/test/lib/caruby/util/command_test.rb +0 -55
  108. data/test/lib/caruby/util/domain_extent_test.rb +0 -60
  109. data/test/lib/caruby/util/file_separator_test.rb +0 -30
  110. data/test/lib/caruby/util/inflector_test.rb +0 -12
  111. data/test/lib/caruby/util/lazy_hash_test.rb +0 -34
  112. data/test/lib/caruby/util/merge_test.rb +0 -83
  113. data/test/lib/caruby/util/module_test.rb +0 -25
  114. data/test/lib/caruby/util/options_test.rb +0 -59
  115. data/test/lib/caruby/util/partial_order_test.rb +0 -42
  116. data/test/lib/caruby/util/pretty_print_test.rb +0 -85
  117. data/test/lib/caruby/util/properties_test.rb +0 -50
  118. data/test/lib/caruby/util/stopwatch_test.rb +0 -18
  119. data/test/lib/caruby/util/topological_sync_enumerator_test.rb +0 -69
  120. data/test/lib/caruby/util/transitive_closure_test.rb +0 -67
  121. data/test/lib/caruby/util/tree_test.rb +0 -23
  122. data/test/lib/caruby/util/trie_test.rb +0 -14
  123. data/test/lib/caruby/util/visitor_test.rb +0 -278
  124. data/test/lib/caruby/util/weak_hash_test.rb +0 -45
  125. data/test/lib/examples/clinical_trials/migration/migration_test.rb +0 -58
  126. data/test/lib/examples/clinical_trials/migration/test_case.rb +0 -38
@@ -1,130 +0,0 @@
1
- $:.unshift 'lib'
2
- $:.unshift 'examples/clinical_trials/lib'
3
-
4
- require 'test/unit'
5
-
6
- require 'caruby/util/log' and
7
- CaRuby::Log.instance.open('test/results/log/clinical_trials.log', :shift_age => 10, :shift_size => 1048576, :debug => true)
8
-
9
- require 'clinical_trials'
10
- require 'caruby/domain/reference_visitor'
11
-
12
- # CaRuby::ReferenceVisitor test cases.
13
- class ReferenceVisitorTest < Test::Unit::TestCase
14
- def setup
15
- super
16
- coordinator = ClinicalTrials::User.new(:login => 'study.coordinator@test.org')
17
- address = ClinicalTrials::Address.new(:street => '555 Elm St', :city => 'Burlington', :state => 'VT', :zip_code => '55555')
18
- @pnt = ClinicalTrials::Participant.new(:name => 'Test Participant', :address => address)
19
- @study = ClinicalTrials::Study.new(:name => 'Test Study', :coordinator => coordinator, :enrollment => [@pnt])
20
- @event = ClinicalTrials::StudyEvent.new(:study => @study, :calendar_event_point => 1.0)
21
- end
22
-
23
- def test_path_references
24
- visitor = CaRuby::ReferencePathVisitorFactory.create(ClinicalTrials::Study, [:enrollment, :address])
25
- assert_equal([@study, @pnt, @pnt.address], visitor.to_enum(@study).to_a, "Path references incorrect")
26
- end
27
-
28
- def test_cycles
29
- # visit all references
30
- visitor = CaRuby::ReferenceVisitor.new { |ref| ref.class.domain_attributes }
31
- visitor.visit(@study)
32
- assert_equal([[@study, @event, @study]], visitor.cycles, "Cycles incorrect")
33
- end
34
-
35
- def test_path_attributes
36
- visitor = CaRuby::ReferencePathVisitorFactory.create(ClinicalTrials::Study, [:enrollment, :address])
37
- assert_equal([nil, :enrollment, :address], visitor.to_enum(@study).map { visitor.attribute }, "Path attributes incorrect")
38
- end
39
-
40
- def test_to_enum
41
- visitor = CaRuby::ReferencePathVisitorFactory.create(ClinicalTrials::Study, [:enrollment, :address])
42
- assert_equal([@study, @pnt, @pnt.address], visitor.to_enum(@study).to_a, "Enumeration incorrect")
43
- end
44
-
45
- def test_id_match
46
- # set the source ids
47
- @study.identifier = 1
48
- @event.identifier = 2
49
- # make a match target
50
- target = CaRuby::CopyVisitor.new { |ref| ref.class.dependent_attributes }.visit(@study)
51
- # match the source to the target
52
- matcher = CaRuby::MatchVisitor.new { |ref| ref.class.dependent_attributes }
53
- matcher.visit(@study, target)
54
- expected = {@study => target, @event => target.events.first}
55
- # validate the match
56
- assert_equal(expected, matcher.matches, "Match incorrect")
57
- end
58
-
59
- def test_copy
60
- visitor = CaRuby::CopyVisitor.new { |ref| ref.class.dependent_attributes }
61
- copy = visitor.visit(@study)
62
- assert_not_nil(copy, "Study not copied")
63
- assert_not_nil(visitor.visited[@study], "#{@study.qp} copy #{copy.qp} not captured in visited #{visitor.visited.qp}")
64
- assert_same(copy, visitor.visited[@study], "#{@study.qp} visited value incorrect")
65
- assert_not_same(copy, @study, "#{@study.qp} not copied into #{copy.qp} as new object")
66
- assert_equal(@study.name, copy.name, "#{@study.qp} attribute not copied")
67
- assert_nil(copy.coordinator, "#{@study.qp} coordinator incorrectly copied into #{copy.qp} as a dependent")
68
- assert(!@study.events.empty?, "#{@study.qp} events cleared by copy")
69
- assert(!copy.events.empty?, "#{@study.qp} events #{@study.events.qp} not copied into #{copy.qp}")
70
- assert_equal(1, copy.events.size, "#{@study.qp} events copy #{copy.qp} size incorrect")
71
- assert_not_same(copy.events.first, @study.events.first, "#{@study.qp} event #{@study.events.first} not copied into #{copy.qp} as new object")
72
- assert_same(copy, copy.events.first.study, "Dependent owner attribute not set to copied owner #{copy.qp}")
73
- end
74
-
75
- def test_merge
76
- # make a merge target
77
- target = CaRuby::CopyVisitor.new { |ref| ref.class.dependent_attributes }.visit(@study)
78
- # set the source ids
79
- @study.identifier = 1
80
- @event.identifier = 2
81
-
82
- # merge into the copy
83
- merger = CaRuby::MergeVisitor.new { |ref| ref.class.dependent_attributes }
84
- merger.visit(@study, target)
85
-
86
- # validate that the ids are copied
87
- assert_equal(@study.identifier, target.identifier, "Merge didn't copy the study identifier")
88
- assert_not_nil(target.events.first, "Merge didn't copy #{@study.qp} event #{@event.qp} to #{target.qp}")
89
- assert_equal(target.events.first.identifier, @event.identifier, "Merge didn't copy #{@study.qp} event #{@event.qp} event identifier to #{target.qp}")
90
- end
91
-
92
- def test_copy_id_match
93
- # set the study id
94
- @study.identifier = 1
95
- # mutate the references a la caCORE to form reference path @study -> @event -> s2,
96
- # where @study.identifier == s2.identifier
97
- s2 = @study.copy(:identifier)
98
- @event.study = s2
99
- s2.events.clear
100
- @study.events << @event
101
-
102
- # copy the mutated source
103
- copier = CaRuby::CopyVisitor.new { |ref| ref.class.dependent_attributes }
104
- copy = copier.visit(@study)
105
-
106
- # validate the copy
107
- assert_not_nil(copy.events.first, "Merge didn't copy event")
108
- assert_same(copy, copy.events.first.study, "Merge didn't match on study id")
109
- end
110
-
111
- def test_copy_with_visit_block
112
- visitor = CaRuby::CopyVisitor.new { |ref| ref.class.domain_attributes }
113
- id = visitor.visit(@study) { |src, tgt| src.identifier }
114
- assert_equal(@study.identifier, id, "Visit didn't return block result")
115
- end
116
-
117
- def test_copy_revisit_same_object
118
- # make a new event in the study, resulting in two paths to the study
119
- ClinicalTrials::StudyEvent.new(:study => @study, :calendar_event_point => 2.0)
120
- # eliminate extraneous references
121
- @study.coordinator = nil
122
- @study.enrollment.clear
123
- # visit all references, starting at an event, with traversal event -> study -> other event -> study
124
- visitor = CaRuby::CopyVisitor.new { |ref| ref.class.domain_attributes }
125
- visited = visitor.visit(@event)
126
- studies = visitor.visited.select { |ref, copy| ClinicalTrials::Study === ref }
127
- assert(!studies.empty?, "No study copied")
128
- assert_equal(1, studies.size, "More than one study copied")
129
- end
130
- end
@@ -1,80 +0,0 @@
1
- $:.unshift 'lib'
2
- $:.unshift '../caruby/lib'
3
-
4
- require "test/unit"
5
- require 'caruby'
6
-
7
- class JavaTest < Test::Unit::TestCase
8
- def test_ruby_to_java_date_conversion
9
- rdt = DateTime.now
10
- jdt = Java::JavaUtil::Date.from_ruby_date(rdt)
11
- assert(CaRuby::Resource.value_equal?(rdt, jdt.to_ruby_date), 'Ruby->Java->Ruby date conversion not idempotent')
12
- end
13
-
14
- def test_java_to_ruby_date_conversion
15
- cal = Java::JavaUtil::Calendar.instance
16
- verify_java_to_ruby_date_conversion(cal.time)
17
- # roll back to a a different DST setting
18
- if cal.timeZone.useDaylightTime then
19
- verify_java_to_ruby_date_conversion(flip_DST(cal))
20
- end
21
- end
22
-
23
- def test_zero_date
24
- jdt = Java::JavaUtil::Date.new(0)
25
- verify_java_to_ruby_date_conversion(jdt)
26
- end
27
-
28
- def flip_DST(cal)
29
- isdt = cal.timeZone.inDaylightTime(cal.time)
30
- 11.times do
31
- cal.roll(Java::JavaUtil::Calendar::MONTH, false)
32
- return cal.time if cal.timeZone.inDaylightTime(cal.time) != isdt
33
- end
34
- end
35
-
36
- def test_to_ruby
37
- assert_same(Java::JavaUtil::BitSet, Class.to_ruby(java.util.BitSet.java_class), "Java => Ruby class incorrect")
38
- end
39
-
40
- def test_list_delete_if
41
- list = Java::JavaUtil::ArrayList.new << 1 << 2
42
- assert_same(list, list.delete_if { |n| n == 2 })
43
- assert_equal([1], list.to_a, "Java ArrayList delete_if incorrect")
44
- end
45
-
46
- def test_set_delete_if
47
- list = Java::JavaUtil::HashSet.new << 1 << 2
48
- assert_same(list, list.delete_if { |n| n == 2 })
49
- assert_equal([1], list.to_a, "Java HashSet delete_if incorrect")
50
- end
51
-
52
- def test_list_clear
53
- list = Java::JavaUtil::ArrayList.new
54
- assert(list.empty?, "Cleared ArrayList not empty")
55
- assert_same(list, list.clear, "ArrayList clear result incorrect")
56
- end
57
-
58
- def test_set_clear
59
- set = Java::JavaUtil::HashSet.new
60
- assert(set.empty?, "Cleared HashSet not empty")
61
- assert_same(set, set.clear, "HashSet clear result incorrect")
62
- end
63
-
64
- def test_set_merge
65
- set = Java::JavaUtil::HashSet.new << 1
66
- other = Java::JavaUtil::HashSet.new << 2
67
- assert_same(set, set.merge(other), "HashSet merge result incorrect")
68
- assert(set.include?(2), "HashSet merge not updated")
69
- assert_same(set, set.clear, "HashSet clear result incorrect")
70
- end
71
-
72
- private
73
-
74
- def verify_java_to_ruby_date_conversion(jdate)
75
- rdt = jdate.to_ruby_date
76
- actual = Java::JavaUtil::Date.from_ruby_date(rdt)
77
- assert_equal(jdate.to_s, actual.to_s, 'Java->Ruby->Java date conversion not idempotent')
78
- assert_equal(jdate.to_ruby_date, rdt, 'Java->Ruby date reconversion not equal')
79
- end
80
- end
@@ -1,14 +0,0 @@
1
- # Add the Java jar file to the Java path.
2
- require 'test/fixtures/caruby/import/ext/bin/mixed_case.jar'
3
-
4
- require 'java'
5
- require "test/unit"
6
-
7
- # Verifies whether JRuby supports a mixed-case package. This can occur in caBIG applications, e.g.
8
- # the +caTissue+ PSBIN custom dynamic extensions. Work-around is to
9
- class MixedCaseTest < Test::Unit::TestCase
10
- def test_import
11
- assert_raises(NameError, "Mixed-case package not resolved") { Java::mixed.Case.Example }
12
- assert_nothing_raised("Mixed-case JRuby module not resolved") { Java::MixedCase::Example }
13
- end
14
- end
@@ -1,102 +0,0 @@
1
- LOG_FILE = 'test/results/log/migration.log'
2
-
3
- require File.join(File.dirname(__FILE__), '..', 'test_case')
4
- require 'caruby/domain/uniquify'
5
- require 'caruby/migration/migrator'
6
-
7
- module CaRuby
8
- module MigrationTestCase
9
- include CaRuby::TestCase
10
-
11
- #@param [String] fixtures the fixtures directory
12
- def setup(fixtures, database=nil)
13
- super(database)
14
- @fixtures = fixtures
15
- # Clear the uniquifier for this migration.
16
- CaRuby::ResourceUniquifier.instance.clear
17
- end
18
-
19
- ## MIGRATION TEST UTILITY METHODS ##
20
-
21
- private
22
-
23
- # Runs a migrator on the given input fixture and options.
24
- #
25
- # @param (see #create_migrator)
26
- # @option (see #create_migrator)
27
- def migrate_to_database(fixture, opts={}, &verifier)
28
- mgtr = create_migrator(fixture, opts)
29
- logger.debug { "Migration test migrating #{fixture} fixture..." }
30
- mgtr.migrate_to_database(&verifier)
31
- logger.debug { "Migration test migrated #{fixture} fixture." }
32
- end
33
-
34
- # Creates a new Migrator for the given fixture with the given options.
35
- # If a factory block is provided, then that factory is called to make a new
36
- # Migrator instance. Otherwise, {CaTissue::Migrator#initialize} makes the instance.
37
- #
38
- # If there is no :input option, then the migration input is set to the
39
- # _fixture_.+csv+ file in the {#initialize} fixtures directory.
40
- #
41
- # @param [Symbol] fixture the migration test fixture
42
- # @param [{Symbol => Object}] opts (see CaTissue::Migrator#initialize)
43
- # @option (see CaTissue::Migrator#initialize)
44
- # @return [CaTissue::Migrator]
45
- # @yield [opts] the optional Migrator factory
46
- def create_migrator(fixture, opts={}, &factory)
47
- opts[:input] ||= File.join(@fixtures, fixture.to_s + '.csv')
48
- block_given? ? yield(opts) : CaRuby::Migrator.new(opts)
49
- end
50
-
51
- # Verifies that the given test fixture is successfully migrated.
52
- # Each migrated target object is validated using {CaTissue::TestCase#verify_saved}.
53
- # In addition, if a verifier block is given to this method, then that block is
54
- # called on the target migration object, or nil if no target was migrated.
55
- # Supported options are described in {CaTissue::Migrator#migrate}.
56
- #
57
- # @param (see #verify_target)
58
- # @option (see #verify_target)
59
- # @yield (see #verify_target)
60
- # @yieldparam (see #verify_target)
61
- def verify_save(fixture, opts={})
62
- logger.debug { "Migrating the #{fixture} test fixture..." }
63
- opts[:unique] = true unless opts.has_key?(:unique)
64
- migrate_to_database(fixture, opts) do |tgt|
65
- verify_saved(tgt)
66
- yield tgt if block_given?
67
- end
68
- end
69
-
70
- # Verifies the given fixture migration.
71
- # Each migrated target object is validated using {#validate_target}.
72
- # The target is migrated but not stored.
73
- #
74
- # @param [Symbol] fixture the test fixture to verify
75
- # @param [<Symbol>] opts the migration options
76
- # @option (see CaTissue::Migrator#migrate)
77
- # @yield [target] verifies the given target
78
- # @yieldparam [Resource] target the domain object to verify
79
- def verify_target(fixture, opts={}, &verifier)
80
- opts[:unique] ||= false
81
- create_migrator(fixture, opts).migrate { |tgt| validate_target(tgt, &verifier) }
82
- end
83
-
84
- # Validates that the given target was successfully migrated.
85
- # If a target was migrated, then this method calls {CaTissue::TestCase#verify_defaults}
86
- # to confirm that the target can be stored.
87
- # In addition, if a block is given to this method then the block is called on the
88
- # (possibly nil) migration target.
89
- #
90
- # @param [Resource] target the domain object to verify
91
- # @yield (see #verify_target)
92
- # @yieldparam (see #verify_target)
93
- def validate_target(target)
94
- assert_not_nil(target, "Missing target")
95
- logger.debug { "Validating migration target #{target}..." }
96
- verify_defaults(target) if target
97
- yield target if block_given?
98
- logger.debug { "Validated migration target #{target}." }
99
- target
100
- end
101
- end
102
- end
@@ -1,230 +0,0 @@
1
- $:.unshift '../caruby/lib'
2
-
3
- # open the logger
4
- LOG_FILE = 'test/results/log/catissue.log' unless defined?(LOG_FILE)
5
- require 'caruby/util/log' and
6
- CaRuby::Log.instance.open(LOG_FILE, :shift_age => 10, :shift_size => 1048576, :debug => true)
7
-
8
- require 'caruby'
9
-
10
- module CaRuby
11
- module TestCase
12
- attr_reader :database
13
-
14
- def setup(database=nil)
15
- super()
16
- logger.info("Testing #{name}...")
17
- @database = database
18
- end
19
-
20
- def teardown
21
- super
22
- @database.close if @database
23
- logger.info("Test #{name} completed.")
24
- end
25
-
26
- def defaults
27
- @defaults ||= CaTissueTest.defaults.uniquify
28
- end
29
-
30
- # Tests the domain object +add_defaults_local+ method.
31
- # Subclasses are responsible for setting every attribute that is a pre-condition for default value initialization.
32
- def verify_defaults(subject)
33
- subject.add_defaults
34
- msg = "#{subject.qp} with default attributes fails validation"
35
- assert_nothing_raised(ValidationError, msg) { subject.validate }
36
- end
37
-
38
- # Tests saving the subject. Calls {Database::Writer#save} on the subject and verifies that subject and its
39
- # references were persisted.
40
- #
41
- # @param [Resource] subject the object to save
42
- def verify_save(subject)
43
- logger.debug{ "Verifying #{subject.qp} save with content:\n#{dump(subject)}" }
44
- # capture the save operation time
45
- @database.clear
46
- st = Stopwatch.measure { @database.open { |db| db.save(subject) } }.elapsed
47
- # the database execution time
48
- dt = @database.execution_time
49
- logger.debug { "#{subject.qp} save took #{'%.2f' % st} seconds, of which #{'%.2f' % dt} were database operations." }
50
- verify_saved(subject)
51
- end
52
-
53
- # Verifies that the given subject and its references were persisted.
54
- #
55
- # @param [Resource] subject the saved object to verify
56
- def verify_saved(subject)
57
- logger.debug { "Verifying saved content of #{subject}..." }
58
- subject.dependent? ? verify_saved_dependent(subject) : verify_saved_independent(subject)
59
- logger.debug { "Verified saved content of #{subject}." }
60
- end
61
-
62
- # Tests a query on the given template.
63
- # The block given to this method is called on the query result.
64
- def verify_query(template, *path) # :yields: result
65
- yield database.query(template, *path)
66
- end
67
-
68
- # Returns the Ruby date as determined by setting a Java Date property.
69
- def date(year, month, day)
70
- jdate = java.util.Calendar.instance
71
- jdate.clear
72
- jdate.set(year, month - 1, day)
73
- jdate.time.to_ruby_date
74
- end
75
-
76
- private
77
-
78
- def dump(obj)
79
- @database.lazy_loader.suspend { obj.dump }
80
- end
81
-
82
- # @param (see #mock_storable_template)
83
- # @return (see #mock_storable_template)
84
- def mock_create_template(obj)
85
- mock_storable_template(obj) { |ref| ref.class.creatable_domain_attributes }
86
- end
87
-
88
- # @param (see #mock_storable_template)
89
- # @return (see #mock_storable_template)
90
- def mock_update_template(obj)
91
- mock_storable_template(obj) { |ref| ref.class.updatable_domain_attributes }
92
- end
93
-
94
- # @param [Resource] obj the domain object to "save"
95
- # @return [Resource] the template to use in the save operation
96
- # @yield [ref] the storable attributes
97
- # @yieldparam [Resource] ref the domain object to "save"
98
- def mock_storable_template(obj, &selector)
99
- # add fake identifiers to prerequisite references
100
- obj.class.storable_prerequisite_attributes.each do |attr|
101
- obj.send(attr).enumerate { |ref| ref.identifier = 1 }
102
- end
103
- # the template builder
104
- bldr = CaRuby::StoreTemplateBuilder.new(@database, &selector)
105
- # the save template
106
- bldr.build_template(obj)
107
- end
108
-
109
- def verify_saved_dependent(dependent)
110
- verify_dependency(dependent)
111
- verify_saved_content(dependent)
112
- end
113
-
114
- def verify_dependency(dependent)
115
- return if dependent.class.owner_attribute.nil?
116
- ownr = dependent.owner
117
- assert_not_nil(ownr, "Owner missing for dependent: #{dependent}")
118
- attribute = ownr.class.dependent_attribute(dependent.class)
119
- assert_not_nil(attribute, "Dependent attribute missing for #{dependent} owner #{ownr}")
120
- # a dependent collection reference must be refetched
121
- if ownr.class.collection_attribute?(attribute) then
122
- verify_saved_dependent_collection_member(dependent, ownr, attribute)
123
- else
124
- assert_not_nil(dependent.identifier, "Stored dependent #{dependent} identifier is not set")
125
- end
126
- end
127
-
128
- # Verifies that the given dependent has an identifier and that the given owner dependent attribute value
129
- # contains the dependent.
130
- #
131
- # JRuby Set include? incorrectly returns false in the OHSU PSR samples_test test_save_grade
132
- # call to this method. Work around by using Set detect rather than include?.
133
- def verify_saved_dependent_collection_member(dependent, owner, attribute)
134
- deps = owner.send(attribute)
135
- assert(deps.detect { |dep| dep == dependent }, "Owner #{owner.qp} #{attribute} value #{deps.pp_s} does not contain #{dependent}")
136
- assert_not_nil(dependent.identifier, "Identifier not set for stored owner #{owner.qp} #{attribute} dependent collection member #{dependent}")
137
- end
138
-
139
- # Verifies the subject stored content.
140
- def verify_saved_independent(subject)
141
- subject_id = subject.identifier
142
- assert_not_nil(subject_id, "#{subject.class.qp} identifier not set")
143
- verify_saved_content(subject)
144
- end
145
-
146
- # Verifies that the given subject matches the database content. Does not verify subject unless it has
147
- # a secondary key.
148
- def verify_saved_content(subject)
149
- attrs = subject.class.secondary_key_attributes
150
- return if attrs.empty?
151
- rqd = attrs & subject.class.mandatory_attributes
152
- missing = rqd.reject { |attr| subject.send(attr) }
153
- assert(missing.empty?, "#{subject} is missing values for secondary key attributes #{missing.to_series}")
154
- # make a secondary key search template
155
- vh = attrs.to_compact_hash do |attr|
156
- v = subject.send(attr)
157
- Resource === v ? v.copy : v
158
- end
159
- tmpl = subject.class.new(vh)
160
- # find the template in the database
161
- logger.debug { "Verifying #{subject.qp} by finding and comparing template #{tmpl.pp_s}..." }
162
- assert_not_nil(tmpl.find, "#{subject} not found in database")
163
- # compare the subject to the fetched template
164
- verify_that_saved_matches_fetched(subject, tmpl)
165
- end
166
-
167
- # Verifies that the given expected domain object has the same content as actual,
168
- # and that the dependents match.
169
- #
170
- # @quirk caTissue caTissue mutilates an unspecified specimen type available quantity, e.g.
171
- # changing a Specimen with specimen type 'Not Specified' from available quantity 1, initial
172
- # quantity 1 to available quantity 0, initial quantity 3 results in available quantity 2
173
- # in database. The update is necessary when creating the Specimen with available quantity 0,
174
- # initial quantity 3 to work around a different caTissue bug. Thus, the bug work-around
175
- # is broken by a different caTissue bug.
176
- #
177
- # @param [Resource] expected the saved value
178
- # @param [Resource] actual the fetched value
179
- def verify_that_saved_matches_fetched(expected, actual)
180
- expected.class.saved_nondomain_attributes.each do |attr|
181
- # TODO - available_quantity broken for spc type Not Specified
182
- # compare attributes that are fetched and set on create
183
- attr_md = expected.class.attribute_metadata(attr)
184
- if verify_saved_attribute?(attr_md) then
185
- eval = expected.database.lazy_loader.suspend { expected.send(attr) }
186
- next if eval.nil_or_empty?
187
- aval = actual.send(attr)
188
- if eval.nil? then
189
- assert_nil(aval, "#{expected.qp} was saved without a #{attr} value, but was stored in the database with value #{actual.qp}")
190
- else
191
- assert_not_nil(aval, "#{expected.qp} was saved with #{attr} value #{eval.qp}, but this value was not found in the database.")
192
- if attr == :available_quantity and expected.specimen_type == 'Not Specified' and eval != aval then
193
- logger.warn("Skipped broken caTissue unspecified specimen type available comparison.")
194
- else
195
- assert(CaRuby::Resource.value_equal?(eval, aval), "#{expected.qp} was saved with #{attr} value #{eval.qp} that does not match the database value #{aval.qp}")
196
- end
197
- end
198
- end
199
- end
200
- verify_dependents_match(expected, actual)
201
- end
202
-
203
- # @param [Attribute] attr_md the saved attribute to check
204
- # @return whether the attribute is fetched, creatable and not volatile
205
- def verify_saved_attribute?(attr_md)
206
- attr_md.fetched? and attr_md.creatable? and not attr_md.volatile?
207
- end
208
-
209
- # Verifies that each expected dependent matches an actual dependent and has the same content.
210
- def verify_dependents_match(expected, actual)
211
- expected.class.dependent_attributes.each do |attr|
212
- edeps = expected.database.lazy_loader.suspend { expected.send(attr) }
213
- next if edeps.nil_or_empty?
214
- adeps = actual.send(attr)
215
- logger.debug { "Verifying #{expected.qp} dependent #{attr} #{edeps.qp} against #{actual.qp} #{adeps.qp}..." } unless edeps.nil_or_empty?
216
- if edeps.collection? then
217
- edeps.each do |edep|
218
- adep = edep.match_in_owner_scope(adeps)
219
- assert_not_nil(adep, "#{expected} #{attr} dependent #{edep} not found in fetched #{adeps.pp_s}")
220
- verify_that_saved_matches_fetched(edep, adep)
221
- end
222
- else
223
- edep = edeps; adep = adeps;
224
- assert_not_nil(adep, "#{expected} #{attr} dependent #{edep} not found in database")
225
- verify_that_saved_matches_fetched(edep, adep)
226
- end
227
- end
228
- end
229
- end
230
- end