git-ds 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|