tdi 0.1.6 → 0.1.7

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