mingle_events 0.0.4
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.
- 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
|