tdi 0.1.6 → 0.1.7

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/lib/planner.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2013-2014 Globo.com
2
+ # Copyright (C) 2013-2015 Globo.com
3
3
  #
4
4
 
5
5
  # This file is part of TDI.
@@ -92,7 +92,7 @@ def plan_compiler(opts, plan)
92
92
  compiled_plan = {}
93
93
 
94
94
  # Role.
95
- # Ex: {"admin": {"desc": "...", "acl": {"domain1": {"port": 80}...}...}...}
95
+ # Ex: {"app": {"desc": "...", "acl": {"domain1": {"port": 80}...}...}...}
96
96
  plan.select { |key, val|
97
97
  val.is_a?(Hash)
98
98
  }.each_with_index do |(role_name, role_content), index|
@@ -169,7 +169,7 @@ def plan_inheriter(opts, plan)
169
169
  inherited_plan = {}
170
170
 
171
171
  # Role may inherit from role.
172
- # Ex: {"admin": {"desc": "...", "inherits": "other_role", "acl": {"domain1": {"port": 80}...}...}...}
172
+ # Ex: {"app": {"desc": "...", "inherits": "other_role", "acl": {"domain1": {"port": 80}...}...}...}
173
173
  plan.select { |key, val|
174
174
  val.is_a?(Hash)
175
175
  }.each_with_index do |(role_name, role_content), index|
@@ -243,10 +243,12 @@ def plan_filter(opts, plan)
243
243
  filtered_plan = {}
244
244
  flag_err = false
245
245
 
246
- # Ex: tdi -p admin
247
- # Ex: tdi -p admin::acl
248
- # Ex: tdi --plan fe
249
- # Ex: tdi --plan admin::acl,solr,be
246
+ # Ex: -p admin
247
+ # Ex: -p admin::acl
248
+ # Ex: --plan app
249
+ # Ex: --plan app::acl
250
+ # Ex: --plan fe
251
+ # Ex: --plan admin::acl,app,fe
250
252
  if opts.plan?
251
253
  # Do filter.
252
254
  puts 'Filtering following test plan from input file:'.cyan if opts[:verbose] > 0
data/lib/rblank.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2013-2014 Globo.com
2
+ # Copyright (C) 2013-2015 Globo.com
3
3
  #
4
4
 
5
5
  # This file is part of TDI.
data/lib/rmerge.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2013-2014 Globo.com
2
+ # Copyright (C) 2013-2015 Globo.com
3
3
  #
4
4
 
5
5
  # This file is part of TDI.
data/lib/runner.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2013-2014 Globo.com
2
+ # Copyright (C) 2013-2015 Globo.com
3
3
  #
4
4
 
5
5
  # This file is part of TDI.
@@ -19,6 +19,7 @@
19
19
 
20
20
  require 'os'
21
21
  require_relative 'tdi'
22
+ require_relative 'util'
22
23
 
23
24
  # Run tests.
24
25
  def runner(opts, filename, plan)
@@ -59,7 +60,6 @@ def runner(opts, filename, plan)
59
60
  else
60
61
  puts "* #{role_name.capitalize} - #{role_content['desc']}".cyan
61
62
  end
62
- # puts "Running tests for role: #{role_name}".cyan if opts[:verbose] > 0
63
63
  puts "Total test plans to run for this role: #{total_plans}".cyan if opts[:verbose] > 1
64
64
 
65
65
  # Test plan.
@@ -70,7 +70,6 @@ def runner(opts, filename, plan)
70
70
  total_cases = plan_content.select { |key, val| val.is_a?(Hash) }.size
71
71
 
72
72
  puts "* #{plan_name.upcase}".cyan
73
- # puts "Test plan: #{role_name}::#{plan_name}".cyan if opts[:verbose] > 0
74
73
  puts "Total test cases to run for this plan: #{total_cases}".cyan if opts[:verbose] > 1
75
74
 
76
75
  if opts[:verbose] > 3
@@ -82,7 +81,7 @@ def runner(opts, filename, plan)
82
81
  # Test plan content (test cases).
83
82
  # Ex: {"domain1": {"port": 80}, "domain2": {"port": 80}...}
84
83
  if tdiplan.respond_to?(plan_name)
85
- tdiplan.send(plan_name, plan_content)
84
+ tdiplan.send(plan_name, role_name, plan_name, plan_content)
86
85
  else
87
86
  puts "Skipping not supported test plan type \"#{plan_name}\" for \"#{role_name}::#{plan_name}\".".yellow
88
87
  tdiplan.skip = tdiplan.skip + total_cases
@@ -95,7 +94,40 @@ def runner(opts, filename, plan)
95
94
  # Summary.
96
95
  summary(opts, tdiplan)
97
96
 
97
+ # Report file.
98
+ report(opts, tdiplan)
99
+
98
100
  # Shred.
101
+ shred(opts, filename, tdiplan)
102
+
103
+ puts 'Running tests... done.'.green if opts[:verbose] > 1
104
+
105
+ ret = tdiplan.plan_passed? ? 0 : 1
106
+ ret = 0 if opts.nofail?
107
+ ret
108
+ end
109
+
110
+ # Display test summary.
111
+ def summary(opts, tdiplan)
112
+ puts '=' * 79
113
+ puts "Total: #{tdiplan.total} | Skip: #{tdiplan.skip} | Pass: #{tdiplan.pass} | Warn: #{tdiplan.warn} | Fail: #{tdiplan.fail}"
114
+ end
115
+
116
+ # Generate report file.
117
+ def report(opts, tdiplan)
118
+ if opts[:verbose] > 2
119
+ puts 'Report:'.cyan
120
+ a_p tdiplan.report
121
+ end
122
+
123
+ if opts.reportfile?
124
+ puts "Generating report file: \"#{opts[:reportfile]}\"".cyan if opts[:verbose] > 1
125
+ File.open(opts[:reportfile], 'w') { |file| file.write(JSON.pretty_generate(tdiplan.report)) }
126
+ end
127
+ end
128
+
129
+ # Remove tdi plan file.
130
+ def shred(opts, filename, tdiplan)
99
131
  if opts.shred?
100
132
  puts "Shreding and removing test plan file: \"#{filename}\"...".cyan if opts[:verbose] > 2
101
133
  if OS.linux?
@@ -112,16 +144,4 @@ def runner(opts, filename, plan)
112
144
  puts "ERR: Shreding and removing test plan file: \"#{filename}\".".light_magenta
113
145
  end
114
146
  end
115
-
116
- puts 'Running tests... done.'.green if opts[:verbose] > 1
117
-
118
- ret = tdiplan.plan_passed? ? 0 : 1
119
- ret = 0 if opts.nofail?
120
- ret
121
- end
122
-
123
- # Display test summary.
124
- def summary(opts, tdiplan)
125
- puts '=' * 79
126
- puts "Total: #{tdiplan.total} | Skip: #{tdiplan.skip} | Pass: #{tdiplan.pass} | Warn: #{tdiplan.warn} | Fail: #{tdiplan.fail}"
127
147
  end
data/lib/tdi.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2013-2014 Globo.com
2
+ # Copyright (C) 2013-2015 Globo.com
3
3
  #
4
4
 
5
5
  # This file is part of TDI.
@@ -17,13 +17,14 @@
17
17
  # You should have received a copy of the GNU General Public License
18
18
  # along with TDI. If not, see <http://www.gnu.org/licenses/>.
19
19
 
20
+ require 'socket'
20
21
  require_relative 'tdi/version'
21
22
 
22
23
  class TDI
23
24
  attr_accessor :plan_passed, :case_passed
24
25
  alias :plan_passed? :plan_passed
25
26
  alias :case_passed? :case_passed
26
- attr_accessor :skip, :pass, :warn, :fail
27
+ attr_accessor :skip, :pass, :warn, :fail, :report
27
28
 
28
29
  def initialize
29
30
  @plan_passed = true
@@ -32,21 +33,32 @@ class TDI
32
33
  @pass = 0
33
34
  @warn = 0
34
35
  @fail = 0
36
+ @report = {hostname: Socket.gethostname}
35
37
  end
36
38
 
37
- def success(msg)
39
+ def update_report(status, role_name, plan_name, res_dict)
40
+ @report[role_name] = {} unless @report.has_key?(role_name)
41
+ @report[role_name][plan_name] = [] unless @report[role_name].has_key?(plan_name)
42
+ res_dict[:status] = status
43
+ @report[role_name][plan_name] << res_dict
44
+ end
45
+
46
+ def success(role_name, plan_name, res_msg, res_dict)
47
+ update_report(:pass, role_name, plan_name, res_dict)
38
48
  # I like the seventies.
39
- printf("%-70s [ %s ]\n", msg, 'PASS'.light_green )
49
+ printf("%-70s [ %s ]\n", res_msg, 'PASS'.light_green)
40
50
  @pass += 1
41
51
  end
42
52
 
43
- def warning(msg)
44
- printf("%-70s [ %s ]\n", msg, 'WARN'.light_yellow )
53
+ def warning(role_name, plan_name, res_msg, res_dict)
54
+ update_report(:warn, role_name, plan_name, res_dict)
55
+ printf("%-70s [ %s ]\n", res_msg, 'WARN'.light_yellow)
45
56
  @warn += 1
46
57
  end
47
58
 
48
- def failure(msg)
49
- printf("%-70s [ %s ]\n", msg, 'FAIL'.light_red )
59
+ def failure(role_name, plan_name, res_msg, res_dict)
60
+ update_report(:fail, role_name, plan_name, res_dict)
61
+ printf("%-70s [ %s ]\n", res_msg, 'FAIL'.light_red)
50
62
  @plan_passed = false
51
63
  @case_passed = false
52
64
  @fail += 1
data/lib/tdi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2013-2014 Globo.com
2
+ # Copyright (C) 2013-2015 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.1.6'
21
+ VERSION = '0.1.7'
22
22
  end
data/lib/util.rb ADDED
@@ -0,0 +1,110 @@
1
+ #
2
+ # Copyright (C) 2013-2015 Globo.com
3
+ #
4
+
5
+ # This file is part of TDI.
6
+
7
+ # TDI is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+
12
+ # TDI is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with TDI. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ require 'awesome_print'
21
+ require 'socket'
22
+ require 'ipaddress'
23
+ require 'resolv'
24
+
25
+ # Awesome Print config.
26
+ def a_p(obj)
27
+ ap obj, {
28
+ indent: 2,
29
+ index: false,
30
+ color: {
31
+ args: :pale,
32
+ array: :white,
33
+ bigdecimal: :blue,
34
+ class: :yellow,
35
+ date: :greenish,
36
+ falseclass: :red,
37
+ fixnum: :blue,
38
+ float: :blue,
39
+ hash: :blue,
40
+ keyword: :cyan,
41
+ method: :purpleish,
42
+ nilclass: :red,
43
+ rational: :blue,
44
+ string: :green,
45
+ struct: :pale,
46
+ symbol: :cyanish,
47
+ time: :greenish,
48
+ trueclass: :green,
49
+ variable: :cyanish,
50
+ }
51
+ }
52
+ end
53
+
54
+ # Return a list of local networks and it's details.
55
+ def local_networks
56
+ Socket.getifaddrs.each.select { |ifaddr| ifaddr.addr.ipv4? and ! ifaddr.name.start_with?('lo') }.
57
+ map do |ifaddr|
58
+ ip = IPAddress::IPv4.new("#{ifaddr.addr.ip_address}/#{ifaddr.netmask.ip_address}")
59
+ {
60
+ interface: ifaddr.name,
61
+ net: ip.network.to_string,
62
+ network: ip.network.address,
63
+ netmask: ip.netmask,
64
+ prefix: ip.prefix,
65
+ broadcast: ip.broadcast.address,
66
+ ipv4: ip.address,
67
+ }
68
+ end
69
+ end
70
+
71
+ # Return the origin network to be used when trying to connect to a remote
72
+ # service.
73
+ #
74
+ # Stolen from:
75
+ #
76
+ # https://coderrr.wordpress.com/2008/05/28/get-your-local-ip-address/
77
+ #
78
+ # The above code does NOT make a connection or send any packets. Since UDP is a
79
+ # stateless protocol connect() merely makes a system call which figures out how
80
+ # to route the packets based on the address and what interface (and therefore IP
81
+ # address) it should bind to. addr() returns an array containing the family
82
+ # (AF_INET), local port, and local address (which is what we want) of the socket.
83
+ # This is a good alternative to `ifconfig`/`ipconfig` solutions because it
84
+ # doesn’t spawn a shell and it works the same on all systems.
85
+ def origin_network(remote)
86
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
87
+
88
+ host = remote # host (name or IP)
89
+ if IPAddress.valid?(remote)
90
+ addr = remote # use address (already IP)
91
+ else
92
+ addr = Resolv.getaddress(remote) rescue nil # get address (resolve name to IP)
93
+ end
94
+
95
+ UDPSocket.open do |s|
96
+ begin
97
+ s.connect(remote, 1)
98
+ res = {from: local_networks.each.select { |locnet| locnet[:ipv4].eql?(s.addr.last) }.first}
99
+ rescue
100
+ res = {from: nil}
101
+ end
102
+
103
+ res[:to] = {host: host, addr: addr}
104
+
105
+ return res
106
+ end
107
+
108
+ ensure
109
+ Socket.do_not_reverse_lookup = orig
110
+ end
data/tdi.gemspec CHANGED
@@ -29,4 +29,6 @@ validating your deployed infrastructure and external dependencies.)
29
29
  spec.add_runtime_dependency 'colorize'
30
30
  spec.add_runtime_dependency 'timeout', '0.0.0'
31
31
  spec.add_runtime_dependency 'net-ssh'
32
+ spec.add_runtime_dependency 'awesome_print'
33
+ spec.add_runtime_dependency 'ipaddress'
32
34
  end
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.1.6
4
+ version: 0.1.7
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: 2015-04-10 00:00:00.000000000 Z
13
+ date: 2015-07-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -124,6 +124,34 @@ dependencies:
124
124
  - - ">="
125
125
  - !ruby/object:Gem::Version
126
126
  version: '0'
127
+ - !ruby/object:Gem::Dependency
128
+ name: awesome_print
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ - !ruby/object:Gem::Dependency
142
+ name: ipaddress
143
+ requirement: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ type: :runtime
149
+ prerelease: false
150
+ version_requirements: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
127
155
  description: |-
128
156
  Test Driven Infrastructure acceptance helpers for
129
157
  validating your deployed infrastructure and external dependencies.
@@ -145,6 +173,10 @@ files:
145
173
  - README.md
146
174
  - Rakefile
147
175
  - bin/tdi
176
+ - doc/json/acl.json
177
+ - doc/json/file.json
178
+ - doc/json/http.json
179
+ - doc/json/ssh.json
148
180
  - helper/acl.rb
149
181
  - helper/file.rb
150
182
  - helper/http.rb
@@ -155,6 +187,7 @@ files:
155
187
  - lib/runner.rb
156
188
  - lib/tdi.rb
157
189
  - lib/tdi/version.rb
190
+ - lib/util.rb
158
191
  - tdi.gemspec
159
192
  homepage: https://github.com/globocom/tdi
160
193
  licenses: