spectre-core 1.8.0
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 +7 -0
- data/exe/spectre +487 -0
- data/lib/spectre.rb +434 -0
- data/lib/spectre/assertion.rb +277 -0
- data/lib/spectre/bag.rb +19 -0
- data/lib/spectre/curl.rb +368 -0
- data/lib/spectre/database/postgres.rb +78 -0
- data/lib/spectre/diagnostic.rb +29 -0
- data/lib/spectre/environment.rb +26 -0
- data/lib/spectre/ftp.rb +195 -0
- data/lib/spectre/helpers.rb +64 -0
- data/lib/spectre/http.rb +343 -0
- data/lib/spectre/http/basic_auth.rb +22 -0
- data/lib/spectre/http/keystone.rb +98 -0
- data/lib/spectre/logger.rb +144 -0
- data/lib/spectre/logger/console.rb +142 -0
- data/lib/spectre/logger/file.rb +96 -0
- data/lib/spectre/mixin.rb +41 -0
- data/lib/spectre/mysql.rb +97 -0
- data/lib/spectre/reporter/console.rb +103 -0
- data/lib/spectre/reporter/junit.rb +98 -0
- data/lib/spectre/resources.rb +46 -0
- data/lib/spectre/ssh.rb +149 -0
- metadata +140 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module Spectre::Http
|
2
|
+
class SpectreHttpRequest
|
3
|
+
def basic_auth username, password
|
4
|
+
@__req['basic_auth'] = {} if not @__req.has_key? 'basic_auth'
|
5
|
+
|
6
|
+
@__req['basic_auth']['username'] = username
|
7
|
+
@__req['basic_auth']['password'] = password
|
8
|
+
|
9
|
+
@__req['auth'] = 'basic_auth'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module BasicAuth
|
14
|
+
def self.on_req http, net_req, req
|
15
|
+
return unless req.has_key? 'basic_auth' and req['auth'] == 'basic_auth'
|
16
|
+
basic_auth_cfg = req['basic_auth']
|
17
|
+
net_req.basic_auth(basic_auth_cfg['username'], basic_auth_cfg['password'])
|
18
|
+
end
|
19
|
+
|
20
|
+
Spectre::Http.register(self)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
class HttpRequest
|
2
|
+
def keystone url, username, password, project, domain, cert
|
3
|
+
@__req['keystone'] = {} if not @__req.has_key? 'keystone'
|
4
|
+
|
5
|
+
@__req['keystone']['url'] = url
|
6
|
+
@__req['keystone']['username'] = username
|
7
|
+
@__req['keystone']['password'] = password
|
8
|
+
@__req['keystone']['project'] = project
|
9
|
+
@__req['keystone']['domain'] = domain
|
10
|
+
@__req['keystone']['cert'] = cert
|
11
|
+
|
12
|
+
@__req.config['auth'] = 'keystone'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
module Spectre::Http::Keystone
|
18
|
+
@@cache = {}
|
19
|
+
|
20
|
+
def self.on_req http, net_req, req
|
21
|
+
return unless req.has_key? 'keystone' and req['auth'] == 'keystone'
|
22
|
+
|
23
|
+
keystone_cfg = req['keystone']
|
24
|
+
|
25
|
+
if @@cache.has_key? keystone_cfg
|
26
|
+
token = @@cache[keystone_cfg]
|
27
|
+
else
|
28
|
+
token, _ = authenticate(
|
29
|
+
keystone_cfg['url'],
|
30
|
+
keystone_cfg['username'],
|
31
|
+
keystone_cfg['password'],
|
32
|
+
keystone_cfg['project'],
|
33
|
+
keystone_cfg['domain'],
|
34
|
+
keystone_cfg['cert'],
|
35
|
+
)
|
36
|
+
|
37
|
+
@@cache[keystone_cfg] = token
|
38
|
+
end
|
39
|
+
|
40
|
+
net_req['X-Auth-Token'] = token
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def self.authenticate keystone_url, username, password, project, domain, cert
|
46
|
+
auth_data = {
|
47
|
+
auth: {
|
48
|
+
identity: {
|
49
|
+
methods: ['password'],
|
50
|
+
password: {
|
51
|
+
user: {
|
52
|
+
name: username,
|
53
|
+
password: password,
|
54
|
+
domain: {
|
55
|
+
name: domain,
|
56
|
+
},
|
57
|
+
},
|
58
|
+
},
|
59
|
+
},
|
60
|
+
scope: {
|
61
|
+
project: {
|
62
|
+
name: project,
|
63
|
+
domain: {
|
64
|
+
name: domain,
|
65
|
+
},
|
66
|
+
},
|
67
|
+
},
|
68
|
+
},
|
69
|
+
}
|
70
|
+
|
71
|
+
keystone_url = keystone_url + '/' if !keystone_url.end_with? '/'
|
72
|
+
|
73
|
+
base_uri = URI(keystone_url)
|
74
|
+
uri = URI.join(base_uri, 'auth/tokens?nocatalog=true')
|
75
|
+
|
76
|
+
http = Net::HTTP.new(base_uri.host, base_uri.port)
|
77
|
+
|
78
|
+
if cert
|
79
|
+
http.use_ssl = true
|
80
|
+
http.ca_file = cert
|
81
|
+
end
|
82
|
+
|
83
|
+
req = Net::HTTP::Post.new(uri)
|
84
|
+
req.body = JSON.pretty_generate(auth_data)
|
85
|
+
req.content_type = 'application/json'
|
86
|
+
|
87
|
+
res = http.request(req)
|
88
|
+
|
89
|
+
raise "error while authenticating: #{res.code} #{res.message}\n#{res.body}" if res.code != '201'
|
90
|
+
|
91
|
+
[
|
92
|
+
res['X-Subject-Token'],
|
93
|
+
JSON.parse(res.body),
|
94
|
+
]
|
95
|
+
end
|
96
|
+
|
97
|
+
Spectre::Http.register(self)
|
98
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Spectre
|
4
|
+
module Logger
|
5
|
+
module Status
|
6
|
+
OK = '[ok]'
|
7
|
+
FAILED = '[failed]'
|
8
|
+
ERROR = '[error]'
|
9
|
+
INFO = '[info]'
|
10
|
+
SKIPPED = '[skipped]'
|
11
|
+
DEBUG = '[debug]'
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
@@debug = false
|
16
|
+
@@logger = []
|
17
|
+
|
18
|
+
def debug!
|
19
|
+
@@debug = true
|
20
|
+
end
|
21
|
+
|
22
|
+
def debug?
|
23
|
+
@@debug
|
24
|
+
end
|
25
|
+
|
26
|
+
def add logger
|
27
|
+
@@logger.append logger
|
28
|
+
end
|
29
|
+
|
30
|
+
def start_subject subject
|
31
|
+
delegate(:start_subject, subject)
|
32
|
+
end
|
33
|
+
|
34
|
+
def end_subject subject
|
35
|
+
delegate(:end_subject, subject)
|
36
|
+
end
|
37
|
+
|
38
|
+
def start_context context
|
39
|
+
delegate(:start_context, context)
|
40
|
+
end
|
41
|
+
|
42
|
+
def end_context context
|
43
|
+
delegate(:end_context, context)
|
44
|
+
end
|
45
|
+
|
46
|
+
def start_spec spec, data=nil
|
47
|
+
delegate(:start_spec, spec, data)
|
48
|
+
end
|
49
|
+
|
50
|
+
def end_spec spec, data=nil
|
51
|
+
delegate(:end_spec, spec, data)
|
52
|
+
end
|
53
|
+
|
54
|
+
def log_subject subject
|
55
|
+
begin
|
56
|
+
start_subject(subject)
|
57
|
+
yield
|
58
|
+
ensure
|
59
|
+
end_subject(subject)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def log_context context
|
64
|
+
begin
|
65
|
+
start_context(context)
|
66
|
+
yield
|
67
|
+
ensure
|
68
|
+
end_context(context)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def log_spec spec, data=nil
|
73
|
+
start_spec(spec, data)
|
74
|
+
yield
|
75
|
+
end_spec(spec, data)
|
76
|
+
end
|
77
|
+
|
78
|
+
def log_separator desc
|
79
|
+
delegate(:log_separator, desc)
|
80
|
+
end
|
81
|
+
|
82
|
+
def start_group desc
|
83
|
+
delegate(:start_group, desc)
|
84
|
+
end
|
85
|
+
|
86
|
+
def end_group desc
|
87
|
+
delegate(:end_group, desc)
|
88
|
+
end
|
89
|
+
|
90
|
+
def log_process desc
|
91
|
+
delegate(:log_process, desc)
|
92
|
+
end
|
93
|
+
|
94
|
+
def log_info message
|
95
|
+
add_log(message)
|
96
|
+
delegate(:log_info, message)
|
97
|
+
end
|
98
|
+
|
99
|
+
def log_debug message
|
100
|
+
return unless @@debug
|
101
|
+
add_log(message)
|
102
|
+
delegate(:log_debug, message)
|
103
|
+
end
|
104
|
+
|
105
|
+
def log_error spec, exception
|
106
|
+
add_log(exception)
|
107
|
+
delegate(:log_error, spec, exception)
|
108
|
+
end
|
109
|
+
|
110
|
+
def log_skipped spec
|
111
|
+
delegate(:log_skipped, spec)
|
112
|
+
end
|
113
|
+
|
114
|
+
def log_status desc, status, annotation=nil
|
115
|
+
delegate(:log_status, desc, status, annotation)
|
116
|
+
end
|
117
|
+
|
118
|
+
def group desc
|
119
|
+
Logger.start_group desc
|
120
|
+
yield
|
121
|
+
Logger.end_group desc
|
122
|
+
end
|
123
|
+
|
124
|
+
alias_method :info, :log_info
|
125
|
+
alias_method :log, :log_info
|
126
|
+
alias_method :debug, :log_debug
|
127
|
+
alias_method :separate, :log_separator
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def delegate method, *args
|
132
|
+
@@logger.each do |logger|
|
133
|
+
logger.send(method, *args) if logger.respond_to? method
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def add_log message
|
138
|
+
Spectre::Runner.current.log.append([DateTime.now, message])
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
Spectre.delegate :log, :info, :debug, :group, :separate, to: self
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'ectoplasm'
|
2
|
+
|
3
|
+
module Spectre
|
4
|
+
module Logger
|
5
|
+
class Console
|
6
|
+
def initialize config
|
7
|
+
raise 'No log format section in config for console logger' unless config.has_key? 'log_format' and config['log_format'].has_key? 'console'
|
8
|
+
|
9
|
+
@config = config['log_format']['console']
|
10
|
+
@indent = @config['indent'] || 2
|
11
|
+
@width = @config['width'] || 80
|
12
|
+
@fmt_end_context = @config['end_context']
|
13
|
+
@fmt_sep = @config['separator']
|
14
|
+
@fmt_start_group = @config['start_group']
|
15
|
+
@fmt_end_group = @config['end_group']
|
16
|
+
|
17
|
+
@process = nil
|
18
|
+
@level = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_subject subject
|
22
|
+
puts subject.desc.blue
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_context context
|
26
|
+
return unless context.__desc
|
27
|
+
puts (' ' * indent) + context.__desc.magenta
|
28
|
+
@level += 1
|
29
|
+
end
|
30
|
+
|
31
|
+
def end_context context
|
32
|
+
return unless context.__desc
|
33
|
+
@level -= 1
|
34
|
+
puts (' ' * indent) + @fmt_end_context.gsub('<desc>', context.__desc).magenta if @fmt_end_context
|
35
|
+
end
|
36
|
+
|
37
|
+
def start_spec spec, data=nil
|
38
|
+
text = spec.desc
|
39
|
+
text += " with #{data}" if data
|
40
|
+
puts (' ' * indent) + text.cyan
|
41
|
+
|
42
|
+
@level += 1
|
43
|
+
end
|
44
|
+
|
45
|
+
def end_spec spec, data
|
46
|
+
@level -= 1
|
47
|
+
end
|
48
|
+
|
49
|
+
def log_separator desc
|
50
|
+
if desc
|
51
|
+
desc = @fmt_sep.gsub('<indent>', ' ' * indent).gsub('<desc>', desc) if @fmt_sep
|
52
|
+
puts desc.blue
|
53
|
+
else
|
54
|
+
puts
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def start_group desc
|
59
|
+
desc = @fmt_start_group.gsub('<desc>', desc) if @fmt_start_group
|
60
|
+
puts (' ' * indent) + desc.blue
|
61
|
+
@level += 1
|
62
|
+
end
|
63
|
+
|
64
|
+
def end_group desc
|
65
|
+
if desc and @fmt_start_group
|
66
|
+
desc = @fmt_start_group.gsub('<desc>', desc) if @fmt_start_group
|
67
|
+
puts (' ' * indent) + desc.blue
|
68
|
+
end
|
69
|
+
|
70
|
+
@level -= 1
|
71
|
+
end
|
72
|
+
|
73
|
+
def log_process desc
|
74
|
+
print_line(desc)
|
75
|
+
@process = desc
|
76
|
+
@level += 1
|
77
|
+
end
|
78
|
+
|
79
|
+
def log_status desc, status, annotation=nil
|
80
|
+
status = status.green if status == Status::OK
|
81
|
+
status = status.blue if status == Status::INFO
|
82
|
+
status = status.grey if status == Status::DEBUG
|
83
|
+
status = status.red if status == Status::FAILED
|
84
|
+
status = status.red if status == Status::ERROR
|
85
|
+
status = status.grey if status == Status::SKIPPED
|
86
|
+
|
87
|
+
txt = status
|
88
|
+
txt += ' ' + annotation if annotation
|
89
|
+
|
90
|
+
@level -= 1
|
91
|
+
|
92
|
+
if @process
|
93
|
+
puts txt
|
94
|
+
else
|
95
|
+
print_line('', status)
|
96
|
+
end
|
97
|
+
|
98
|
+
@process = nil
|
99
|
+
end
|
100
|
+
|
101
|
+
def log_info message
|
102
|
+
print_line(message, Status::INFO.blue)
|
103
|
+
end
|
104
|
+
|
105
|
+
def log_debug message
|
106
|
+
print_line(message, Status::DEBUG.grey)
|
107
|
+
end
|
108
|
+
|
109
|
+
def log_error spec, exception
|
110
|
+
txt = (Status::ERROR + ' - ' + exception.class.name).red
|
111
|
+
print_line('', txt)
|
112
|
+
end
|
113
|
+
|
114
|
+
def log_skipped spec
|
115
|
+
print_line('', Status::SKIPPED.grey)
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def indent
|
121
|
+
(@level+1) * @indent
|
122
|
+
end
|
123
|
+
|
124
|
+
def print_line text='', status=nil
|
125
|
+
puts if @process
|
126
|
+
|
127
|
+
ind = indent
|
128
|
+
line = (' ' * indent) + text
|
129
|
+
remaining = @width - text.length - ind
|
130
|
+
line += '.' * (@width - text.length - ind) if remaining > 0
|
131
|
+
|
132
|
+
print line
|
133
|
+
|
134
|
+
if status
|
135
|
+
puts status
|
136
|
+
@process = nil
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Spectre
|
2
|
+
module Logger
|
3
|
+
class File
|
4
|
+
def initialize config
|
5
|
+
raise 'No log format section in config for console logger' unless config.has_key? 'log_format' and config['log_format'].has_key? 'file'
|
6
|
+
|
7
|
+
@config = config['log_format']['file']
|
8
|
+
@fmt_start_group = @config['start_group']
|
9
|
+
@fmt_end_group = @config['end_group']
|
10
|
+
@fmt_sep = @config['separator']
|
11
|
+
|
12
|
+
@file_log = ::Logger.new config['log_file'], progname: 'spectre'
|
13
|
+
@file_log.level = config['debug'] ? 'DEBUG' : 'INFO'
|
14
|
+
end
|
15
|
+
|
16
|
+
def start_subject subject
|
17
|
+
@file_log.debug "start running subject '#{subject.desc}'"
|
18
|
+
end
|
19
|
+
|
20
|
+
def end_subject subject
|
21
|
+
@file_log.debug "subject '#{subject.desc}' finished"
|
22
|
+
end
|
23
|
+
|
24
|
+
def start_context context
|
25
|
+
if context and context.__desc
|
26
|
+
@file_log.debug "start running context '#{context.__desc}'"
|
27
|
+
else
|
28
|
+
@file_log.debug "start running main context of #{context.__subject.desc}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def end_context context
|
33
|
+
if context and context.__desc
|
34
|
+
@file_log.debug "context '#{context.__desc}' finished"
|
35
|
+
else
|
36
|
+
@file_log.debug "main context finished of #{context.__subject.desc}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_spec spec, data=nil
|
41
|
+
log_msg = "start running spec [#{spec.name}] '#{spec.desc}'"
|
42
|
+
log_msg += " with data #{data}" if data
|
43
|
+
@file_log.debug log_msg
|
44
|
+
end
|
45
|
+
|
46
|
+
def end_spec spec, data=nil
|
47
|
+
log_msg = "running spec [#{spec.name}] '#{spec.desc}'"
|
48
|
+
log_msg += " with data #{data}" if data
|
49
|
+
log_msg += " finished"
|
50
|
+
@file_log.debug log_msg
|
51
|
+
end
|
52
|
+
|
53
|
+
def log_separator desc
|
54
|
+
desc = @fmt_sep.gsub('<desc>', desc) if @fmt_sep
|
55
|
+
@file_log.info desc
|
56
|
+
end
|
57
|
+
|
58
|
+
def start_group desc
|
59
|
+
desc = @fmt_start_group.gsub('<desc>', desc) if @fmt_start_group
|
60
|
+
@file_log.info desc
|
61
|
+
end
|
62
|
+
|
63
|
+
def end_group desc
|
64
|
+
desc = @fmt_end_group.gsub('<desc>', desc) if @fmt_end_group
|
65
|
+
@file_log.info desc
|
66
|
+
end
|
67
|
+
|
68
|
+
def log_process desc
|
69
|
+
@file_log.debug desc
|
70
|
+
end
|
71
|
+
|
72
|
+
def log_info message
|
73
|
+
@file_log.info "#{Status::INFO} #{message}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def log_debug message
|
77
|
+
@file_log.debug "#{Status::DEBUG} #{message}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def log_error spec, exception
|
81
|
+
file, line = exception.backtrace[0].match(/(.*\.rb):(\d+)/).captures
|
82
|
+
@file_log.error "An unexpected error occured at '#{file}:#{line}' while running spec '#{spec.name}': [#{exception.class}] #{exception.message}\n#{exception.backtrace.join "\n"}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def log_skipped spec
|
86
|
+
@file_log.warn "spec '#{spec.desc}' canceled by user"
|
87
|
+
end
|
88
|
+
|
89
|
+
def log_status desc, status, annotation=nil
|
90
|
+
msg = "expected #{desc}...#{status.upcase}"
|
91
|
+
msg += " - #{annotation}" if annotation
|
92
|
+
@file_log.debug msg
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|