mingle_events 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/LICENSE.txt +202 -0
- data/README.textile +117 -0
- data/lib/mingle_events.rb +26 -0
- data/lib/mingle_events/feed.rb +5 -0
- data/lib/mingle_events/feed/author.rb +28 -0
- data/lib/mingle_events/feed/category.rb +75 -0
- data/lib/mingle_events/feed/element_support.rb +19 -0
- data/lib/mingle_events/feed/entry.rb +96 -0
- data/lib/mingle_events/feed/page.rb +61 -0
- data/lib/mingle_events/http_error.rb +26 -0
- data/lib/mingle_events/mingle_basic_auth_access.rb +71 -0
- data/lib/mingle_events/mingle_oauth_access.rb +40 -0
- data/lib/mingle_events/poller.rb +32 -0
- data/lib/mingle_events/processors.rb +10 -0
- data/lib/mingle_events/processors/author_filter.rb +62 -0
- data/lib/mingle_events/processors/card_data.rb +102 -0
- data/lib/mingle_events/processors/card_type_filter.rb +28 -0
- data/lib/mingle_events/processors/category_filter.rb +19 -0
- data/lib/mingle_events/processors/custom_property_filter.rb +30 -0
- data/lib/mingle_events/processors/http_post_publisher.rb +20 -0
- data/lib/mingle_events/processors/pipeline.rb +20 -0
- data/lib/mingle_events/processors/puts_publisher.rb +17 -0
- data/lib/mingle_events/project_custom_properties.rb +33 -0
- data/lib/mingle_events/project_event_fetcher.rb +96 -0
- data/test/mingle_events/feed/author_test.rb +39 -0
- data/test/mingle_events/feed/category_test.rb +20 -0
- data/test/mingle_events/feed/entry_test.rb +140 -0
- data/test/mingle_events/feed/page_test.rb +82 -0
- data/test/mingle_events/poller_test.rb +47 -0
- data/test/mingle_events/processors/author_filter_test.rb +80 -0
- data/test/mingle_events/processors/card_data_test.rb +210 -0
- data/test/mingle_events/processors/card_type_filter_test.rb +51 -0
- data/test/mingle_events/processors/category_filter_test.rb +27 -0
- data/test/mingle_events/processors/custom_property_filter_test.rb +51 -0
- data/test/mingle_events/processors/pipeline_test.rb +32 -0
- data/test/mingle_events/project_custom_properties_test.rb +39 -0
- data/test/mingle_events/project_event_fetcher_test.rb +122 -0
- data/test/test_helper.rb +163 -0
- data/test/web_hook_server/web_hook_server.rb +6 -0
- metadata +140 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module MingleEvents
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Filters events by card types. As events do not contain the type
|
5
|
+
# of the card, this filter requires a lookup against Mingle to
|
6
|
+
# determine the type of the card that sourced the event. In the case
|
7
|
+
# of the card's being deleted in the interim between the actual event
|
8
|
+
# and this filtering, the event will be filtered as there is no means
|
9
|
+
# to determine its type. Therefore, it's recommended to also
|
10
|
+
# subscribe a 'CardDeleted' processor to the same project.
|
11
|
+
class CardTypeFilter
|
12
|
+
|
13
|
+
def initialize(card_types, card_data)
|
14
|
+
@card_types = card_types
|
15
|
+
@card_data = card_data
|
16
|
+
end
|
17
|
+
|
18
|
+
def process_events(events)
|
19
|
+
events.select do |event|
|
20
|
+
event.card? &&
|
21
|
+
@card_data.for_card_event(event) &&
|
22
|
+
@card_types.include?(@card_data.for_card_event(event)[:card_type_name])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MingleEvents
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Removes events from the stream that do not match all of the specified categories
|
5
|
+
class CategoryFilter
|
6
|
+
|
7
|
+
def initialize(categories)
|
8
|
+
@categories = categories
|
9
|
+
end
|
10
|
+
|
11
|
+
def process_events(events)
|
12
|
+
events.select do |event|
|
13
|
+
@categories.all?{|c| event.categories.include?(c)}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module MingleEvents
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Filters events by a single custom property value.
|
5
|
+
# As events will not necessarily contain this data,
|
6
|
+
# this filter requires a lookup against Mingle to
|
7
|
+
# determine the type of the card that sourced the event. In the case
|
8
|
+
# of the card's being deleted in the interim between the actual event
|
9
|
+
# and this filtering, the event will be filtered as there is no means
|
10
|
+
# to determine its type. Therefore, it's recommended to also
|
11
|
+
# subscribe a 'CardDeleted' processor to the same project.
|
12
|
+
class CustomPropertyFilter
|
13
|
+
|
14
|
+
def initialize(property_name, property_value, card_data)
|
15
|
+
@property_name = property_name
|
16
|
+
@property_value = property_value
|
17
|
+
@card_data = card_data
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_events(events)
|
21
|
+
events.select do |event|
|
22
|
+
event.card? &&
|
23
|
+
@card_data.for_card_event(event) &&
|
24
|
+
@property_value == @card_data.for_card_event(event)[:custom_properties][@property_name]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module MingleEvents
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
class HttpPostPublisher
|
5
|
+
|
6
|
+
def initialize(url)
|
7
|
+
@url = url
|
8
|
+
end
|
9
|
+
|
10
|
+
def process_events(events)
|
11
|
+
events.map{|e| process_event(e)}
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_event(event)
|
15
|
+
Net::HTTP.post_form(URI.parse(@url), {'event' => event.raw_xml}).body
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module MingleEvents
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Manages the passing of a stream of events through a sequence of processors
|
5
|
+
class Pipeline
|
6
|
+
|
7
|
+
def initialize(processors)
|
8
|
+
@processors = processors
|
9
|
+
end
|
10
|
+
|
11
|
+
def process_events(events)
|
12
|
+
processed_events = events
|
13
|
+
@processors.each do |processor|
|
14
|
+
processed_events = processor.process_events(processed_events)
|
15
|
+
end
|
16
|
+
processed_events
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MingleEvents
|
2
|
+
module Processors
|
3
|
+
|
4
|
+
# Writes each event in stream to stdout, mostly for demonstration purposes
|
5
|
+
class PutsPublisher
|
6
|
+
|
7
|
+
def process_events(events)
|
8
|
+
events.map{|e| process_event(e)}
|
9
|
+
end
|
10
|
+
|
11
|
+
def process_event(event)
|
12
|
+
puts "Processing event #{event}"
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module MingleEvents
|
2
|
+
|
3
|
+
class ProjectCustomProperties
|
4
|
+
|
5
|
+
def initialize(mingle_access, project_identifier)
|
6
|
+
@mingle_access = mingle_access
|
7
|
+
@project_identifier = project_identifier
|
8
|
+
end
|
9
|
+
|
10
|
+
def property_name_for_column(column_name)
|
11
|
+
property_names_by_column_name[column_name]
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def property_names_by_column_name
|
17
|
+
@property_names_by_column_name ||= lookup_property_names_by_column_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def lookup_property_names_by_column_name
|
21
|
+
as_document.search('/property_definitions/property_definition').inject({}) do |mapping, element|
|
22
|
+
mapping[element.at('column_name').inner_text] = element.at('name').inner_text
|
23
|
+
mapping
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def as_document
|
28
|
+
@as_document ||= Nokogiri::XML(@mingle_access.fetch_page("/api/v2/projects/#{@project_identifier}/property_definitions.xml"))
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module MingleEvents
|
2
|
+
|
3
|
+
# fetch all unseen events and write them to disk for future processing
|
4
|
+
class ProjectEventFetcher
|
5
|
+
|
6
|
+
def initialize(project_identifier, mingle_access, state_dir=nil)
|
7
|
+
@project_identifier = project_identifier
|
8
|
+
@mingle_access = mingle_access
|
9
|
+
base_uri = URI.parse(mingle_access.base_url)
|
10
|
+
@state_dir = File.expand_path(state_dir || File.join('~', '.mingle_events', base_uri.host, base_uri.port.to_s, project_identifier, 'fetched_events'))
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset
|
14
|
+
FileUtils.rm_rf(@state_dir)
|
15
|
+
end
|
16
|
+
|
17
|
+
def fetch_latest
|
18
|
+
page = Feed::Page.new("/api/v2/projects/#{@project_identifier}/feeds/events.xml", @mingle_access)
|
19
|
+
most_recent_new_entry = page.entries.first
|
20
|
+
|
21
|
+
last_fetched_entry = load_last_fetched_entry
|
22
|
+
fetched_previously_seen_event = false
|
23
|
+
next_entry = nil
|
24
|
+
while !fetched_previously_seen_event && page
|
25
|
+
page.entries.each do |entry|
|
26
|
+
|
27
|
+
if last_fetched_entry && entry.entry_id == last_fetched_entry.entry_id
|
28
|
+
fetched_previously_seen_event = true
|
29
|
+
break
|
30
|
+
end
|
31
|
+
|
32
|
+
write_entry_to_disk(entry, next_entry)
|
33
|
+
next_entry = entry
|
34
|
+
|
35
|
+
end
|
36
|
+
page = page.next
|
37
|
+
end
|
38
|
+
|
39
|
+
update_current_state(most_recent_new_entry)
|
40
|
+
|
41
|
+
file_for_entry(next_entry)
|
42
|
+
end
|
43
|
+
|
44
|
+
def file_for_entry(entry)
|
45
|
+
return nil if entry.nil?
|
46
|
+
|
47
|
+
entry_id_as_uri = URI.parse(entry.entry_id)
|
48
|
+
relative_path_parts = entry_id_as_uri.path.split('/')
|
49
|
+
entry_id_int = relative_path_parts.last
|
50
|
+
insertions = ["#{entry_id_int.to_i/16384}", "#{entry_id_int.to_i%16384}"]
|
51
|
+
relative_path_parts = relative_path_parts[0..-2] + insertions + ["#{entry_id_int}.yml"]
|
52
|
+
File.join(@state_dir, *relative_path_parts)
|
53
|
+
end
|
54
|
+
|
55
|
+
def current_state_file
|
56
|
+
File.expand_path(File.join(@state_dir, 'current_state.yml'))
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def load_last_fetched_entry
|
62
|
+
current_state = if File.exist?(current_state_file)
|
63
|
+
YAML.load(File.new(current_state_file))
|
64
|
+
else
|
65
|
+
{:last_fetched_entry_info_file => nil}
|
66
|
+
end
|
67
|
+
last_fetched_entry = if current_state[:last_fetched_entry_info_file]
|
68
|
+
last_fetched_entry_info = YAML.load(File.new(current_state[:last_fetched_entry_info_file]))
|
69
|
+
Feed::Entry.new(Nokogiri::XML(last_fetched_entry_info[:entry_xml]).at('/entry'))
|
70
|
+
else
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def update_current_state(most_recent_new_entry)
|
76
|
+
if most_recent_new_entry
|
77
|
+
File.open(current_state_file, 'w') do |out|
|
78
|
+
YAML.dump({:last_fetched_entry_info_file => file_for_entry(most_recent_new_entry)}, out)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def write_entry_to_disk(entry, next_entry)
|
84
|
+
file = file_for_entry(entry)
|
85
|
+
FileUtils.mkdir_p(File.dirname(file))
|
86
|
+
file_content = {
|
87
|
+
:entry_xml => entry.raw_xml,
|
88
|
+
:next_entry_file_path => file_for_entry(next_entry)
|
89
|
+
}
|
90
|
+
File.open(file, 'w') do |out|
|
91
|
+
YAML.dump(file_content, out)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
|
2
|
+
|
3
|
+
module MingleEvents
|
4
|
+
module Feed
|
5
|
+
|
6
|
+
class AuthorTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_parse_attributes
|
9
|
+
element = Nokogiri.XML(%{
|
10
|
+
<author xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
11
|
+
<name>Sammy Soso</name>
|
12
|
+
<email>sammy@example.com</email>
|
13
|
+
<uri>https://mingle.example.com/api/v2/users/233.xml</uri>
|
14
|
+
<mingle:icon>https://mingle.example.com/user/icon/233/profile.jpg</mingle:icon>
|
15
|
+
</author>})
|
16
|
+
|
17
|
+
author = Author.new(element)
|
18
|
+
assert_equal("Sammy Soso", author.name)
|
19
|
+
assert_equal("sammy@example.com", author.email)
|
20
|
+
assert_equal("https://mingle.example.com/api/v2/users/233.xml", author.uri)
|
21
|
+
assert_equal("https://mingle.example.com/user/icon/233/profile.jpg", author.icon_uri)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_parse_attributes_when_no_optional_fields
|
25
|
+
element = Nokogiri.XML(%{
|
26
|
+
<author xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
27
|
+
<name>Sammy Soso</name>
|
28
|
+
</author>})
|
29
|
+
author = Author.new(element)
|
30
|
+
assert_equal("Sammy Soso", author.name)
|
31
|
+
assert_nil(author.email)
|
32
|
+
assert_nil(author.uri)
|
33
|
+
assert_nil(author.icon_uri)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
|
2
|
+
|
3
|
+
module MingleEvents
|
4
|
+
module Feed
|
5
|
+
|
6
|
+
class CategoryTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_equality
|
9
|
+
assert_equal(Category::CARD, Category::CARD)
|
10
|
+
assert_equal(Category::CARD, Category.new('card', 'http://www.thoughtworks-studios.com/ns/mingle#categories'))
|
11
|
+
assert_not_equal(Category::CARD, Category::PAGE)
|
12
|
+
assert_not_equal(Category::CARD, nil)
|
13
|
+
assert_not_equal(Category::CARD, Object.new)
|
14
|
+
assert_equal(:foo, {Category::CARD => :foo}[Category.new('card', 'http://www.thoughtworks-studios.com/ns/mingle#categories')])
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
|
2
|
+
|
3
|
+
module MingleEvents
|
4
|
+
module Feed
|
5
|
+
|
6
|
+
class EntryTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_parse_basic_attributes
|
9
|
+
element_xml_text = %{
|
10
|
+
<entry xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
11
|
+
<id>https://mingle.example.com/projects/mingle/events/index/234443</id>
|
12
|
+
<title>Page Special:HeaderActions changed</title>
|
13
|
+
<updated>2011-02-03T08:12:42Z</updated>
|
14
|
+
<author>
|
15
|
+
<name>Sammy Soso</name>
|
16
|
+
<email>sammy@example.com</email>
|
17
|
+
<uri>https://mingle.example.com/api/v2/users/233.xml</uri>
|
18
|
+
</author>
|
19
|
+
</entry>}
|
20
|
+
element = Nokogiri::XML(element_xml_text)
|
21
|
+
|
22
|
+
entry = Entry.new(element)
|
23
|
+
# assert_equal(element_xml_text.inspect, entry.raw_xml.inspect)
|
24
|
+
assert_equal("https://mingle.example.com/projects/mingle/events/index/234443", entry.entry_id)
|
25
|
+
assert_equal("Page Special:HeaderActions changed", entry.title)
|
26
|
+
assert_equal("Thu Feb 03 08:12:42 UTC 2011", entry.updated.to_s)
|
27
|
+
assert_equal("Sammy Soso", entry.author.name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_parse_categories
|
31
|
+
element_xml_text = %{
|
32
|
+
<entry xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
33
|
+
<category term="foo" scheme='http://tws.com/ns#mingle' />
|
34
|
+
<category term="bar" scheme="http://tws.com/ns#go" />
|
35
|
+
</entry>}
|
36
|
+
element = Nokogiri::XML(element_xml_text)
|
37
|
+
|
38
|
+
entry = Entry.new(element)
|
39
|
+
assert_equal(
|
40
|
+
[Category.new('foo', 'http://tws.com/ns#mingle'), Category.new('bar', 'http://tws.com/ns#go')],
|
41
|
+
entry.categories
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_parse_card_number_and_version
|
46
|
+
|
47
|
+
# the links below contain intentionally nonsensical data so as to ensure
|
48
|
+
# that the card number is derived from a single, precise position
|
49
|
+
|
50
|
+
element_xml_text = %{
|
51
|
+
<entry xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
52
|
+
<category term="card" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
53
|
+
<link href="https://mingle.example.com/projects/atlas/cards/102" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="text/html" title="bug #103"/>
|
54
|
+
<link href="https://mingle.example.com/api/v2/projects/atlas/cards/104.xml?version=7" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="application/vnd.mingle+xml" title="bug #105 (v7)"/>
|
55
|
+
<link href="https://mingle.example.com/api/v2/projects/atlas/cards/106.xml" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="application/vnd.mingle+xml" title="bug #107"/>
|
56
|
+
<link href="https://mingle.example.com/projects/atlas/cards/108?version=17" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="text/html" title="bug #109 (v7)"/>
|
57
|
+
</entry>}
|
58
|
+
element = Nokogiri::XML(element_xml_text)
|
59
|
+
|
60
|
+
entry = Entry.new(element)
|
61
|
+
assert_equal(106, entry.card_number)
|
62
|
+
assert_equal(7, entry.version)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_card_number_and_version_throws_error_when_event_not_related_to_a_card
|
66
|
+
element_xml_text = %{
|
67
|
+
<entry xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
68
|
+
<category term="page" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
69
|
+
</entry>}
|
70
|
+
element = Nokogiri::XML(element_xml_text)
|
71
|
+
|
72
|
+
entry = Entry.new(element)
|
73
|
+
|
74
|
+
begin
|
75
|
+
entry.card_number
|
76
|
+
fail("Should not have been able to retrieve a card number for non card-related event!")
|
77
|
+
rescue Exception => e
|
78
|
+
assert_equal("You cannot get the card number for an event that is not sourced by a card!", e.message)
|
79
|
+
end
|
80
|
+
|
81
|
+
begin
|
82
|
+
entry.version
|
83
|
+
fail("Should not have been able to retrieve a card version for non card-related event!")
|
84
|
+
rescue Exception => e
|
85
|
+
assert_equal("You cannot get card version data for an event that is not sourced by a card!", e.message)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_parse_card_version_resource_uri
|
91
|
+
|
92
|
+
# the links below contain intentionally nonsensical data so as to ensure
|
93
|
+
# that the card number is derived from a single, precise position
|
94
|
+
|
95
|
+
element_xml_text = %{
|
96
|
+
<entry xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
97
|
+
<category term="card" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
98
|
+
<link href="https://mingle.example.com/projects/atlas/cards/102" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="text/html" title="bug #103"/>
|
99
|
+
<link href="https://mingle.example.com/api/v2/projects/atlas/cards/104.xml?version=7" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="application/vnd.mingle+xml" title="bug #105 (v7)"/>
|
100
|
+
<link href="https://mingle.example.com/api/v2/projects/atlas/cards/106.xml" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="application/vnd.mingle+xml" title="bug #107"/>
|
101
|
+
<link href="https://mingle.example.com/projects/atlas/cards/108?version=7" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="text/html" title="bug #109 (v7)"/>
|
102
|
+
</entry>}
|
103
|
+
element = Nokogiri::XML(element_xml_text)
|
104
|
+
|
105
|
+
entry = Entry.new(element)
|
106
|
+
assert_equal('https://mingle.example.com/api/v2/projects/atlas/cards/104.xml?version=7', entry.card_version_resource_uri)
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_card_version_resource_uri_throws_error_when_not_card_event
|
110
|
+
element_xml_text = %{
|
111
|
+
<entry xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
112
|
+
<category term="page" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
113
|
+
</entry>}
|
114
|
+
element = Nokogiri::XML(element_xml_text)
|
115
|
+
|
116
|
+
entry = Entry.new(element)
|
117
|
+
begin
|
118
|
+
entry.card_version_resource_uri
|
119
|
+
fail("Should not have been able to retrieve a card version resource URI for non card-related event!")
|
120
|
+
rescue Exception => e
|
121
|
+
assert_equal("You cannot get card version data for an event that is not sourced by a card!", e.message)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_entry_id_aliased_as_event_id
|
126
|
+
element_xml_text = %{
|
127
|
+
<entry xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
128
|
+
<id>https://mingle.example.com/projects/mingle/events/index/234443</id>
|
129
|
+
</entry>}
|
130
|
+
element = Nokogiri::XML(element_xml_text)
|
131
|
+
|
132
|
+
entry = Entry.new(element)
|
133
|
+
assert_equal('https://mingle.example.com/projects/mingle/events/index/234443', entry.event_id)
|
134
|
+
assert_equal(entry.entry_id, entry.event_id)
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|