place 0.1.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.
- data/Changelog +11 -0
- data/LICENSE +207 -0
- data/README.markdown +96 -0
- data/Rakefile +9 -0
- data/Technical.markdown +29 -0
- data/examples/sample-1.rb +34 -0
- data/lib/place/comment.rb +76 -0
- data/lib/place/link.rb +20 -0
- data/lib/place/participation.rb +12 -0
- data/lib/place/project.rb +159 -0
- data/lib/place/time_point.rb +55 -0
- data/lib/place/user.rb +79 -0
- data/lib/place/work_item.rb +179 -0
- data/lib/place/work_record.rb +51 -0
- data/lib/place.rb +112 -0
- data/place.gemspec +19 -0
- data/test/helper.rb +9 -0
- data/test/test_comment.rb +35 -0
- data/test/test_place.rb +28 -0
- data/test/test_project.rb +100 -0
- data/test/test_time_point.rb +50 -0
- data/test/test_user.rb +51 -0
- data/test/test_workitem.rb +172 -0
- metadata +133 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module Place
|
2
|
+
|
3
|
+
# A TimePoint is a "named milestone"
|
4
|
+
class TimePoint < Ohm::Model
|
5
|
+
attribute :tid
|
6
|
+
index :tid
|
7
|
+
attribute :url
|
8
|
+
|
9
|
+
attribute :name
|
10
|
+
attribute :time
|
11
|
+
attribute :description
|
12
|
+
|
13
|
+
reference :project, Project
|
14
|
+
|
15
|
+
collection :workitems, WorkItem, :timepoint
|
16
|
+
|
17
|
+
class << self; attr_accessor :rules end
|
18
|
+
@rules = {
|
19
|
+
'name' => '//time-point/field[@id="name"]',
|
20
|
+
'description' => '//time-point/field[@id="description"]',
|
21
|
+
'time' => '//time-point/field[@id="time"]'
|
22
|
+
}
|
23
|
+
|
24
|
+
# Collect all timepoints (url) under a given project url
|
25
|
+
def self.collect_all(base_url)
|
26
|
+
Dir.glob(base_url + '/tracker/timepoints/*.xml').each do |filename|
|
27
|
+
TimePoint.create(
|
28
|
+
:tid => File.basename(filename, '.xml'),
|
29
|
+
:url => filename,
|
30
|
+
:project => Project.find_by_url(base_url)
|
31
|
+
)
|
32
|
+
Place.logger.info("collected timepoint at #{filename}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Retrieve a specific timepoint data (name, time, description)
|
37
|
+
def retrieve
|
38
|
+
content = IO.readlines(url).join('')
|
39
|
+
doc = Nokogiri::XML(content)
|
40
|
+
self.class.rules.each_pair do |k,v|
|
41
|
+
tmp = doc.xpath(v)
|
42
|
+
self.send("#{k}=", tmp[0].content) unless tmp[0].nil?
|
43
|
+
end
|
44
|
+
Place.logger.info("retrieved timepoint #{self.url}")
|
45
|
+
self.save
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.find_by_tid(tid)
|
49
|
+
return nil if tid.nil?
|
50
|
+
tps = self.find(:tid => tid.to_s)
|
51
|
+
tps.nil? ? nil : tps[0]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/lib/place/user.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
module Place
|
2
|
+
|
3
|
+
# A User is an account under Polarion
|
4
|
+
class User < Ohm::Model
|
5
|
+
attribute :name
|
6
|
+
index :name
|
7
|
+
attribute :url
|
8
|
+
|
9
|
+
attribute :full_name
|
10
|
+
attribute :description
|
11
|
+
attribute :email
|
12
|
+
|
13
|
+
collection :workrecords, WorkRecord, :user
|
14
|
+
collection :comments, Comment, :author
|
15
|
+
|
16
|
+
set :watches, WorkItem
|
17
|
+
collection :author_of, WorkItem, :author
|
18
|
+
set :assignments, WorkItem
|
19
|
+
|
20
|
+
collection :participations, Participation, :user
|
21
|
+
|
22
|
+
|
23
|
+
# Collect all users (name, url) under a given repository url
|
24
|
+
def self.collect_all(base_url)
|
25
|
+
Dir.glob(base_url + '/.polarion/user-management/users/**/user.xml').each do |filename|
|
26
|
+
User.create(
|
27
|
+
:name => File.dirname(filename).split(/\//).last,
|
28
|
+
:url => filename
|
29
|
+
)
|
30
|
+
Place.logger.info("collected user at #{filename}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self; attr_accessor :rules end
|
35
|
+
@rules = {
|
36
|
+
'full_name' => '//user/field[@id="name"]',
|
37
|
+
'description' => '//user/field[@id="description"]',
|
38
|
+
'email' => '//user/field[@id="email"]'
|
39
|
+
}
|
40
|
+
|
41
|
+
# Retrieve a specific user data (based on name and url only)
|
42
|
+
def retrieve
|
43
|
+
content = IO.readlines(url).join('')
|
44
|
+
doc = Nokogiri::XML(content)
|
45
|
+
self.class.rules.each_pair do |k,v|
|
46
|
+
tmp = doc.xpath(v)
|
47
|
+
self.send("#{k}=", tmp[0].content) unless tmp[0].nil?
|
48
|
+
end
|
49
|
+
Place.logger.info("retrieved user at #{self.name}")
|
50
|
+
self.save
|
51
|
+
end
|
52
|
+
|
53
|
+
def retrieve_watches
|
54
|
+
content = IO.readlines(url).join('')
|
55
|
+
doc = Nokogiri::XML(content)
|
56
|
+
doc.xpath('//user/field[@id="watches"]/list//item').each do |wa|
|
57
|
+
prj, wid = wa.text.split('$')
|
58
|
+
if Project.all.map{|p| p.name}.include?(prj)
|
59
|
+
wi = WorkItem.find_by_wid(wid)
|
60
|
+
unless wi.nil?
|
61
|
+
wi.watches << User.find_by_name(name)
|
62
|
+
wi.save
|
63
|
+
self.watches << wi
|
64
|
+
self.save
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
Place.logger.info("retrieved watches for user #{self.name}")
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
# Find a user by the given name, returns +nil+ if not present
|
73
|
+
def self.find_by_name(name)
|
74
|
+
users = self.find(:name => name.to_s)
|
75
|
+
users.nil? ? nil : users[0]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Place
|
5
|
+
|
6
|
+
# Each WorkItem has a work-item id (wid) and an url that refers to its main xml file (workitem.xml) located under its own directory (that terminates with its Polarion ID = our wid).
|
7
|
+
class WorkItem < Ohm::Model
|
8
|
+
attribute :wid
|
9
|
+
index :wid
|
10
|
+
|
11
|
+
attribute :url
|
12
|
+
attribute :type
|
13
|
+
index :type
|
14
|
+
attribute :fields
|
15
|
+
|
16
|
+
reference :author, User
|
17
|
+
set :assignees, User
|
18
|
+
|
19
|
+
reference :timepoint, TimePoint
|
20
|
+
reference :project, Project
|
21
|
+
|
22
|
+
set :watches, User
|
23
|
+
collection :workrecords, WorkRecord, :workitem
|
24
|
+
collection :comments, Comment, :workitem
|
25
|
+
|
26
|
+
# Collect all workitems (wid and url) under a given project url
|
27
|
+
def self.collect_all(base_url)
|
28
|
+
Dir.glob(base_url + '/tracker/workitems/**/workitem.xml').each do |filename|
|
29
|
+
wi = WorkItem.create(
|
30
|
+
:wid => File.dirname(filename).split(/\//).last,
|
31
|
+
:url => filename,
|
32
|
+
:fields => "{}"
|
33
|
+
)
|
34
|
+
project_prefix = wi.wid.split(/\-/)[0]
|
35
|
+
wi.project = Project.find_by_prefix(project_prefix)
|
36
|
+
Place.logger.info("collected workitem at #{wi.url}")
|
37
|
+
wi.save
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Retrieve a specific workitem (based on wid and url only)
|
42
|
+
def retrieve
|
43
|
+
content = IO.readlines(url).join('')
|
44
|
+
doc = Nokogiri::XML(content)
|
45
|
+
|
46
|
+
doc.xpath('//work-item/field').each do |field|
|
47
|
+
self[field.attributes['id'].to_s] = field.content
|
48
|
+
end
|
49
|
+
|
50
|
+
self.type = self[:type]
|
51
|
+
|
52
|
+
self.author = User.find_by_name(self[:author])
|
53
|
+
|
54
|
+
unless self[:assignee].nil?
|
55
|
+
self[:assignee].split.each do |name|
|
56
|
+
u = User.find_by_name(name)
|
57
|
+
unless u.nil?
|
58
|
+
self.assignees << u
|
59
|
+
u.assignments << self
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
self.timepoint = TimePoint.find_by_tid(self['timePoint'])
|
65
|
+
|
66
|
+
%w(initialEstimate timeSpent remainingEstimate).each do |t|
|
67
|
+
self[t] = to_hours(self[t])
|
68
|
+
end
|
69
|
+
|
70
|
+
# links
|
71
|
+
doc.xpath('/work-item/field[@id="linkedWorkItems"]/list/struct').each do |struct|
|
72
|
+
l = Link.create(
|
73
|
+
:role => struct.xpath('item[@id="role"]').text,
|
74
|
+
:suspect => struct.xpath('item[@id="suspect"]').text == 'true' ? true : false,
|
75
|
+
:revision => struct.xpath('item[@id="revision"]').empty? ? false : true,
|
76
|
+
:from => self,
|
77
|
+
:to => WorkItem.find_by_wid(struct.xpath('item[@id="workItem"]').text),
|
78
|
+
:from_wid => self.wid,
|
79
|
+
:to_wid => struct.xpath('item[@id="workItem"]').text
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
# comments
|
84
|
+
Dir.glob(File.dirname(url) + '/comment-*.xml').each do |filename|
|
85
|
+
c = Comment.create(:url => filename)
|
86
|
+
c.retrieve
|
87
|
+
end
|
88
|
+
|
89
|
+
# workrecords
|
90
|
+
Dir.glob(File.dirname(url) + '/workrecord-*.xml').each do |filename|
|
91
|
+
wr = WorkRecord.create(:url => filename)
|
92
|
+
wr.retrieve
|
93
|
+
end
|
94
|
+
|
95
|
+
Place.logger.info("retrieved workitem #{self.wid}")
|
96
|
+
|
97
|
+
self.save
|
98
|
+
end
|
99
|
+
|
100
|
+
# Get value from specified field, +nil+ if not present
|
101
|
+
def [](fname)
|
102
|
+
JSON.parse(fields)[fname.to_s]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Set value for specified field
|
106
|
+
def []=(fname, fvalue)
|
107
|
+
h = JSON.parse(self.fields)
|
108
|
+
h[fname.to_s] = fvalue
|
109
|
+
self.fields = h.to_json
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns a workitem by its wid, +nil+ if not present
|
113
|
+
def self.find_by_wid(wid)
|
114
|
+
wis = self.find(:wid => wid)
|
115
|
+
wis.nil? ? nil : wis[0]
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns all workitems of the given +type+
|
119
|
+
def self.find_by_type(type)
|
120
|
+
#self.all.select{|wi| wi.type == type.to_s}
|
121
|
+
self.find(:type => type.to_s)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns all links from the current workitems to others, eventually only with a specified role
|
125
|
+
def links_out(role=nil)
|
126
|
+
if role.nil?
|
127
|
+
Link.find(:from_wid => self.wid)
|
128
|
+
else
|
129
|
+
Link.find(:from_wid => self.wid, :role => role.to_s)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns all links to the current workitems from others, eventually only with a specified role
|
134
|
+
def links_in(role=nil)
|
135
|
+
if role.nil?
|
136
|
+
Link.find(:to_wid => self.wid)
|
137
|
+
else
|
138
|
+
Link.find(:to_wid => self.wid, :role => role.to_s)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns all the fields name for the workitem
|
143
|
+
def field_names
|
144
|
+
JSON.parse(self.fields).keys.sort
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns the total sum, for a given +field+, from descendant and workitem itself
|
148
|
+
# Note: descendants = children with parent role
|
149
|
+
def total_on(field)
|
150
|
+
# return a past computed value if present
|
151
|
+
return self["_total_on_#{field}"] unless self["_total_on_#{field}"].nil?
|
152
|
+
|
153
|
+
# computing the total
|
154
|
+
total = self[field].nil? ? 0 : self[field]
|
155
|
+
children.each{|c| total += c.total_on(field) }
|
156
|
+
|
157
|
+
# saving (momoizing) for future invocations
|
158
|
+
self["_total_on_#{field}"] = total.to_f
|
159
|
+
self.save
|
160
|
+
|
161
|
+
total.to_f
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
|
168
|
+
# Returns workitem effective children (linked in with a parent role)
|
169
|
+
def children
|
170
|
+
tmp = [].to_set
|
171
|
+
project.parent_roles.each do |role|
|
172
|
+
tmp.merge(links_in(role).map{|lnk| lnk.from}) unless links_in(role).empty?
|
173
|
+
end
|
174
|
+
tmp.to_a
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Place
|
2
|
+
|
3
|
+
# Each WorkRecord ties a User to a WorkItem, with a +time_spent+, +date+ plus a +type+ and a +comment+
|
4
|
+
class WorkRecord < Ohm::Model
|
5
|
+
attribute :url
|
6
|
+
index :url
|
7
|
+
|
8
|
+
attribute :time_spent
|
9
|
+
attribute :date
|
10
|
+
attribute :type
|
11
|
+
attribute :comment
|
12
|
+
|
13
|
+
reference :user, User
|
14
|
+
reference :workitem, WorkItem
|
15
|
+
|
16
|
+
class << self; attr_accessor :rules end
|
17
|
+
@rules = {
|
18
|
+
'time_spent' => '//work-record/field[@id="timeSpent"]',
|
19
|
+
'date' => '//work-record/field[@id="date"]',
|
20
|
+
'type' => '//work-record/field[@id="type"]',
|
21
|
+
'comment' => '//work-record/field[@id="comment"]',
|
22
|
+
'user' => '//work-record/field[@id="user"]'
|
23
|
+
}
|
24
|
+
|
25
|
+
# Retrieve a specific workrecord data (time_spent, date, user, workitem) + (type, comment)
|
26
|
+
def retrieve
|
27
|
+
content = IO.readlines(url).join('')
|
28
|
+
doc = Nokogiri::XML(content)
|
29
|
+
self.class.rules.each_pair do |k,v|
|
30
|
+
tmp = doc.xpath(v)
|
31
|
+
|
32
|
+
case k
|
33
|
+
when 'time_spent'
|
34
|
+
self.send("#{k}=", to_hours(tmp[0].content))
|
35
|
+
when 'user'
|
36
|
+
self.send("#{k}=", User.find_by_name(tmp[0].content))
|
37
|
+
else
|
38
|
+
self.send("#{k}=", tmp[0].content) unless tmp[0].nil?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
self.workitem = WorkItem.find_by_wid(File.dirname(self.url).split(/\//).last)
|
43
|
+
|
44
|
+
Place.logger.info("saved workrecord #{self.url}")
|
45
|
+
|
46
|
+
self.save
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
data/lib/place.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'ohm'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'json'
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
|
9
|
+
require File.join(File.dirname(__FILE__), 'place', 'project')
|
10
|
+
require File.join(File.dirname(__FILE__), 'place', 'time_point')
|
11
|
+
require File.join(File.dirname(__FILE__), 'place', 'user')
|
12
|
+
require File.join(File.dirname(__FILE__), 'place', 'work_item')
|
13
|
+
require File.join(File.dirname(__FILE__), 'place', 'work_record')
|
14
|
+
require File.join(File.dirname(__FILE__), 'place', 'comment')
|
15
|
+
require File.join(File.dirname(__FILE__), 'place', 'link')
|
16
|
+
require File.join(File.dirname(__FILE__), 'place', 'participation')
|
17
|
+
|
18
|
+
|
19
|
+
module Place
|
20
|
+
VERSION = '0.1.0'
|
21
|
+
|
22
|
+
@conf = {}
|
23
|
+
|
24
|
+
def self.setup(repository_path)
|
25
|
+
@conf['base'] = repository_path
|
26
|
+
Ohm.connect
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.conf
|
30
|
+
@conf
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.logger
|
34
|
+
@log
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.logger_setup(filename=nil)
|
38
|
+
unless filename.nil?
|
39
|
+
@log = Logger.new(filename)
|
40
|
+
else
|
41
|
+
@log = Logger.new(STDERR)
|
42
|
+
end
|
43
|
+
@log.level = Logger::INFO
|
44
|
+
end
|
45
|
+
|
46
|
+
# Collect and retrieve all repo information, for each contained project
|
47
|
+
# If a project url is specified, it retrieves only info on this project
|
48
|
+
# BEWARE: each gather flush the whole database!
|
49
|
+
def gather!(project_url=nil)
|
50
|
+
start_time = Time.now.to_i
|
51
|
+
|
52
|
+
path = @conf['base'] # without ending '.polarion'
|
53
|
+
Ohm.flush
|
54
|
+
|
55
|
+
Project.collect_all(path)
|
56
|
+
User.collect_all(path)
|
57
|
+
|
58
|
+
unless project_url.nil?
|
59
|
+
prj = Project.find_by_url(project_url)
|
60
|
+
prj.retrieve
|
61
|
+
else
|
62
|
+
Project.all.each{|prj| prj.retrieve}
|
63
|
+
end
|
64
|
+
|
65
|
+
Ohm.redis.set 'updated_duration', Time.now.to_i - start_time
|
66
|
+
end
|
67
|
+
|
68
|
+
# Write last update timespent for the whole database
|
69
|
+
def updated!
|
70
|
+
Ohm.redis.set 'updated', Time.now.strftime("%d.%m.%Y %H:%M:%S")
|
71
|
+
end
|
72
|
+
|
73
|
+
def updated_at
|
74
|
+
Ohm.redis.get 'updated'
|
75
|
+
end
|
76
|
+
|
77
|
+
def updated?
|
78
|
+
not updated_at.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
def updated_duration
|
82
|
+
Ohm.redis.get 'updated_duration'
|
83
|
+
end
|
84
|
+
|
85
|
+
def reset!
|
86
|
+
Ohm.flush
|
87
|
+
end
|
88
|
+
|
89
|
+
# from duration to number of hours (1d == 8h)
|
90
|
+
def to_hours(duration)
|
91
|
+
return nil if duration.nil?
|
92
|
+
# TODO with a case statement or another regexp?
|
93
|
+
if duration =~ /(\d+)d\s(\d+)h/
|
94
|
+
days, hours = $1.to_f, $2.to_f
|
95
|
+
elsif duration =~ /(\d+)\/(\d+)d/
|
96
|
+
days = $1.to_f / $2.to_f
|
97
|
+
hours = 0
|
98
|
+
elsif duration =~ /(\d+)\/(\d+)h/
|
99
|
+
days = 0
|
100
|
+
hours = $1.to_f / $2.to_f
|
101
|
+
elsif duration =~ /(\d+)d/
|
102
|
+
days, hours = $1.to_f, 0
|
103
|
+
elsif duration =~ /(\d+)h/
|
104
|
+
days, hours = 0, $1.to_f
|
105
|
+
else
|
106
|
+
days, hours = 0, 0
|
107
|
+
end
|
108
|
+
|
109
|
+
(8*days + hours)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
data/place.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = "place"
|
4
|
+
s.version = "0.1.0"
|
5
|
+
s.summary = "Polarion LACE: Polarion items access in Ruby"
|
6
|
+
s.description = <<-EOF
|
7
|
+
Extract information from Polarion and turns it into easy manageable ruby objects.
|
8
|
+
|
9
|
+
Those objects are stored via Redis.
|
10
|
+
EOF
|
11
|
+
s.authors = ["Carlo Pecchia"]
|
12
|
+
s.email = ["info@carlopecchia.eu"]
|
13
|
+
s.homepage = "http://github.com/carlopecchia/place"
|
14
|
+
s.add_dependency('json')
|
15
|
+
s.add_dependency('ohm')
|
16
|
+
s.add_dependency('nokogiri')
|
17
|
+
s.files = ["Changelog", "LICENSE", "README.markdown", "Technical.markdown", "Rakefile", "lib/place.rb", "lib/place/project.rb", "lib/place/link.rb", "lib/place/participation.rb", "lib/place/user.rb", "lib/place/time_point.rb", "lib/place/work_item.rb", "lib/place/work_record.rb", "lib/place/comment.rb", "place.gemspec", "test/test_project.rb", "test/helper.rb", "test/test_workitem.rb", "test/test_time_point.rb", "test/test_place.rb", "test/test_comment.rb", "test/test_user.rb", "examples/sample-1.rb"]
|
18
|
+
end
|
19
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
$: << File.join(File.dirname(__FILE__), '.')
|
3
|
+
require 'helper.rb'
|
4
|
+
|
5
|
+
class CommentTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Place.setup(File.expand_path(File.join(File.dirname(__FILE__), 'repo')))
|
9
|
+
Place.gather!
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
Ohm.flush
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_environment
|
17
|
+
Comment.all.each do |c|
|
18
|
+
assert_not_nil c.author
|
19
|
+
assert_not_nil c.workitem
|
20
|
+
assert_not_nil c.text
|
21
|
+
assert_not_nil c.created
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_find_by_cid
|
26
|
+
assert_not_nil Comment.find_by_cid('P-6#1')
|
27
|
+
assert_nil Comment.find_by_cid('P-6#z00')
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_parent
|
31
|
+
c = Comment.find_by_cid('P-6#2')
|
32
|
+
assert_not_nil c.parent
|
33
|
+
assert_equal Comment.find_by_cid('P-6#1'), c.parent
|
34
|
+
end
|
35
|
+
end
|
data/test/test_place.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
$: << File.join(File.dirname(__FILE__), '.')
|
3
|
+
require 'helper.rb'
|
4
|
+
|
5
|
+
class PlaceTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def teardown
|
8
|
+
Ohm.flush
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_gather
|
12
|
+
base = File.expand_path(File.join(File.dirname(__FILE__), 'repo'))
|
13
|
+
Place.setup(base)
|
14
|
+
Place.gather!
|
15
|
+
|
16
|
+
assert_equal 2, Project.all.size
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_duration
|
20
|
+
assert_equal 11, to_hours('1d 3h')
|
21
|
+
assert_equal 16, to_hours('2d')
|
22
|
+
assert_equal 3, to_hours('3h')
|
23
|
+
assert_equal 0.5, to_hours('1/2h')
|
24
|
+
assert_equal 4, to_hours('1/2d')
|
25
|
+
assert_equal 0, to_hours('')
|
26
|
+
assert_equal nil, to_hours(nil)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
|
2
|
+
$: << File.join(File.dirname(__FILE__), '.')
|
3
|
+
require 'helper.rb'
|
4
|
+
|
5
|
+
class ProjectTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@base = File.expand_path(File.join(File.dirname(__FILE__), 'repo'))
|
9
|
+
Place.setup(@base)
|
10
|
+
Place.gather!
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
Ohm.flush
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_collecting
|
18
|
+
assert_not_nil @base
|
19
|
+
assert_equal 2, Project.all.size
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_find_by_name
|
23
|
+
p = Project.find_by_name('P')
|
24
|
+
assert_equal 'P', p.name
|
25
|
+
assert_equal 'P', p.prefix
|
26
|
+
assert_not_nil p.description
|
27
|
+
|
28
|
+
p = Project.find_by_name 'NONE'
|
29
|
+
assert_nil p
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_find_by_url
|
33
|
+
p = Project.find_by_url(@base + '/P/.polarion')
|
34
|
+
assert_not_nil p
|
35
|
+
|
36
|
+
b = Project.find_by_url(@base + '/A/B/.polarion')
|
37
|
+
assert_not_nil b
|
38
|
+
|
39
|
+
n = Project.find_by_url(@base + '/none/.polarion')
|
40
|
+
assert_nil n
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_find_by_prefix
|
44
|
+
p = Project.find_by_prefix('P')
|
45
|
+
assert_not_nil p
|
46
|
+
|
47
|
+
p = Project.find_by_prefix('NONE')
|
48
|
+
assert_nil p
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_workitems
|
52
|
+
p = Project.find_by_name('P')
|
53
|
+
assert_not_nil p
|
54
|
+
|
55
|
+
assert p.workitems.all.size > 0
|
56
|
+
|
57
|
+
wi = p.workitems.all.first
|
58
|
+
assert_not_nil wi
|
59
|
+
assert_equal p, wi.project
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_roles
|
63
|
+
p = Project.find_by_name('P')
|
64
|
+
assert_not_nil p
|
65
|
+
|
66
|
+
assert p.roles.size > 0
|
67
|
+
assert p.roles.include?('project_admin')
|
68
|
+
assert !p.roles.include?('foo servant role')
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_users
|
72
|
+
p = Project.find_by_name('P')
|
73
|
+
assert_not_nil p
|
74
|
+
|
75
|
+
assert_equal 2, p.users.size
|
76
|
+
assert_equal 1, p.users('project_admin').size
|
77
|
+
|
78
|
+
u = User.find_by_name 'alice'
|
79
|
+
assert_not_nil u
|
80
|
+
assert_equal u, p.users('project_admin').first
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_parent_roles
|
84
|
+
p = Project.find_by_name('P')
|
85
|
+
assert_not_nil p
|
86
|
+
|
87
|
+
assert ! p.parent_roles.empty?
|
88
|
+
assert p.parent_roles.include?('parent')
|
89
|
+
assert p.parent_roles.include?('refines')
|
90
|
+
assert ! p.parent_roles.include?('depends')
|
91
|
+
|
92
|
+
# A/B doesn't have a local file for workitem-link-roles
|
93
|
+
b = Project.find_by_url(@base + '/A/B/.polarion')
|
94
|
+
assert_not_nil b
|
95
|
+
assert ! b.parent_roles.empty?
|
96
|
+
assert b.parent_roles.include?('parent')
|
97
|
+
assert_equal 1, b.parent_roles.size
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|