rets 0.9.0 → 0.10.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/Manifest.txt +24 -0
  4. data/README.md +73 -1
  5. data/Rakefile +1 -1
  6. data/lib/rets.rb +202 -1
  7. data/lib/rets/client.rb +83 -94
  8. data/lib/rets/http_client.rb +42 -0
  9. data/lib/rets/metadata.rb +15 -3
  10. data/lib/rets/metadata/caching.rb +59 -0
  11. data/lib/rets/metadata/file_cache.rb +29 -0
  12. data/lib/rets/metadata/json_serializer.rb +27 -0
  13. data/lib/rets/metadata/lookup_table.rb +65 -0
  14. data/lib/rets/metadata/lookup_type.rb +3 -4
  15. data/lib/rets/metadata/marshal_serializer.rb +27 -0
  16. data/lib/rets/metadata/multi_lookup_table.rb +70 -0
  17. data/lib/rets/metadata/null_cache.rb +24 -0
  18. data/lib/rets/metadata/resource.rb +39 -29
  19. data/lib/rets/metadata/rets_class.rb +27 -23
  20. data/lib/rets/metadata/rets_object.rb +32 -0
  21. data/lib/rets/metadata/table.rb +9 -101
  22. data/lib/rets/metadata/table_factory.rb +19 -0
  23. data/lib/rets/metadata/yaml_serializer.rb +27 -0
  24. data/lib/rets/parser/compact.rb +61 -18
  25. data/lib/rets/parser/error_checker.rb +8 -1
  26. data/test/fixtures.rb +58 -0
  27. data/test/test_caching.rb +89 -0
  28. data/test/test_client.rb +44 -24
  29. data/test/test_error_checker.rb +18 -0
  30. data/test/test_file_cache.rb +42 -0
  31. data/test/test_http_client.rb +96 -60
  32. data/test/test_json_serializer.rb +26 -0
  33. data/test/test_marshal_serializer.rb +26 -0
  34. data/test/test_metadata.rb +62 -450
  35. data/test/test_metadata_class.rb +50 -0
  36. data/test/test_metadata_lookup_table.rb +21 -0
  37. data/test/test_metadata_lookup_type.rb +12 -0
  38. data/test/test_metadata_multi_lookup_table.rb +60 -0
  39. data/test/test_metadata_object.rb +20 -0
  40. data/test/test_metadata_resource.rb +140 -0
  41. data/test/test_metadata_root.rb +151 -0
  42. data/test/test_metadata_table.rb +21 -0
  43. data/test/test_metadata_table_factory.rb +24 -0
  44. data/test/test_parser_compact.rb +23 -28
  45. data/test/test_yaml_serializer.rb +26 -0
  46. metadata +29 -5
@@ -0,0 +1,50 @@
1
+ require_relative "helper"
2
+
3
+ class TestMetadataClass < MiniTest::Test
4
+ def test_rets_class_find_table
5
+ table = Rets::Metadata::Table.new({ "SystemName" => 'test' }, 'resource_id')
6
+ rets_class = Rets::Metadata::RetsClass.new('class_name', 'visible_name', 'standard name', 'description', [table])
7
+
8
+ assert_equal table, rets_class.find_table("test")
9
+ end
10
+
11
+ def test_rets_class_find_lookup_table
12
+ table = Rets::Metadata::LookupTable.new('resource_id', [], { "SystemName" => 'test' })
13
+ rets_class = Rets::Metadata::RetsClass.new('class_name', 'visible_name', 'standard name', 'description', [table])
14
+
15
+ assert_equal table, rets_class.find_table("test")
16
+ end
17
+
18
+ def test_rets_class_find_table_container
19
+ resource_id = "a"
20
+ class_name = "b"
21
+
22
+ table = mock(:resource => resource_id, :class => class_name)
23
+ metadata = { :table => [table] }
24
+
25
+ assert_equal table, Rets::Metadata::RetsClass.find_table_container(metadata, resource_id, class_name)
26
+ end
27
+
28
+ def test_rets_class_build
29
+ resource_id = "id"
30
+ lookup_types = []
31
+
32
+ table_fragment = stub(:fragment)
33
+ table_container = stub(:tables => [table_fragment])
34
+ table = stub(:table)
35
+
36
+ Rets::Metadata::TableFactory.expects(:build).with(table_fragment, resource_id, lookup_types).returns(table)
37
+ Rets::Metadata::RetsClass.expects(:find_table_container).returns(table_container)
38
+
39
+ rets_class = Rets::Metadata::RetsClass.build({}, resource_id, lookup_types, "")
40
+
41
+ assert_equal(rets_class.tables, [table])
42
+ end
43
+
44
+ def test_rets_class_build_when_find_table_container_returns_nil
45
+ new_rets_class = stub(:new_rets_class)
46
+ Rets::Metadata::RetsClass.stubs(:new => new_rets_class)
47
+ Rets::Metadata::RetsClass.stubs(:find_table_container => nil)
48
+ Rets::Metadata::RetsClass.build({}, "resource_id", [], "")
49
+ end
50
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "helper"
2
+
3
+ class TestMetadataLookupTable < MiniTest::Test
4
+ def setup
5
+ $VERBOSE = true
6
+ end
7
+
8
+ def teardown
9
+ $VERBOSE = false
10
+ end
11
+
12
+ def test_lookup_table_resolve_returns_single_value_if_not_multi
13
+ fragment = {}
14
+ lookup_types = [
15
+ Rets::Metadata::LookupType.new("Value" => "A,B", "LongValue" => "AaaBbb")
16
+ ]
17
+ lookup_table = Rets::Metadata::LookupTable.new("Foo", lookup_types, fragment)
18
+
19
+ assert_equal "AaaBbb", lookup_table.resolve("A,B")
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ require_relative "helper"
2
+
3
+ class TestMetadataLookupType < MiniTest::Test
4
+ def test_lookup_type_initialize
5
+ fragment = { "Value" => 'a', "LongValue" => 'c' }
6
+
7
+ lookup_type = Rets::Metadata::LookupType.new(fragment)
8
+
9
+ assert_equal('a', lookup_type.value)
10
+ assert_equal('c', lookup_type.long_value)
11
+ end
12
+ end
@@ -0,0 +1,60 @@
1
+ require_relative "helper"
2
+
3
+ class TestMetadataMultiLookupTable < MiniTest::Test
4
+ def setup
5
+ @fragment = { "Interpretation" => "LookupMulti" }
6
+ $VERBOSE = true
7
+ end
8
+
9
+ def teardown
10
+ $VERBOSE = false
11
+ end
12
+
13
+ def test_lookup_table_resolve_returns_empty_array_when_value_is_empty_and_is_multi?
14
+ lookup_table = Rets::Metadata::MultiLookupTable.new("Foo", [], @fragment)
15
+
16
+ assert_equal [], lookup_table.resolve("")
17
+ end
18
+
19
+ def test_lookup_table_resolve_returns_multi_value_array_when_multi
20
+ lookup_types = [
21
+ Rets::Metadata::LookupType.new("Value" => "A", "LongValue" => "Aaa"),
22
+ Rets::Metadata::LookupType.new("Value" => "B", "LongValue" => "Bbb"),
23
+ ]
24
+ lookup_table = Rets::Metadata::MultiLookupTable.new("Foo", lookup_types, @fragment)
25
+
26
+ assert_equal ["Aaa", "Bbb"], lookup_table.resolve("A,B")
27
+ end
28
+
29
+ #Sandicor does this :|
30
+ def test_lookup_table_resolve_returns_multi_value_array_when_multi_with_quoted_values
31
+ lookup_types = [
32
+ Rets::Metadata::LookupType.new("Value" => "A", "LongValue" => "Aaa"),
33
+ Rets::Metadata::LookupType.new("Value" => "B", "LongValue" => "Bbb"),
34
+ ]
35
+ lookup_table = Rets::Metadata::MultiLookupTable.new("Foo", lookup_types, @fragment)
36
+
37
+ assert_equal ["Aaa", "Bbb"], lookup_table.resolve(%q["A","B"])
38
+ end
39
+
40
+ # This scenario is unfortunately common.
41
+ def test_lookup_table_resolve_returns_nil_when_lookup_type_is_not_present_for_multi_value
42
+ lookup_types = [
43
+ Rets::Metadata::LookupType.new("Value" => "A", "LongValue" => "Aaa"),
44
+ ]
45
+ lookup_table = Rets::Metadata::MultiLookupTable.new("Foo", lookup_types, @fragment)
46
+
47
+ lookup_table.expects(:warn).with("Discarding unmappable value of #{"B".inspect}")
48
+
49
+ assert_equal ["Aaa", ""], lookup_table.resolve("A,B")
50
+ end
51
+
52
+ # This scenario is unfortunately common.
53
+ def test_lookup_table_resolve_returns_nil_when_lookup_type_is_not_present_for_single_value
54
+ lookup_table = Rets::Metadata::MultiLookupTable.new("Foo", [], @fragment)
55
+
56
+ lookup_table.expects(:warn).with("Discarding unmappable value of #{"A".inspect}")
57
+
58
+ assert_equal [""], lookup_table.resolve("A")
59
+ end
60
+ end
@@ -0,0 +1,20 @@
1
+ require_relative "helper"
2
+
3
+ class TestMetadataObject < MiniTest::Test
4
+ def test_rets_object_build
5
+ name = "Name"
6
+ mime_type = "mimetype"
7
+ description = "description"
8
+
9
+ object_fragment = {
10
+ "VisibleName" => name,
11
+ "MIMEType" => mime_type,
12
+ "Description" => description,
13
+ }
14
+
15
+ assert_equal(
16
+ Rets::Metadata::RetsObject.build(object_fragment),
17
+ Rets::Metadata::RetsObject.new(name, mime_type, description)
18
+ )
19
+ end
20
+ end
@@ -0,0 +1,140 @@
1
+ require_relative "helper"
2
+
3
+ class TestMetadataResource < MiniTest::Test
4
+ def test_resource_build_lookup_tree
5
+ metadata = stub(:metadata)
6
+ resource = stub(:resource)
7
+
8
+ Rets::Metadata::Resource.expects(:find_lookup_containers).
9
+ with(metadata, resource).
10
+ returns([stub(:lookups => [{"LookupName" => "Foo"}])])
11
+
12
+ Rets::Metadata::Resource.expects(:find_lookup_type_containers).
13
+ with(metadata, resource, "Foo").
14
+ returns([stub(:lookup_types => [{"Value" => "111", "LongValue" => "Bar"}])])
15
+
16
+ tree = Rets::Metadata::Resource.build_lookup_tree(resource, metadata)
17
+
18
+ assert_equal ["Foo"], tree.keys
19
+ assert_equal 1, tree["Foo"].size
20
+
21
+ lookup_type = tree["Foo"].first
22
+
23
+ assert_equal "111", lookup_type.value
24
+ assert_equal "Bar", lookup_type.long_value
25
+ end
26
+
27
+ def test_resource_build_classes
28
+ resource_id = "id"
29
+ lookup_types = []
30
+
31
+ metadata = stub(:metadata)
32
+ rets_class = stub(:rets_class)
33
+ rets_class_fragment = stub(:rets_class_fragment)
34
+
35
+ Rets::Metadata::RetsClass.expects(:build).with(rets_class_fragment, resource_id, lookup_types, metadata).returns(rets_class)
36
+ Rets::Metadata::Resource.expects(:find_rets_classes).with(metadata, resource_id).returns([rets_class_fragment])
37
+
38
+ classes = Rets::Metadata::Resource.build_classes(resource_id, lookup_types, metadata)
39
+ assert_equal([rets_class], classes)
40
+ end
41
+
42
+ def test_resource_build_objects
43
+ resource_id = "id"
44
+
45
+ metadata = stub(:metadata)
46
+ rets_object = stub(:rets_object)
47
+ rets_object_fragment = stub(:rets_object_fragment)
48
+
49
+ Rets::Metadata::RetsObject.expects(:build).with(rets_object_fragment).returns(rets_object)
50
+ Rets::Metadata::Resource.expects(:find_rets_objects).with(metadata, resource_id).returns([rets_object_fragment])
51
+
52
+ objects = Rets::Metadata::Resource.build_objects(resource_id, metadata)
53
+ assert_equal([rets_object], objects)
54
+ end
55
+
56
+ def test_resource_build
57
+ fragment = { "ResourceID" => "test" }
58
+
59
+ lookup_types = stub(:lookup_types)
60
+ classes = stub(:classes)
61
+ objects = stub(:classes)
62
+ metadata = stub(:metadata)
63
+
64
+ Rets::Metadata::Resource.stubs(:build_lookup_tree => lookup_types)
65
+ Rets::Metadata::Resource.stubs(:build_classes => classes)
66
+ Rets::Metadata::Resource.stubs(:build_objects => objects)
67
+
68
+ resource = Rets::Metadata::Resource.build(fragment, metadata, Logger.new(STDOUT))
69
+
70
+ assert_equal(classes, resource.rets_classes)
71
+ assert_equal(objects, resource.rets_objects)
72
+ end
73
+
74
+ def test_resource_build_with_incomplete_classes
75
+ fragment = { "ResourceID" => "test" }
76
+
77
+ lookup_types = stub(:lookup_types)
78
+ metadata = stub(:metadata)
79
+
80
+ Rets::Metadata::Resource.stubs(:build_lookup_tree => lookup_types)
81
+ Rets::Metadata::Resource.stubs(:build_classes).raises(Rets::Metadata::Resource::MissingRetsClass)
82
+
83
+ error_log = StringIO.new
84
+ resource = Rets::Metadata::Resource.build(fragment, metadata, Logger.new(error_log))
85
+
86
+ error_log.rewind
87
+ error_msg = error_log.read
88
+ assert error_msg.include?('MissingRetsClass')
89
+ assert_equal(nil, resource)
90
+ end
91
+
92
+ def test_resource_find_lookup_containers
93
+ resource_id = "id"
94
+ metadata = {
95
+ :lookup => [
96
+ stub(:resource => resource_id),
97
+ stub(:resource => resource_id),
98
+ stub(:resource => "a")
99
+ ]
100
+ }
101
+
102
+ lookup_containers = Rets::Metadata::Resource.find_lookup_containers(metadata, resource_id)
103
+
104
+ assert_equal(2, lookup_containers.size)
105
+ assert_equal(["id", "id"], lookup_containers.map(&:resource))
106
+ end
107
+
108
+ def test_resource_find_lookup_type_containers
109
+ resource_id = "id"
110
+ metadata = {
111
+ :lookup_type => [
112
+ stub(:resource => resource_id, :lookup => "look"),
113
+ stub(:resource => resource_id, :lookup => "look"),
114
+ stub(:resource => resource_id, :lookup => "not_look"),
115
+ stub(:resource => "a", :lookup => "look"),
116
+ stub(:resource => "a", :lookup => "not_look")
117
+ ]
118
+ }
119
+ lookup_type_containers = Rets::Metadata::Resource.find_lookup_type_containers(metadata, resource_id, "look")
120
+
121
+ assert_equal(2, lookup_type_containers.size)
122
+ assert_equal(["id", "id"], lookup_type_containers.map(&:resource))
123
+ end
124
+
125
+ def test_resource_find_rets_classes
126
+ rets_classes = stub(:rets_classes)
127
+
128
+ metadata = { :class => [stub(:resource => "id", :classes => rets_classes),
129
+ stub(:resource => "id", :classes => rets_classes),
130
+ stub(:resource => "a")]}
131
+
132
+ assert_equal(rets_classes, Rets::Metadata::Resource.find_rets_classes(metadata, "id"))
133
+ end
134
+
135
+ def test_resource_find_rets_class
136
+ rets_class = Rets::Metadata::RetsClass.new('test', '', '', '', [])
137
+ resource = Rets::Metadata::Resource.new('', '', [rets_class], [])
138
+ assert_equal(rets_class, resource.find_rets_class("test"))
139
+ end
140
+ end
@@ -0,0 +1,151 @@
1
+ require_relative "helper"
2
+
3
+ class TestMetadataRoot < MiniTest::Test
4
+ def setup
5
+ @root = Rets::Metadata::Root.new(Logger.new(STDOUT), {})
6
+ end
7
+
8
+ def test_metadata_root_build_tree
9
+ resource = stub(:id => "X")
10
+ Rets::Metadata::Resource.stubs(:build => resource)
11
+ resource_fragment = stub(:resource_fragment)
12
+ resource_container = stub(:rows => [resource_fragment])
13
+ @root.stubs(:metadata_types => { :resource => [resource_container] })
14
+ assert_equal({"x" => resource}, @root.build_tree)
15
+ assert_equal(resource, @root.build_tree["X"])
16
+ end
17
+
18
+ def test_metadata_root_version
19
+ @root.instance_variable_set("@metadata_types", {:system => [stub(:version => "1")]})
20
+ assert_equal "1", @root.version
21
+ end
22
+
23
+ def test_metadata_root_date
24
+ @root.instance_variable_set("@metadata_types", {:system => [stub(:date => "1")]})
25
+ assert_equal "1", @root.date
26
+ end
27
+
28
+ def test_metadata_root_different_version
29
+ @root.stubs(:version).returns("1.2.2")
30
+ @root.stubs(:date).returns("1")
31
+
32
+ current_version = "1.2.3"
33
+ current_timestamp = "1"
34
+
35
+ assert !@root.current?(current_timestamp, current_version)
36
+ end
37
+
38
+ def test_metadata_root_same_version
39
+ @root.stubs(:version).returns("1.2.2")
40
+ @root.stubs(:date).returns("1")
41
+
42
+ current_version = "1.2.2"
43
+ current_timestamp = "2"
44
+
45
+ assert @root.current?(current_timestamp, current_version)
46
+ end
47
+
48
+ def test_metadata_root_no_version_same_timestamp
49
+ @root.stubs(:version).returns("")
50
+ @root.stubs(:date).returns("1")
51
+
52
+ current_version = "1.2.3"
53
+ current_timestamp = "1"
54
+
55
+ assert @root.current?(current_timestamp, current_version)
56
+ end
57
+
58
+ def test_metadata_root_current
59
+ @root.stubs(:version).returns("1.2.2")
60
+ @root.stubs(:date).returns("1")
61
+
62
+ current_timestamp = "1"
63
+ current_version = "1.2.2"
64
+
65
+ assert @root.current?(current_timestamp, current_version)
66
+ end
67
+
68
+ # missing timestamp - this happens in violation of the spec.
69
+ def test_metadata_root_current_ignores_missing_timestamp
70
+ @root.stubs(:version).returns("1.2.2")
71
+ @root.stubs(:date).returns("1")
72
+
73
+ current_timestamp = nil
74
+ current_version = "1.2.2"
75
+
76
+ assert @root.current?(current_timestamp, current_version)
77
+ end
78
+
79
+ # missing version - this happens in violation of the spec.
80
+ def test_metadata_root_current_ignores_missing_version
81
+ @root.stubs(:version).returns("1.2.2")
82
+ @root.stubs(:date).returns("1")
83
+
84
+ current_timestamp = "1"
85
+ current_version = nil
86
+
87
+ assert @root.current?(current_timestamp, current_version)
88
+ end
89
+
90
+ def test_metadata_root_metadata_types_constructs_a_hash_of_metadata_types_from_sources
91
+ test_sources = { "X" => "Y", "Z" => "W" }
92
+ root = Rets::Metadata::Root.new(stub(:logger), test_sources)
93
+ root.stubs(:build_containers => "Y--")
94
+ Nokogiri.stubs(:parse => "Y-")
95
+
96
+ assert_equal({:x => "Y--", :z => "Y--"}, root.metadata_types)
97
+ end
98
+
99
+ def test_metadata_root_build_containers_selects_correct_tags
100
+ doc = "<RETS><METADATA-FOO></METADATA-FOO><MET-FOO></MET-FOO><METADATA-BAR /></RETS>"
101
+
102
+ @root.expects(:build_container).with { |fragment| fragment.name == "METADATA-FOO" }
103
+ @root.expects(:build_container).with { |fragment| fragment.name == "METADATA-BAR" }
104
+
105
+ @root.build_containers(Nokogiri.parse(doc))
106
+ end
107
+
108
+ def test_metadata_root_build_container_uses_row_containers_for_resource
109
+ doc = Nokogiri.parse(METADATA_RESOURCE).xpath("//METADATA-RESOURCE").first
110
+
111
+ container = @root.build_container(doc)
112
+
113
+ assert_instance_of Rets::Metadata::Containers::ResourceContainer, container
114
+
115
+ assert_equal 13, container.resources.size
116
+
117
+ resource = container.resources.first
118
+
119
+ assert_equal "ActiveAgent", resource["StandardName"]
120
+ end
121
+
122
+ def test_metadata_root_build_container_uses_system_container_for_system
123
+ doc = Nokogiri.parse(METADATA_SYSTEM).xpath("//METADATA-SYSTEM").first
124
+
125
+ container = @root.build_container(doc)
126
+ assert_instance_of Rets::Metadata::Containers::SystemContainer, container
127
+ end
128
+
129
+ def test_metadata_root_build_container_uses_base_container_for_unknown_metadata_types
130
+ doc = Nokogiri.parse(METADATA_UNKNOWN).xpath("//METADATA-FOO").first
131
+
132
+ container = @root.build_container(doc)
133
+ assert_instance_of Rets::Metadata::Containers::Container, container
134
+ end
135
+
136
+ def test_root_can_be_serialized
137
+ sources = { :x => "a" }
138
+ root = Rets::Metadata::Root.new(stub(:logger), sources)
139
+ assert_equal sources, root.marshal_dump
140
+ end
141
+
142
+ def test_root_can_be_unserialized
143
+ logger = stub(:logger)
144
+ sources = { :x => "a" }
145
+
146
+ root_to_serialize = Rets::Metadata::Root.new(logger, sources)
147
+ new_root = Rets::Metadata::Root.new(logger, root_to_serialize.marshal_dump)
148
+
149
+ assert_equal root_to_serialize.marshal_dump, new_root.marshal_dump
150
+ end
151
+ end