git-ds 0.9.2
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/README.rdoc +795 -0
- data/doc/Examples.rdoc +36 -0
- data/doc/examples/key_value/kv_get.rb +29 -0
- data/doc/examples/key_value/kv_init.rb +20 -0
- data/doc/examples/key_value/kv_list.rb +28 -0
- data/doc/examples/key_value/kv_remove.rb +29 -0
- data/doc/examples/key_value/kv_set.rb +39 -0
- data/doc/examples/key_value/model.rb +156 -0
- data/doc/examples/key_value/test.rb +50 -0
- data/doc/examples/test_suite/model.rb +503 -0
- data/doc/examples/test_suite/test.rb +173 -0
- data/doc/examples/test_suite/ts_add_bug.rb +65 -0
- data/doc/examples/test_suite/ts_add_module.rb +74 -0
- data/doc/examples/test_suite/ts_add_module_to_test.rb +78 -0
- data/doc/examples/test_suite/ts_add_test.rb +77 -0
- data/doc/examples/test_suite/ts_add_test_suite.rb +65 -0
- data/doc/examples/test_suite/ts_add_test_to_bug.rb +76 -0
- data/doc/examples/test_suite/ts_init.rb +20 -0
- data/doc/examples/test_suite/ts_list.rb +118 -0
- data/doc/examples/test_suite/ts_perform_test.rb +104 -0
- data/doc/examples/test_suite/ts_update_bugs.rb +58 -0
- data/doc/examples/user_group/model.rb +265 -0
- data/doc/examples/user_group/test.rb +64 -0
- data/doc/examples/user_group/ug_add_group.rb +39 -0
- data/doc/examples/user_group/ug_add_group_user.rb +36 -0
- data/doc/examples/user_group/ug_add_user.rb +39 -0
- data/doc/examples/user_group/ug_init.rb +20 -0
- data/doc/examples/user_group/ug_list.rb +32 -0
- data/lib/git-ds.rb +14 -0
- data/lib/git-ds/config.rb +53 -0
- data/lib/git-ds/database.rb +289 -0
- data/lib/git-ds/exec_cmd.rb +107 -0
- data/lib/git-ds/index.rb +205 -0
- data/lib/git-ds/model.rb +136 -0
- data/lib/git-ds/model/db_item.rb +42 -0
- data/lib/git-ds/model/fs_item.rb +51 -0
- data/lib/git-ds/model/item.rb +428 -0
- data/lib/git-ds/model/item_list.rb +97 -0
- data/lib/git-ds/model/item_proxy.rb +128 -0
- data/lib/git-ds/model/property.rb +144 -0
- data/lib/git-ds/model/root.rb +46 -0
- data/lib/git-ds/repo.rb +455 -0
- data/lib/git-ds/shared.rb +17 -0
- data/lib/git-ds/transaction.rb +77 -0
- data/tests/ut_database.rb +304 -0
- data/tests/ut_git_grit_equiv.rb +195 -0
- data/tests/ut_index.rb +203 -0
- data/tests/ut_model.rb +360 -0
- data/tests/ut_repo.rb +260 -0
- data/tests/ut_user_group_model.rb +316 -0
- metadata +142 -0
data/doc/Examples.rdoc
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
=Key-Value datastore
|
2
|
+
|
3
|
+
{doc/examples/key_value/model.rb}[link:doc/examples/key_value/model_rb.html]
|
4
|
+
|
5
|
+
KeyValueModel
|
6
|
+
|
7
|
+
* KeyValueModelItem
|
8
|
+
|
9
|
+
==Example
|
10
|
+
:include: doc/examples/key_value/test.rb
|
11
|
+
|
12
|
+
=Test Suite backend
|
13
|
+
|
14
|
+
{doc/examples/test_suite/model.rb}[link:doc/examples/test_suite/model_rb.html]
|
15
|
+
|
16
|
+
TestSuiteModel
|
17
|
+
|
18
|
+
* ModuleModelItem
|
19
|
+
* TestSuiteModelItem
|
20
|
+
* TestModelItem
|
21
|
+
* BugModelItem
|
22
|
+
|
23
|
+
==Example
|
24
|
+
:include: doc/examples/test_suite/test.rb
|
25
|
+
|
26
|
+
=User/Group database
|
27
|
+
|
28
|
+
{doc/examples/user_group/model.rb}[link:doc/examples/user_group/model_rb.html]
|
29
|
+
|
30
|
+
UserGroupModel
|
31
|
+
|
32
|
+
* UserModelItem
|
33
|
+
* GroupModelItem
|
34
|
+
|
35
|
+
==Example
|
36
|
+
:include: doc/examples/test_suite/test.rb
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Get a key:value pair from a database repo
|
3
|
+
# Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
|
4
|
+
|
5
|
+
# Add examples dir and lib/git-ds to ruby path
|
6
|
+
BASE=File.dirname(File.expand_path(__FILE__)\
|
7
|
+
).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
|
8
|
+
$: << BASE + File::SEPARATOR + 'lib'
|
9
|
+
$: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
|
10
|
+
|
11
|
+
require 'key_value/model'
|
12
|
+
|
13
|
+
if __FILE__ == $0
|
14
|
+
if ARGV.count < 1 || ARGV.count > 2
|
15
|
+
puts "Usage : #{$0} [FILENAME] KEY"
|
16
|
+
puts "Repo dir is assumed to be . if FILENAME is not specified."
|
17
|
+
exit -1
|
18
|
+
end
|
19
|
+
|
20
|
+
path = (ARGV.count == 2) ? ARGV.shift : GitDS::Database.top_level
|
21
|
+
key = ARGV.shift
|
22
|
+
|
23
|
+
model = KeyValueModel.new(GitDS::Database.connect(path, false))
|
24
|
+
raise "Could not connect to Model!" if not model
|
25
|
+
|
26
|
+
puts model[key]
|
27
|
+
|
28
|
+
exit 0
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Initialize a key/value database repo
|
3
|
+
# Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
|
4
|
+
|
5
|
+
BASE=File.dirname(File.expand_path(__FILE__)\
|
6
|
+
).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
|
7
|
+
$: << BASE + File::SEPARATOR + 'lib'
|
8
|
+
$: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
|
9
|
+
|
10
|
+
require 'key_value/model'
|
11
|
+
|
12
|
+
if __FILE__ == $0
|
13
|
+
if ARGV.count != 1
|
14
|
+
puts "Usage : #{$0} FILENAME"
|
15
|
+
exit -1
|
16
|
+
end
|
17
|
+
|
18
|
+
KeyValueModel.new(GitDS::Database.connect(ARGV.shift, true))
|
19
|
+
exit 0
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# List all key:value pairs in a database repo
|
3
|
+
# Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
|
4
|
+
|
5
|
+
# Add examples dir and lib/git-ds to ruby path
|
6
|
+
BASE=File.dirname(File.expand_path(__FILE__)\
|
7
|
+
).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
|
8
|
+
$: << BASE + File::SEPARATOR + 'lib'
|
9
|
+
$: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
|
10
|
+
|
11
|
+
require 'key_value/model'
|
12
|
+
|
13
|
+
if __FILE__ == $0
|
14
|
+
if ARGV.count > 1
|
15
|
+
puts "Usage : #{$0} [FILENAME]"
|
16
|
+
puts "Repo dir is assumed to be . if FILENAME is not specified."
|
17
|
+
exit -1
|
18
|
+
end
|
19
|
+
|
20
|
+
path = (ARGV.count == 1) ? ARGV.shift : GitDS::Database.top_level
|
21
|
+
|
22
|
+
model = KeyValueModel.new(GitDS::Database.connect(path, false))
|
23
|
+
raise "Could not connect to Model!" if not model
|
24
|
+
|
25
|
+
model.each { |k, v| puts "#{k} : #{v}" }
|
26
|
+
|
27
|
+
exit 0
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Remove a key:value pair from a database repo
|
3
|
+
# Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
|
4
|
+
|
5
|
+
# Add examples dir and lib/git-ds to ruby path
|
6
|
+
BASE=File.dirname(File.expand_path(__FILE__)\
|
7
|
+
).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
|
8
|
+
$: << BASE + File::SEPARATOR + 'lib'
|
9
|
+
$: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
|
10
|
+
|
11
|
+
require 'key_value/model'
|
12
|
+
|
13
|
+
if __FILE__ == $0
|
14
|
+
if ARGV.count < 1 || ARGV.count > 2
|
15
|
+
puts "Usage : #{$0} [FILENAME] KEY"
|
16
|
+
puts "Repo dir is assumed to be . if FILENAME is not specified."
|
17
|
+
exit -1
|
18
|
+
end
|
19
|
+
|
20
|
+
path = (ARGV.count == 2) ? ARGV.shift : GitDS::Database.top_level
|
21
|
+
key = ARGV.shift
|
22
|
+
|
23
|
+
model = KeyValueModel.new(GitDS::Database.connect(path, false))
|
24
|
+
raise "Could not connect to Model!" if not model
|
25
|
+
|
26
|
+
model.remove key
|
27
|
+
|
28
|
+
exit 0
|
29
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Set a key:value pair in a database repo
|
3
|
+
# Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
|
4
|
+
|
5
|
+
# Add examples dir and lib/git-ds to ruby path
|
6
|
+
BASE=File.dirname(File.expand_path(__FILE__)\
|
7
|
+
).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
|
8
|
+
$: << BASE + File::SEPARATOR + 'lib'
|
9
|
+
$: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
|
10
|
+
|
11
|
+
require 'key_value/model'
|
12
|
+
|
13
|
+
if __FILE__ == $0
|
14
|
+
if ARGV.count < 2 || ARGV.count > 3
|
15
|
+
puts "Usage : #{$0} [FILENAME] KEY VALUE"
|
16
|
+
puts "Repo dir is assumed to be . if FILENAME is not specified."
|
17
|
+
puts "A new GitDS database will be created if FILENAME does not exist."
|
18
|
+
exit -1
|
19
|
+
end
|
20
|
+
|
21
|
+
path = ''
|
22
|
+
autocreate = false
|
23
|
+
if ARGV.count == 3
|
24
|
+
path = ARGV.shift
|
25
|
+
autocreate = true
|
26
|
+
else
|
27
|
+
path = GitDS::Database.top_level
|
28
|
+
end
|
29
|
+
key = ARGV.shift
|
30
|
+
val = ARGV.shift
|
31
|
+
|
32
|
+
model = KeyValueModel.new(GitDS::Database.connect(path, autocreate))
|
33
|
+
raise "Could not connect to Model!" if not model
|
34
|
+
|
35
|
+
# Note: this will automatically be committed:
|
36
|
+
model[key] = val
|
37
|
+
|
38
|
+
exit 0
|
39
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# :title: GitDS Model Example: Key/Value
|
3
|
+
=begin rdoc
|
4
|
+
<i>Copyright 2011 Thoughtgang <http://www.thoughtgang.org></i>
|
5
|
+
|
6
|
+
This example demonstrates a GitDS database that acts as a simple Key:Value
|
7
|
+
datastore.
|
8
|
+
|
9
|
+
==Usage
|
10
|
+
|
11
|
+
An example of the usage of this model can be found in the following script:
|
12
|
+
|
13
|
+
doc/examples/key_value/test.rb
|
14
|
+
|
15
|
+
This script can be run to generate an example Git-DS repository:
|
16
|
+
|
17
|
+
bash$ doc/examples/key_value/test.rb
|
18
|
+
bash$ cd kv_test.db && qgit &
|
19
|
+
|
20
|
+
The following command-line utilities are provided for manipulating this
|
21
|
+
data model:
|
22
|
+
|
23
|
+
doc/examples/key_value/kv_get.rb
|
24
|
+
doc/examples/key_value/kv_init.rb
|
25
|
+
doc/examples/key_value/kv_list.rb
|
26
|
+
doc/examples/key_value/kv_remove.rb
|
27
|
+
doc/examples/key_value/kv_set.rb
|
28
|
+
|
29
|
+
===Initialize a Key:Value datastore
|
30
|
+
|
31
|
+
model = KeyValueModel.new(GitDS::Database.connect('kv_test.db', true))
|
32
|
+
|
33
|
+
===Set a key:value pair
|
34
|
+
|
35
|
+
model[key] = value
|
36
|
+
|
37
|
+
===Get a key:value pair
|
38
|
+
|
39
|
+
model[key]
|
40
|
+
|
41
|
+
===Remove a key:value pair
|
42
|
+
|
43
|
+
model.remove(key)
|
44
|
+
|
45
|
+
===List all key:value pairs
|
46
|
+
|
47
|
+
model.each { |key, value| ... }
|
48
|
+
|
49
|
+
=end
|
50
|
+
|
51
|
+
require 'git-ds/database'
|
52
|
+
require 'git-ds/model'
|
53
|
+
|
54
|
+
# ============================================================================
|
55
|
+
|
56
|
+
=begin rdoc
|
57
|
+
A data model representing a basic Key/Value store.
|
58
|
+
|
59
|
+
This has the following structure on disk:
|
60
|
+
key-value/ : ModelItem class for Key/Value pairs
|
61
|
+
key-value/$KEY/value : Property file containing value of key
|
62
|
+
=end
|
63
|
+
|
64
|
+
class KeyValueModel < GitDS::Model
|
65
|
+
def initialize(db)
|
66
|
+
super db, 'key/value model'
|
67
|
+
end
|
68
|
+
|
69
|
+
=begin rdoc
|
70
|
+
Return KeyValudeModelItem for key.
|
71
|
+
=end
|
72
|
+
def pair(key)
|
73
|
+
path = KeyValueModelItem.instance_path(self.root.path, key)
|
74
|
+
KeyValueModelItem.new(self, path)
|
75
|
+
end
|
76
|
+
|
77
|
+
=begin rdoc
|
78
|
+
Return true if key exists in Model.
|
79
|
+
=end
|
80
|
+
def include?(key)
|
81
|
+
super KeyValueModelItem.instance_path(self.root.path, key)
|
82
|
+
end
|
83
|
+
|
84
|
+
alias :exist? :include?
|
85
|
+
|
86
|
+
=begin rdoc
|
87
|
+
Return value for key if it exists in model, nil otherwise.
|
88
|
+
=end
|
89
|
+
def [](key)
|
90
|
+
return nil if not exist? key
|
91
|
+
p = pair(key)
|
92
|
+
p ? p.value : nil
|
93
|
+
end
|
94
|
+
|
95
|
+
=begin rdoc
|
96
|
+
Set value for key to 'val'. The key/value pair is created if it does not
|
97
|
+
already exist.
|
98
|
+
=end
|
99
|
+
def []=(key, val)
|
100
|
+
if self.exist? key
|
101
|
+
p = pair(key)
|
102
|
+
p.value = val if p
|
103
|
+
else
|
104
|
+
KeyValueModelItem.create self.root, {:key => key, :value => val}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
=begin rdoc
|
109
|
+
Yield each key, value pair in database.
|
110
|
+
=end
|
111
|
+
def each
|
112
|
+
KeyValueModelItem.list(self.root).each do |k|
|
113
|
+
yield [k, self[k]]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
=begin rdoc
|
118
|
+
Remove a key:value pair from the database.
|
119
|
+
=end
|
120
|
+
def remove(key)
|
121
|
+
pair(key).delete
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
=begin rdoc
|
126
|
+
A ModelItem class for Key/Value pairs. This assumes that value is a String.
|
127
|
+
To support other datatypes, subclass and override the value() accessor.
|
128
|
+
=end
|
129
|
+
class KeyValueModelItem < GitDS::ModelItem
|
130
|
+
name 'key-value'
|
131
|
+
|
132
|
+
property(:value, '')
|
133
|
+
|
134
|
+
=begin rdoc
|
135
|
+
Use :key as the ident field of the create() Hash.
|
136
|
+
=end
|
137
|
+
def self.ident_key
|
138
|
+
:key
|
139
|
+
end
|
140
|
+
|
141
|
+
alias :key :ident
|
142
|
+
|
143
|
+
=begin rdoc
|
144
|
+
Return the value of the key:value pair.
|
145
|
+
=end
|
146
|
+
def value
|
147
|
+
property(:value)
|
148
|
+
end
|
149
|
+
|
150
|
+
=begin rdoc
|
151
|
+
Set the value of the key:value pair.
|
152
|
+
=end
|
153
|
+
def value=(val)
|
154
|
+
set_property(:value, val)
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Test Key/Value database example
|
3
|
+
# Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
|
4
|
+
|
5
|
+
BASE=File.dirname(File.expand_path(__FILE__)\
|
6
|
+
).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
|
7
|
+
$: << BASE + File::SEPARATOR + 'lib'
|
8
|
+
$: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
|
9
|
+
|
10
|
+
require 'key_value/model'
|
11
|
+
|
12
|
+
# ----------------------------------------------------------------------
|
13
|
+
|
14
|
+
def fill_model(model)
|
15
|
+
model.exec do
|
16
|
+
{
|
17
|
+
:a => 1,
|
18
|
+
:b => 2,
|
19
|
+
:c => 3
|
20
|
+
}.each { |k,v| model[k] = v }
|
21
|
+
end
|
22
|
+
|
23
|
+
model.db.set_author('a user', 'au@users.net')
|
24
|
+
|
25
|
+
model.exec do
|
26
|
+
{
|
27
|
+
:a => 999,
|
28
|
+
:b => 998,
|
29
|
+
:c => 997,
|
30
|
+
:d => 996,
|
31
|
+
:e => 995
|
32
|
+
}.each { |k,v| model[k] = v }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# ----------------------------------------------------------------------
|
37
|
+
def list_model(model)
|
38
|
+
model.each { |k, v| puts "#{k} : #{v}" }
|
39
|
+
end
|
40
|
+
|
41
|
+
# ----------------------------------------------------------------------
|
42
|
+
if __FILE__ == $0
|
43
|
+
path = (ARGV.count > 0) ? ARGV.shift : 'kv_test.db'
|
44
|
+
|
45
|
+
db = GitDS::Database.connect(path, true)
|
46
|
+
model = KeyValueModel.new(db) if db
|
47
|
+
fill_model(model) if model
|
48
|
+
list_model(model) if model
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,503 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# :title: GitDS Model Example: Test Suite
|
3
|
+
# :doc:
|
4
|
+
=begin rdoc
|
5
|
+
<i>Copyright 2011 Thoughtgang <http://www.thoughtgang.org></i>
|
6
|
+
|
7
|
+
This example is suitable for demonstrating branches, commits, tags, and
|
8
|
+
actions by multiple users.
|
9
|
+
|
10
|
+
The TestSuite model consists of Modules (source code files), Test Suites
|
11
|
+
(collections of tests), Tests (specific test instances), and Bugs (bug
|
12
|
+
reports). Tests can be associated with modules (which they verify), and Bugs
|
13
|
+
can be associated with Tests (which cause them to be manifest). Tests have
|
14
|
+
a pass/fail state which is updated over time as they are performed, and Bugs
|
15
|
+
have an open/closed state which is updated over time as the Tests which
|
16
|
+
detect them pass or fail.
|
17
|
+
|
18
|
+
Note: This is not a serious proposal for a bug-tracking data model. It is
|
19
|
+
intended only to serve as an example of a data model with frequent changes by
|
20
|
+
multiple users.
|
21
|
+
|
22
|
+
==Usage
|
23
|
+
|
24
|
+
An example of the usage of this model can be found in the following script:
|
25
|
+
|
26
|
+
doc/examples/test_suite/test.rb
|
27
|
+
|
28
|
+
This script can be run to generate an example Git-DS repository:
|
29
|
+
|
30
|
+
bash$ doc/examples/test_suite/test.rb
|
31
|
+
bash$ cd ts_test.db && qgit &
|
32
|
+
|
33
|
+
The following command-line utilities are provided for manipulating this
|
34
|
+
data model:
|
35
|
+
|
36
|
+
doc/examples/test_suite/ts_add_bug.rb
|
37
|
+
doc/examples/test_suite/ts_add_module.rb
|
38
|
+
doc/examples/test_suite/ts_add_module_to_test.rb
|
39
|
+
doc/examples/test_suite/ts_add_test.rb
|
40
|
+
doc/examples/test_suite/ts_add_test_suite.rb
|
41
|
+
doc/examples/test_suite/ts_add_test_to_bug.rb
|
42
|
+
doc/examples/test_suite/ts_init.rb
|
43
|
+
doc/examples/test_suite/ts_list.rb
|
44
|
+
doc/examples/test_suite/ts_perform_test.rb
|
45
|
+
doc/examples/test_suite/ts_update_bugs.rb
|
46
|
+
|
47
|
+
===Initialize a TestSuite database
|
48
|
+
|
49
|
+
# connect the model, creating it if necessary
|
50
|
+
model = TestSuiteModel.new(GitDS::Database.connect('ts_test.db', true))
|
51
|
+
|
52
|
+
# connect as a specific user (Git author)
|
53
|
+
model = TestSuiteModel.new(GitDS::Database.connect_as('ts_test.db'
|
54
|
+
username, email))
|
55
|
+
|
56
|
+
===Add a Source Module
|
57
|
+
|
58
|
+
m = model.add_module(path, data)
|
59
|
+
|
60
|
+
===Add a Test Suite
|
61
|
+
|
62
|
+
s = model.add_test_suite(name, description)
|
63
|
+
|
64
|
+
===Add Tests to a Test Suite
|
65
|
+
|
66
|
+
t = s.add_test(name)
|
67
|
+
|
68
|
+
# Add a test with a list of modules
|
69
|
+
modules [ 'path.to.module.1', 'path.to.module.2' ]
|
70
|
+
t = suite.add_test(name, modules)
|
71
|
+
|
72
|
+
# Add a specific Module to a Test
|
73
|
+
m = model.module('path.to.module.3'
|
74
|
+
t.add_module(m)
|
75
|
+
|
76
|
+
===Add a Bug Report
|
77
|
+
|
78
|
+
b = model.add_bug(name, description)
|
79
|
+
|
80
|
+
# Add a specific test to a Bug
|
81
|
+
s = model.suite('UnitTests')
|
82
|
+
t = s.test('test_foo')
|
83
|
+
b.add_test(t)
|
84
|
+
|
85
|
+
===Updating Tests and Bugs
|
86
|
+
|
87
|
+
# Pass a block to perform_tests to update each test
|
88
|
+
model.perform_tests do |t|
|
89
|
+
|
90
|
+
# Generate the new pass/fail state and log for the test.
|
91
|
+
# In reality, this might invoke and monitor a test method or program.
|
92
|
+
passed = false
|
93
|
+
log = "RuntimeError in..."
|
94
|
+
|
95
|
+
# Write the new pass/fail state and log to the test
|
96
|
+
t.perform( passed, log )
|
97
|
+
end
|
98
|
+
|
99
|
+
# Update all Bugs to be open or closed depending on the state of their Tests
|
100
|
+
model.update_bugs
|
101
|
+
|
102
|
+
=end
|
103
|
+
|
104
|
+
require 'git-ds/database'
|
105
|
+
require 'git-ds/model'
|
106
|
+
|
107
|
+
# =============================================================================
|
108
|
+
|
109
|
+
=begin rdoc
|
110
|
+
The model has the following structure in the repo:
|
111
|
+
|
112
|
+
module/ : ModelItem class
|
113
|
+
module/$NAME : ModelItem class instance
|
114
|
+
module/$NAME/data : Property (str)
|
115
|
+
module/$NAME/path : Property (str)
|
116
|
+
bug/ : ModelItem class
|
117
|
+
bug/$ID : ModelItem class instance
|
118
|
+
bug/$ID/test : ProxyItemList
|
119
|
+
bug/$ID/description : Property (str)
|
120
|
+
bug/$ID/open : Property (bool)
|
121
|
+
test_suite/ : ModelItem class
|
122
|
+
test_suite/$ID : ModelItem class instance
|
123
|
+
test_suite/description : Property (str)
|
124
|
+
test_suite/$ID/test : ModelItem class
|
125
|
+
test_suite/$ID/test/$ID : ModelItem class instance
|
126
|
+
test_suite/$ID/test/$ID/module : ProxyItemList
|
127
|
+
test_suite/$ID/test/$ID/pass : Property (bool)
|
128
|
+
test_suite/$ID/test/$ID/log : Property (str)
|
129
|
+
test_suite/$ID/test/$ID/timestamp : Property (ts)
|
130
|
+
=end
|
131
|
+
|
132
|
+
class TestSuiteModel < GitDS::Model
|
133
|
+
def initialize(db)
|
134
|
+
super db, 'test-suite model'
|
135
|
+
end
|
136
|
+
|
137
|
+
=begin rdoc
|
138
|
+
Add a Module to the database.
|
139
|
+
=end
|
140
|
+
def add_module(path, data)
|
141
|
+
args = { :ident =>
|
142
|
+
path.split(File::SEPARATOR).reject{ |x| x.empty? }.join('.'),
|
143
|
+
:name => File.basename(path), :path => File.dirname(path),
|
144
|
+
:data => data }
|
145
|
+
ModuleModelItem.new self, ModuleModelItem.create(self.root, args)
|
146
|
+
end
|
147
|
+
|
148
|
+
=begin rdoc
|
149
|
+
List all Modules in the database.
|
150
|
+
=end
|
151
|
+
def modules
|
152
|
+
ModuleModelItem.list(self.root)
|
153
|
+
end
|
154
|
+
|
155
|
+
=begin rdoc
|
156
|
+
Instantiate a Module.
|
157
|
+
=end
|
158
|
+
def module(ident)
|
159
|
+
path = ModuleModelItem.instance_path(self.root.path, ident)
|
160
|
+
ModuleModelItem.new self, path
|
161
|
+
end
|
162
|
+
|
163
|
+
=begin rdoc
|
164
|
+
Add a Bug to the database.
|
165
|
+
=end
|
166
|
+
def add_bug(ident, description)
|
167
|
+
args = { :ident => ident, :description => description }
|
168
|
+
BugModelItem.new self, BugModelItem.create(self.root, args)
|
169
|
+
end
|
170
|
+
|
171
|
+
=begin rdoc
|
172
|
+
List the IDs of all Bug in the database.
|
173
|
+
=end
|
174
|
+
def bugs
|
175
|
+
BugModelItem.list(self.root)
|
176
|
+
end
|
177
|
+
|
178
|
+
=begin rdoc
|
179
|
+
Instantiate a Bug.
|
180
|
+
=end
|
181
|
+
def bug(ident)
|
182
|
+
BugModelItem.new self, BugModelItem.instance_path(self.root.path, ident)
|
183
|
+
end
|
184
|
+
|
185
|
+
=begin rdoc
|
186
|
+
Update the status of all Bugs.
|
187
|
+
=end
|
188
|
+
def update_bugs
|
189
|
+
model = self
|
190
|
+
exec {
|
191
|
+
model.bugs.each do |ident|
|
192
|
+
b = model.bug(ident)
|
193
|
+
b.update
|
194
|
+
end
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
=begin rdoc
|
199
|
+
Add a TestSuite to the database.
|
200
|
+
=end
|
201
|
+
def add_test_suite(ident, description)
|
202
|
+
args = { :ident => ident, :description => description }
|
203
|
+
TestSuiteModelItem.new self, TestSuiteModelItem.create(self.root, args)
|
204
|
+
end
|
205
|
+
|
206
|
+
=begin rdoc
|
207
|
+
List all TestSuitesin the database.
|
208
|
+
=end
|
209
|
+
def test_suites
|
210
|
+
TestSuiteModelItem.list(self.root)
|
211
|
+
end
|
212
|
+
|
213
|
+
=begin rdoc
|
214
|
+
Instantiate a TestSuite.
|
215
|
+
=end
|
216
|
+
def test_suite(ident)
|
217
|
+
path = TestSuiteModelItem.instance_path(self.root.path, ident)
|
218
|
+
TestSuiteModelItem.new self, path
|
219
|
+
end
|
220
|
+
|
221
|
+
=begin rdoc
|
222
|
+
Perform all tests in all TestSuites.
|
223
|
+
This yields each Test to the supplied block.
|
224
|
+
=end
|
225
|
+
def perform_tests(&block)
|
226
|
+
model = self
|
227
|
+
exec {
|
228
|
+
model.test_suites.each do |ident|
|
229
|
+
s = model.test_suite(ident)
|
230
|
+
s.perform_tests(&block)
|
231
|
+
end
|
232
|
+
}
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# ----------------------------------------------------------------------
|
237
|
+
=begin rdoc
|
238
|
+
A module for testing. Usually a source code file.
|
239
|
+
=end
|
240
|
+
class ModuleModelItem < GitDS::FsModelItem
|
241
|
+
name 'module'
|
242
|
+
|
243
|
+
property :name
|
244
|
+
property :path
|
245
|
+
property :data
|
246
|
+
|
247
|
+
=begin rdoc
|
248
|
+
Contents of the module. This will usually be source code.
|
249
|
+
=end
|
250
|
+
def data
|
251
|
+
property(:data)
|
252
|
+
end
|
253
|
+
|
254
|
+
def data=(val)
|
255
|
+
set_property(:data, val)
|
256
|
+
end
|
257
|
+
|
258
|
+
=begin rdoc
|
259
|
+
Name of the module in the filesystem.
|
260
|
+
=end
|
261
|
+
def name
|
262
|
+
property(:name)
|
263
|
+
end
|
264
|
+
|
265
|
+
=begin rdoc
|
266
|
+
Path of the module in the filesystem.
|
267
|
+
=end
|
268
|
+
def path
|
269
|
+
property(:path)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# ----------------------------------------------------------------------
|
274
|
+
=begin rdoc
|
275
|
+
A collection of tests.
|
276
|
+
=end
|
277
|
+
class TestSuiteModelItem < GitDS::ModelItem
|
278
|
+
name 'test_suite'
|
279
|
+
|
280
|
+
property :description
|
281
|
+
|
282
|
+
def initialize(model, path)
|
283
|
+
super
|
284
|
+
@tests = GitDS::ModelItemList.new(TestModelItem, model, path)
|
285
|
+
end
|
286
|
+
|
287
|
+
=begin rdoc
|
288
|
+
Description (e.g. purpose) of the tests.
|
289
|
+
=end
|
290
|
+
def description
|
291
|
+
property(:description)
|
292
|
+
end
|
293
|
+
|
294
|
+
def description=(val)
|
295
|
+
set_property(:description, val)
|
296
|
+
end
|
297
|
+
|
298
|
+
=begin rdoc
|
299
|
+
List all tests in suite.
|
300
|
+
=end
|
301
|
+
def tests
|
302
|
+
ensure_valid
|
303
|
+
@tests.keys
|
304
|
+
end
|
305
|
+
|
306
|
+
=begin rdoc
|
307
|
+
Instantiate Test object.
|
308
|
+
=end
|
309
|
+
def test(ident)
|
310
|
+
ensure_valid
|
311
|
+
@tests[ident]
|
312
|
+
end
|
313
|
+
|
314
|
+
=begin rdoc
|
315
|
+
Add a test to this suite.
|
316
|
+
=end
|
317
|
+
def add_test( ident, modules = [] )
|
318
|
+
ensure_valid
|
319
|
+
t = TestModelItem.new @model, @tests.add(self, { :ident => ident } )
|
320
|
+
modules.each { |m| t.add_module(m) }
|
321
|
+
end
|
322
|
+
|
323
|
+
=begin rdoc
|
324
|
+
Delete a test from this suite.
|
325
|
+
=end
|
326
|
+
def del_test(ident)
|
327
|
+
ensure_valid
|
328
|
+
@tests.delete(ident)
|
329
|
+
end
|
330
|
+
|
331
|
+
=begin rdoc
|
332
|
+
Perform all tests in this TestSuite.
|
333
|
+
This yields each Test to the supplied block. The code in the block is
|
334
|
+
expected to update the Test object Properties :pass and :log.
|
335
|
+
=end
|
336
|
+
def perform_tests(&block)
|
337
|
+
suite = self
|
338
|
+
@model.exec {
|
339
|
+
suite.tests.each do |ident|
|
340
|
+
t = suite.test(ident)
|
341
|
+
yield t
|
342
|
+
end
|
343
|
+
}
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
# ----------------------------------------------------------------------
|
348
|
+
=begin rdoc
|
349
|
+
A specific test.
|
350
|
+
This identifies a specific test which is associated with one or more Modules.
|
351
|
+
The testing software will invoke the perform method for each test it runs in
|
352
|
+
order to update the test results in the database.
|
353
|
+
=end
|
354
|
+
class TestModelItem < GitDS::ModelItem
|
355
|
+
name 'test'
|
356
|
+
|
357
|
+
property :pass, false
|
358
|
+
property :log, ''
|
359
|
+
property :timestamp
|
360
|
+
|
361
|
+
def self.fill(model, item_path, args)
|
362
|
+
super
|
363
|
+
# Note: by default, all tests are pass=false and timestamp=create_time
|
364
|
+
properties[:timestamp].set(model, item_path, Time.now.to_s)
|
365
|
+
end
|
366
|
+
|
367
|
+
def initialize(model, path)
|
368
|
+
super
|
369
|
+
@modules = GitDS::ProxyItemList.new(ModuleModelItem, model, path)
|
370
|
+
end
|
371
|
+
|
372
|
+
=begin rdoc
|
373
|
+
Store the results of performing a test.
|
374
|
+
=end
|
375
|
+
def perform(pass, log='', timestamp=Time.now)
|
376
|
+
set_property(:pass, pass)
|
377
|
+
set_property(:log, log)
|
378
|
+
set_property(:timestamp, timestamp)
|
379
|
+
end
|
380
|
+
|
381
|
+
=begin rdoc
|
382
|
+
The timestamp of the latest run of the test.
|
383
|
+
=end
|
384
|
+
def timestamp
|
385
|
+
ts_property(:timestamp)
|
386
|
+
end
|
387
|
+
|
388
|
+
=begin rdoc
|
389
|
+
The result of the latest run of the test.
|
390
|
+
=end
|
391
|
+
def pass?
|
392
|
+
bool_property(:pass)
|
393
|
+
end
|
394
|
+
|
395
|
+
=begin rdoc
|
396
|
+
The log from the latest run of the test.
|
397
|
+
=end
|
398
|
+
def log
|
399
|
+
property(:log)
|
400
|
+
end
|
401
|
+
|
402
|
+
=begin rdoc
|
403
|
+
List all modules associated with this test.
|
404
|
+
=end
|
405
|
+
def modules
|
406
|
+
ensure_valid
|
407
|
+
@modules.keys
|
408
|
+
end
|
409
|
+
|
410
|
+
=begin rdoc
|
411
|
+
Associate a module with this test.
|
412
|
+
=end
|
413
|
+
def add_module(m)
|
414
|
+
ensure_valid
|
415
|
+
@modules.add(self, m, true)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
# ----------------------------------------------------------------------
|
420
|
+
=begin rdoc
|
421
|
+
A bug report. This includes a description of the bug and an open/closed status.
|
422
|
+
A Bug is associated with one or more Tests that cause the Bug to occur.
|
423
|
+
Bugs should be closed when none of their tests fail; this can be handled
|
424
|
+
automatically by calling Bug#update after performing tests.
|
425
|
+
=end
|
426
|
+
class BugModelItem < GitDS::ModelItem
|
427
|
+
name 'bug'
|
428
|
+
|
429
|
+
property :description
|
430
|
+
property :open, true
|
431
|
+
|
432
|
+
def initialize(model, path)
|
433
|
+
super
|
434
|
+
@tests = GitDS::ProxyItemList.new(TestModelItem, model, path)
|
435
|
+
end
|
436
|
+
|
437
|
+
=begin rdoc
|
438
|
+
Description of the bug and its effects.
|
439
|
+
=end
|
440
|
+
def description
|
441
|
+
property(:description)
|
442
|
+
end
|
443
|
+
|
444
|
+
def description=(val)
|
445
|
+
set_property(:description, val)
|
446
|
+
end
|
447
|
+
|
448
|
+
=begin rdoc
|
449
|
+
Status of the bug: open or closed?
|
450
|
+
=end
|
451
|
+
def open?
|
452
|
+
bool_property(:open)
|
453
|
+
end
|
454
|
+
|
455
|
+
def open=(val)
|
456
|
+
set_property(:open, val)
|
457
|
+
end
|
458
|
+
|
459
|
+
=begin rdoc
|
460
|
+
Tests which demonstrate the buig.
|
461
|
+
=end
|
462
|
+
def tests
|
463
|
+
ensure_valid
|
464
|
+
@tests.keys
|
465
|
+
end
|
466
|
+
|
467
|
+
=begin rdoc
|
468
|
+
Associated a test with this bug.
|
469
|
+
|
470
|
+
Note: t is a TestModelItem object.
|
471
|
+
=end
|
472
|
+
def add_test( t )
|
473
|
+
ensure_valid
|
474
|
+
@tests.add(self, t )
|
475
|
+
end
|
476
|
+
|
477
|
+
=begin rdoc
|
478
|
+
Delete a test from this suite.
|
479
|
+
=end
|
480
|
+
def del_test(ident)
|
481
|
+
ensure_valid
|
482
|
+
@tests.delete(ident)
|
483
|
+
end
|
484
|
+
|
485
|
+
=begin rdoc
|
486
|
+
Update the status of the bug: open if any of the tests fail, closed if all
|
487
|
+
of the tests pass.
|
488
|
+
=end
|
489
|
+
def update
|
490
|
+
pass_all = true
|
491
|
+
tests.each do |ident|
|
492
|
+
test = @tests[ident]
|
493
|
+
pass_all = false if not test.pass?
|
494
|
+
end
|
495
|
+
|
496
|
+
# pass_all should equal !open
|
497
|
+
if pass_all == open?
|
498
|
+
open = (not pass_all)
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
end
|
503
|
+
|