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.
- data/Gemfile +9 -0
- data/History.md +5 -1
- data/lib/caruby.rb +3 -5
- data/lib/caruby/caruby-src.tar.gz +0 -0
- data/lib/caruby/database.rb +53 -69
- data/lib/caruby/database/application_service.rb +25 -0
- data/lib/caruby/database/cache.rb +60 -0
- data/lib/caruby/database/fetched_matcher.rb +52 -38
- data/lib/caruby/database/lazy_loader.rb +4 -4
- data/lib/caruby/database/operation.rb +34 -0
- data/lib/caruby/database/persistable.rb +171 -86
- data/lib/caruby/database/persistence_service.rb +32 -34
- data/lib/caruby/database/persistifier.rb +100 -43
- data/lib/caruby/database/reader.rb +107 -85
- data/lib/caruby/database/reader_template_builder.rb +60 -0
- data/lib/caruby/database/saved_matcher.rb +3 -3
- data/lib/caruby/database/sql_executor.rb +88 -17
- data/lib/caruby/database/writer.rb +213 -177
- data/lib/caruby/database/writer_template_builder.rb +334 -0
- data/lib/caruby/{util → helpers}/controlled_value.rb +0 -0
- data/lib/caruby/{util → helpers}/coordinate.rb +4 -4
- data/lib/caruby/{util → helpers}/person.rb +3 -3
- data/lib/caruby/{util → helpers}/properties.rb +7 -9
- data/lib/caruby/{util → helpers}/roman.rb +2 -2
- data/lib/caruby/{util → helpers}/version.rb +1 -1
- data/lib/caruby/json/deserializer.rb +2 -2
- data/lib/caruby/json/serializer.rb +49 -7
- data/lib/caruby/metadata.rb +30 -0
- data/lib/caruby/metadata/java_property.rb +21 -0
- data/lib/caruby/metadata/propertied.rb +191 -0
- data/lib/caruby/metadata/property.rb +22 -0
- data/lib/caruby/metadata/property_characteristics.rb +201 -0
- data/lib/caruby/migration/migratable.rb +11 -182
- data/lib/caruby/rdbi/driver/jdbc.rb +446 -0
- data/lib/caruby/resource.rb +20 -823
- data/lib/caruby/version.rb +1 -1
- data/test/lib/caruby/database/cache_test.rb +54 -0
- data/test/lib/caruby/{util → helpers}/controlled_value_test.rb +3 -5
- data/test/lib/caruby/{util → helpers}/person_test.rb +4 -6
- data/test/lib/caruby/helpers/properties_test.rb +34 -0
- data/test/lib/caruby/{util → helpers}/roman_test.rb +2 -3
- data/test/lib/caruby/{util → helpers}/version_test.rb +2 -3
- data/test/lib/helper.rb +7 -0
- metadata +161 -214
- data/lib/caruby/cli/application.rb +0 -36
- data/lib/caruby/cli/command.rb +0 -202
- data/lib/caruby/csv/csv_mapper.rb +0 -159
- data/lib/caruby/csv/csvio.rb +0 -203
- data/lib/caruby/database/search_template_builder.rb +0 -56
- data/lib/caruby/database/store_template_builder.rb +0 -278
- data/lib/caruby/domain.rb +0 -193
- data/lib/caruby/domain/attribute.rb +0 -584
- data/lib/caruby/domain/attributes.rb +0 -628
- data/lib/caruby/domain/dependency.rb +0 -225
- data/lib/caruby/domain/id_alias.rb +0 -22
- data/lib/caruby/domain/importer.rb +0 -183
- data/lib/caruby/domain/introspection.rb +0 -176
- data/lib/caruby/domain/inverse.rb +0 -172
- data/lib/caruby/domain/inversible.rb +0 -90
- data/lib/caruby/domain/java_attribute.rb +0 -173
- data/lib/caruby/domain/merge.rb +0 -185
- data/lib/caruby/domain/metadata.rb +0 -142
- data/lib/caruby/domain/mixin.rb +0 -35
- data/lib/caruby/domain/properties.rb +0 -95
- data/lib/caruby/domain/reference_visitor.rb +0 -428
- data/lib/caruby/domain/uniquify.rb +0 -50
- data/lib/caruby/import/java.rb +0 -387
- data/lib/caruby/migration/migrator.rb +0 -918
- data/lib/caruby/migration/resource_module.rb +0 -9
- data/lib/caruby/migration/uniquify.rb +0 -17
- data/lib/caruby/util/attribute_path.rb +0 -44
- data/lib/caruby/util/cache.rb +0 -56
- data/lib/caruby/util/class.rb +0 -149
- data/lib/caruby/util/collection.rb +0 -1152
- data/lib/caruby/util/domain_extent.rb +0 -46
- data/lib/caruby/util/file_separator.rb +0 -65
- data/lib/caruby/util/inflector.rb +0 -27
- data/lib/caruby/util/log.rb +0 -95
- data/lib/caruby/util/math.rb +0 -12
- data/lib/caruby/util/merge.rb +0 -59
- data/lib/caruby/util/module.rb +0 -18
- data/lib/caruby/util/options.rb +0 -97
- data/lib/caruby/util/partial_order.rb +0 -35
- data/lib/caruby/util/pretty_print.rb +0 -204
- data/lib/caruby/util/stopwatch.rb +0 -74
- data/lib/caruby/util/topological_sync_enumerator.rb +0 -62
- data/lib/caruby/util/transitive_closure.rb +0 -55
- data/lib/caruby/util/tree.rb +0 -48
- data/lib/caruby/util/trie.rb +0 -37
- data/lib/caruby/util/uniquifier.rb +0 -30
- data/lib/caruby/util/validation.rb +0 -20
- data/lib/caruby/util/visitor.rb +0 -365
- data/lib/caruby/util/weak_hash.rb +0 -36
- data/test/lib/caruby/csv/csv_mapper_test.rb +0 -40
- data/test/lib/caruby/csv/csvio_test.rb +0 -69
- data/test/lib/caruby/database/persistable_test.rb +0 -92
- data/test/lib/caruby/domain/domain_test.rb +0 -112
- data/test/lib/caruby/domain/inversible_test.rb +0 -99
- data/test/lib/caruby/domain/reference_visitor_test.rb +0 -130
- data/test/lib/caruby/import/java_test.rb +0 -80
- data/test/lib/caruby/import/mixed_case_test.rb +0 -14
- data/test/lib/caruby/migration/test_case.rb +0 -102
- data/test/lib/caruby/test_case.rb +0 -230
- data/test/lib/caruby/util/cache_test.rb +0 -23
- data/test/lib/caruby/util/class_test.rb +0 -61
- data/test/lib/caruby/util/collection_test.rb +0 -398
- data/test/lib/caruby/util/command_test.rb +0 -55
- data/test/lib/caruby/util/domain_extent_test.rb +0 -60
- data/test/lib/caruby/util/file_separator_test.rb +0 -30
- data/test/lib/caruby/util/inflector_test.rb +0 -12
- data/test/lib/caruby/util/lazy_hash_test.rb +0 -34
- data/test/lib/caruby/util/merge_test.rb +0 -83
- data/test/lib/caruby/util/module_test.rb +0 -25
- data/test/lib/caruby/util/options_test.rb +0 -59
- data/test/lib/caruby/util/partial_order_test.rb +0 -42
- data/test/lib/caruby/util/pretty_print_test.rb +0 -85
- data/test/lib/caruby/util/properties_test.rb +0 -50
- data/test/lib/caruby/util/stopwatch_test.rb +0 -18
- data/test/lib/caruby/util/topological_sync_enumerator_test.rb +0 -69
- data/test/lib/caruby/util/transitive_closure_test.rb +0 -67
- data/test/lib/caruby/util/tree_test.rb +0 -23
- data/test/lib/caruby/util/trie_test.rb +0 -14
- data/test/lib/caruby/util/visitor_test.rb +0 -278
- data/test/lib/caruby/util/weak_hash_test.rb +0 -45
- data/test/lib/examples/clinical_trials/migration/migration_test.rb +0 -58
- 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
|