tdi 0.2.3 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +41 -3
- data/bin/tdi +6 -2
- data/doc/output/both.png +0 -0
- data/doc/output/failure.png +0 -0
- data/doc/output/nofail.png +0 -0
- data/doc/output/success.png +0 -0
- data/doc/output/warnfail.png +0 -0
- data/doc/output/warning.png +0 -0
- data/helper/acl.rb +1 -1
- data/helper/file.rb +43 -18
- data/helper/http.rb +13 -2
- data/helper/ssh.rb +1 -1
- data/lib/planner.rb +5 -5
- data/lib/rblank.rb +1 -1
- data/lib/rmerge.rb +1 -1
- data/lib/runner.rb +10 -4
- data/lib/tdi.rb +1 -8
- data/lib/tdi/version.rb +2 -2
- data/lib/util.rb +2 -2
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 244daf4e0163efb156bc527c7b1f47d0a8f0aaa5
|
4
|
+
data.tar.gz: b6d43ee88862a8e6a51423b697cf8c53f4c3145d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b26b2de5ab7ba6d092856a85deb9b374de6eb4f8633a78694c69167202fc1b55faf644fb22ef71b0100292c1b151c085cc7d664d43d35cb69a935eb8de2ec0f
|
7
|
+
data.tar.gz: 62b798baccb34ff7dbbb9cfe70b67575e79d3812e4458c3cf4c31c2b71f537db6724c5840c44844e0439e77beae64e5e2582d2b0a646cf7c3cdd5c683766df43
|
data/README.md
CHANGED
@@ -40,6 +40,9 @@ Examples:
|
|
40
40
|
tdi tdi.json -n
|
41
41
|
tdi tdi.json --nofail
|
42
42
|
|
43
|
+
tdi tdi.json -w
|
44
|
+
tdi tdi.json --warnfail
|
45
|
+
|
43
46
|
tdi tdi.json -p app
|
44
47
|
tdi tdi.json --plan app
|
45
48
|
tdi tdi.json --plan app::acl
|
@@ -60,6 +63,7 @@ Examples:
|
|
60
63
|
Options:
|
61
64
|
|
62
65
|
-n, --nofail No fail mode.
|
66
|
+
-w, --warnfail Fail if any warning.
|
63
67
|
-p, --plan Test plan list.
|
64
68
|
-r, --reportfile Report file to save test plan status.
|
65
69
|
-s, --shred Wipe out the test plan, leaving no trace behind.
|
@@ -247,7 +251,10 @@ tdi_plan = {
|
|
247
251
|
:app => {
|
248
252
|
:desc => 'Test role',
|
249
253
|
:acl => {'localhost' => {:port => [22, 80]}},
|
250
|
-
:http => {
|
254
|
+
:http => {
|
255
|
+
'globo.com' => {:code => 301},
|
256
|
+
'noexist.globo.com' => {:code => 200},
|
257
|
+
},
|
251
258
|
}
|
252
259
|
}
|
253
260
|
|
@@ -263,19 +270,50 @@ tdi_plan = {
|
|
263
270
|
'app': {
|
264
271
|
'desc': 'Test role',
|
265
272
|
'acl': {'localhost': {'port': [22, 80]}},
|
266
|
-
'http': {
|
273
|
+
'http': {
|
274
|
+
'globo.com': {'code': 301},
|
275
|
+
'noexist.globo.com': {'code': 200},
|
276
|
+
},
|
267
277
|
}
|
268
278
|
}
|
269
279
|
|
270
280
|
open('tdi.json', 'w').write(json.dumps(tdi_plan, indent=2))
|
271
281
|
```
|
272
282
|
|
273
|
-
###
|
283
|
+
### Validating your plan file
|
274
284
|
|
275
285
|
Use JSONLint site to validate your JSONs.
|
276
286
|
|
277
287
|
http://jsonlint.com/
|
278
288
|
|
289
|
+
## Running test plans and their possible `return codes`
|
290
|
+
|
291
|
+
Return codes are:
|
292
|
+
|
293
|
+
* `0` if all `success`
|
294
|
+
|
295
|
+

|
296
|
+
|
297
|
+
* `0` by default even if warning (warning should not generate a validation error)
|
298
|
+
|
299
|
+

|
300
|
+
|
301
|
+
* `1` if any `failure`
|
302
|
+
|
303
|
+

|
304
|
+
|
305
|
+
* `2` if any `warning` plus option `-w` or `--warnfail`
|
306
|
+
|
307
|
+

|
308
|
+
|
309
|
+
* `3` if both `failure` and `warning` plus option `-w` or `--warnfail`
|
310
|
+
|
311
|
+

|
312
|
+
|
313
|
+
* `0` regardless failure or warning if `-n` or `--nofail`
|
314
|
+
|
315
|
+

|
316
|
+
|
279
317
|
## Contributors
|
280
318
|
|
281
319
|
[People](https://github.com/globocom/tdi/graphs/contributors)
|
data/bin/tdi
CHANGED
@@ -13,14 +13,14 @@
|
|
13
13
|
#
|
14
14
|
# === Authors
|
15
15
|
#
|
16
|
-
# Rogério Carvalho Schneider <
|
16
|
+
# Rogério Carvalho Schneider <schneider@corp.globo.com>
|
17
17
|
# Leonardo Martins de Lima <leonardo.martins@corp.globo.com>
|
18
18
|
# Diogo Kiss <diogokiss@corp.globo.com>
|
19
19
|
# Francisco Corrêa <francisco@corp.globo.com>
|
20
20
|
#
|
21
21
|
# === Copyright
|
22
22
|
#
|
23
|
-
# Copyright (C) 2013-
|
23
|
+
# Copyright (C) 2013-2017 Globo.com
|
24
24
|
#
|
25
25
|
|
26
26
|
# This file is part of TDI.
|
@@ -170,6 +170,9 @@ Examples:
|
|
170
170
|
tdi tdi.json -n
|
171
171
|
tdi tdi.json --nofail
|
172
172
|
|
173
|
+
tdi tdi.json -w
|
174
|
+
tdi tdi.json --warnfail
|
175
|
+
|
173
176
|
tdi tdi.json -p app
|
174
177
|
tdi tdi.json --plan app
|
175
178
|
tdi tdi.json --plan app::acl
|
@@ -190,6 +193,7 @@ Examples:
|
|
190
193
|
Options:
|
191
194
|
EOS
|
192
195
|
on :n, :nofail, 'No fail mode.'
|
196
|
+
on :w, :warnfail, 'Fail if any warning.'
|
193
197
|
on :p, :plan, 'Test plan list.', as: Array, argument: :optional
|
194
198
|
on :r, :reportfile, 'Report file to save test plan status.', argument: :required
|
195
199
|
on :s, :shred, 'Wipe out the test plan, leaving no trace behind.'
|
data/doc/output/both.png
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/helper/acl.rb
CHANGED
data/helper/file.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2017 Globo.com
|
3
3
|
#
|
4
4
|
|
5
5
|
# This file is part of TDI.
|
@@ -64,41 +64,66 @@ class TDIPlan < TDI
|
|
64
64
|
rescue
|
65
65
|
@flag_success = false if perm.eql?('rw')
|
66
66
|
ensure
|
67
|
-
# Cleanup
|
68
|
-
|
67
|
+
# Cleanup. If type is directory, remove tempfile.
|
68
|
+
if type.eql?('directory')
|
69
|
+
FileUtils.rm(filename) rescue nil
|
70
|
+
end
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
72
74
|
# Type.
|
73
75
|
case type
|
74
76
|
when 'directory'
|
77
|
+
# Access?
|
78
|
+
# Must exist, be readable and executable.
|
79
|
+
@flag_success = File.exist?(path) && File.readable?(path) && File.executable?(path)
|
80
|
+
@flag_success = File.exist?(path) && File.readable?(path) && File.executable?(path) && File.writable?(path) if perm.eql?('rw')
|
81
|
+
|
75
82
|
# Path.
|
76
83
|
filename = "#{path}/#{ENV['HOSTNAME']}.rw"
|
77
|
-
testPerm filename, perm, type
|
84
|
+
testPerm filename, perm, type if @flag_success # must be accessible or false positive may manifest
|
78
85
|
when 'file'
|
86
|
+
# Access?
|
87
|
+
# Must exist and be readable.
|
88
|
+
@flag_success = File.exist?(path) && File.readable?(path)
|
89
|
+
@flag_success = File.exist?(path) && File.readable?(path) && File.writable?(path) if perm.eql?('rw')
|
90
|
+
|
79
91
|
# Path.
|
80
92
|
filename = path
|
81
|
-
testPerm filename, perm, type
|
93
|
+
testPerm filename, perm, type if @flag_success # must be accessible or false positive may manifest
|
82
94
|
when 'link'
|
83
|
-
|
84
|
-
|
95
|
+
# Access?
|
96
|
+
# Must exist and be readable. Target must also exist.
|
97
|
+
@flag_success = File.symlink?(path) && File.exist?(path) && File.readable?(path)
|
98
|
+
@flag_success = File.symlink?(path) && File.exist?(path) && File.readable?(path) && File.writable?(path) if perm.eql?('rw')
|
85
99
|
else
|
86
100
|
puts "ERR: Invalid file plan format \"#{type}\". Type must be \"directory\", \"file\" or \"link\".".light_magenta
|
87
101
|
exit 1
|
88
102
|
end
|
89
103
|
|
90
104
|
# Location.
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
105
|
+
if @flag_success
|
106
|
+
mount_p = File.realpath(path)
|
107
|
+
mount_t = nil
|
108
|
+
while !mount_p.eql?('/') && mount_t.nil?
|
109
|
+
mount_t = Filesystem.mounts.select { |mount| mount.mount_point.eql?(mount_p) }.first
|
110
|
+
mount_t = mount_t.mount_type unless mount_t.nil?
|
111
|
+
mount_p = File.expand_path("#{mount_p}/../") # pop leaf dir before next iteration
|
112
|
+
end
|
113
|
+
if mount_t.nil?
|
114
|
+
mount_p = '/'
|
115
|
+
mount_t = Filesystem.mounts.select { |mount| mount.mount_point.eql?(mount_p) }.first.mount_type
|
116
|
+
end
|
117
|
+
|
118
|
+
case location
|
119
|
+
when 'local'
|
120
|
+
@flag_success = false if REMOTE_FS_LIST.include?(mount_t)
|
121
|
+
when 'nfs'
|
122
|
+
@flag_success = false unless mount_t.eql?('nfs')
|
123
|
+
else
|
124
|
+
puts "ERR: Invalid file plan format \"#{location}\". Location must be \"local\" or \"nfs\".".light_magenta
|
125
|
+
exit 1
|
126
|
+
end
|
102
127
|
end
|
103
128
|
|
104
129
|
# Verdict.
|
data/helper/http.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2017 Globo.com
|
3
3
|
#
|
4
4
|
|
5
5
|
# This file is part of TDI.
|
@@ -75,7 +75,11 @@ class TDIPlan < TDI
|
|
75
75
|
addr = nil
|
76
76
|
proxy_addr = nil
|
77
77
|
res_str = case_name
|
78
|
-
|
78
|
+
if proxy.nil?
|
79
|
+
res_dict = {url: case_name, net: origin_network(host)}
|
80
|
+
else
|
81
|
+
res_dict = {url: case_name, net: origin_network(proxy)}
|
82
|
+
end
|
79
83
|
res_dict[:proxy] = "#{proxy}:#{proxy_port}" unless proxy.nil?
|
80
84
|
headers = nil
|
81
85
|
response = nil
|
@@ -88,6 +92,13 @@ class TDIPlan < TDI
|
|
88
92
|
begin
|
89
93
|
addr = getaddress(host).to_s
|
90
94
|
|
95
|
+
# Update report information to keep :to key pointing to the actual host,
|
96
|
+
# not to the proxy host. Add :via key with proxy network data.
|
97
|
+
unless proxy.nil?
|
98
|
+
res_dict[:net][:via] = res_dict[:net][:to]
|
99
|
+
res_dict[:net][:to] = {host: host, addr: addr}
|
100
|
+
end
|
101
|
+
|
91
102
|
if not proxy.nil? and not proxy_port.nil?
|
92
103
|
proxy_addr = getaddress(proxy).to_s
|
93
104
|
http = Net::HTTP::Proxy(proxy, proxy_port)
|
data/helper/ssh.rb
CHANGED
data/lib/planner.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2017 Globo.com
|
3
3
|
#
|
4
4
|
|
5
5
|
# This file is part of TDI.
|
@@ -132,9 +132,9 @@ def plan_compiler(opts, plan)
|
|
132
132
|
end
|
133
133
|
|
134
134
|
# Test case compile.
|
135
|
-
new_case_content = role_content.reject { |key, val| UNMERGEABLE_KEY_LIST.include?(key)
|
136
|
-
new_case_content.merge!(plan_content.reject { |key, val| UNMERGEABLE_KEY_LIST.include?(key)
|
137
|
-
new_case_content.merge!(case_content.reject { |key, val| UNMERGEABLE_KEY_LIST.include?(key)
|
135
|
+
new_case_content = role_content.reject { |key, val| UNMERGEABLE_KEY_LIST.include?(key) || val.is_a?(Hash) }
|
136
|
+
new_case_content.merge!(plan_content.reject { |key, val| UNMERGEABLE_KEY_LIST.include?(key) || val.is_a?(Hash) })
|
137
|
+
new_case_content.merge!(case_content.reject { |key, val| UNMERGEABLE_KEY_LIST.include?(key) || val.is_a?(Hash) })
|
138
138
|
|
139
139
|
# Test case (new, merged).
|
140
140
|
compiled_plan[role_name][plan_name][case_name] = new_case_content
|
@@ -209,7 +209,7 @@ def plan_inheriter(opts, plan)
|
|
209
209
|
unless i_plan.nil?
|
210
210
|
i_role_name, i_plan_name = role_plan_split(i_plan)
|
211
211
|
|
212
|
-
if i_role_name.nil?
|
212
|
+
if i_role_name.nil? || i_plan_name.nil?
|
213
213
|
puts "ERR: Invalid inheritance \"#{i_plan}\". Must match pattern \"role::plan\".".light_magenta
|
214
214
|
exit 1
|
215
215
|
end
|
data/lib/rblank.rb
CHANGED
data/lib/rmerge.rb
CHANGED
data/lib/runner.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2017 Globo.com
|
3
3
|
#
|
4
4
|
|
5
5
|
# This file is part of TDI.
|
@@ -30,7 +30,7 @@ def runner(opts, filename, plan)
|
|
30
30
|
# Ex: {"common": {"desc": "...", "acl": {"domain1": {"port": 80}...}...}...}
|
31
31
|
plan.select { |role_name, role_content|
|
32
32
|
if role_content.is_a?(Hash)
|
33
|
-
UNTESTABLE_ROLE_LIST.include?(role_name)
|
33
|
+
UNTESTABLE_ROLE_LIST.include?(role_name) || role_content['notest'].eql?('true')
|
34
34
|
end
|
35
35
|
}.each_pair do |role_name, role_content|
|
36
36
|
puts "Skipping reserved or disabled role: #{role_name}".yellow if opts[:verbose] > 0
|
@@ -39,7 +39,7 @@ def runner(opts, filename, plan)
|
|
39
39
|
# Remove untestable roles.
|
40
40
|
plan.reject! { |role_name, role_content|
|
41
41
|
if role_content.is_a?(Hash)
|
42
|
-
UNTESTABLE_ROLE_LIST.include?(role_name)
|
42
|
+
UNTESTABLE_ROLE_LIST.include?(role_name) || role_content['notest'].eql?('true')
|
43
43
|
end
|
44
44
|
}
|
45
45
|
total_roles = plan.select { |key, val| val.is_a?(Hash) }.size
|
@@ -102,8 +102,14 @@ def runner(opts, filename, plan)
|
|
102
102
|
|
103
103
|
puts 'Running tests... done.'.green if opts[:verbose] > 1
|
104
104
|
|
105
|
-
ret =
|
105
|
+
ret = 0
|
106
|
+
ret += 1 if tdiplan.fail > 0
|
107
|
+
ret += 2 if opts.warnfail? && tdiplan.warn > 0
|
106
108
|
ret = 0 if opts.nofail?
|
109
|
+
# 1 if failures
|
110
|
+
# 2 if warnings (only if -w/--warnfail is active)
|
111
|
+
# 3 if both (only if -w/--warnfail is active)
|
112
|
+
# 0 if none or if -n/--nofail is active
|
107
113
|
ret
|
108
114
|
end
|
109
115
|
|
data/lib/tdi.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2017 Globo.com
|
3
3
|
#
|
4
4
|
|
5
5
|
# This file is part of TDI.
|
@@ -21,14 +21,9 @@ require 'socket'
|
|
21
21
|
require_relative 'tdi/version'
|
22
22
|
|
23
23
|
class TDI
|
24
|
-
attr_accessor :plan_passed, :case_passed
|
25
|
-
alias :plan_passed? :plan_passed
|
26
|
-
alias :case_passed? :case_passed
|
27
24
|
attr_accessor :skip, :pass, :warn, :fail, :report
|
28
25
|
|
29
26
|
def initialize
|
30
|
-
@plan_passed = true
|
31
|
-
@case_passed = true
|
32
27
|
@skip = 0
|
33
28
|
@pass = 0
|
34
29
|
@warn = 0
|
@@ -59,8 +54,6 @@ class TDI
|
|
59
54
|
def failure(role_name, plan_name, res_msg, res_dict)
|
60
55
|
update_report(:fail, role_name, plan_name, res_dict)
|
61
56
|
printf("%-70s [ %s ]\n", res_msg, 'FAIL'.light_red)
|
62
|
-
@plan_passed = false
|
63
|
-
@case_passed = false
|
64
57
|
@fail += 1
|
65
58
|
end
|
66
59
|
|
data/lib/tdi/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2017 Globo.com
|
3
3
|
#
|
4
4
|
|
5
5
|
# This file is part of TDI.
|
@@ -18,5 +18,5 @@
|
|
18
18
|
# along with TDI. If not, see <http://www.gnu.org/licenses/>.
|
19
19
|
|
20
20
|
module Tdi
|
21
|
-
VERSION = '0.2.
|
21
|
+
VERSION = '0.2.4'
|
22
22
|
end
|
data/lib/util.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2017 Globo.com
|
3
3
|
#
|
4
4
|
|
5
5
|
# This file is part of TDI.
|
@@ -52,7 +52,7 @@ end
|
|
52
52
|
|
53
53
|
# Return a list of local networks and it's details.
|
54
54
|
def local_networks
|
55
|
-
Socket.getifaddrs.each.select { |ifaddr| ifaddr.addr.ipv4?
|
55
|
+
Socket.getifaddrs.each.select { |ifaddr| ifaddr.addr.ipv4? && !ifaddr.name.start_with?('lo') }.
|
56
56
|
map do |ifaddr|
|
57
57
|
ip = IPAddress::IPv4.new("#{ifaddr.addr.ip_address}/#{ifaddr.netmask.ip_address}")
|
58
58
|
{
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tdi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rogério Carvalho Schneider
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-04-
|
13
|
+
date: 2017-04-19 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -157,6 +157,12 @@ files:
|
|
157
157
|
- doc/json/file.json
|
158
158
|
- doc/json/http.json
|
159
159
|
- doc/json/ssh.json
|
160
|
+
- doc/output/both.png
|
161
|
+
- doc/output/failure.png
|
162
|
+
- doc/output/nofail.png
|
163
|
+
- doc/output/success.png
|
164
|
+
- doc/output/warnfail.png
|
165
|
+
- doc/output/warning.png
|
160
166
|
- helper/acl.rb
|
161
167
|
- helper/file.rb
|
162
168
|
- helper/http.rb
|