spectre-core 1.8.1 → 1.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc992f089d223d10e25ed3ab390e2fa2b3ea826b24c3943bf60ea04992d14163
4
- data.tar.gz: c95f4a37b887bef1d79fe22f221ddd35957e259d03d3e1c2513b973d3c54f564
3
+ metadata.gz: 76697e95cde1f8359db1f305ba1d15869bd53903d49a0575fa1ee6f2cda7bf98
4
+ data.tar.gz: 72562ba547d8f8ff68e880d8f196bd31c7da8f1fd5639231bb56aa838830879a
5
5
  SHA512:
6
- metadata.gz: b7e9166af9137aab37688aa5a1a975296765d903c53e4547a7e1e74de8347cd4ce6e0860a0fd23dd494cc90fd8baafced1fff3381ecd99316159189f80a44629
7
- data.tar.gz: d762e949fdffe4b5faac4a35192eb2ca130a8799f714667eb10b2e09550ccbff13047581f72e5753e3262b4771f4a4bc65aa46e58615ad6d0e894c9c63f9e0d2
6
+ metadata.gz: e1ce860bd80ee58af11d506ad9e297f9a432a6f71f62b7702574c5dd52af0f6a6de7fa8bd2e35c167e387e063f86f97a77f51e0541399a866133c0a3524b22a9
7
+ data.tar.gz: eebfbac67335a7663f407a26094336ee9815a02ebe74789b82254a45ca6539ccc036f289a3eed37cfc581b8e178986f70cbdf5d3c1af49a657ebce4c9ce7246b
data/exe/spectre CHANGED
@@ -48,6 +48,7 @@ DEFAULT_CONFIG = {
48
48
  },
49
49
  'debug' => false,
50
50
  'out_path' => './reports',
51
+ 'secure_keys' => ['password', 'secret', 'token', 'secure', 'authorization'],
51
52
  'spec_patterns' => ['./specs/**/*.spec.rb'],
52
53
  'mixin_patterns' => ['../common/mixins/**/*.mixin.rb', './mixins/**/*.mixin.rb'],
53
54
  'env_patterns' => ['./environments/**/*.env.yml'],
@@ -68,10 +69,6 @@ DEFAULT_CONFIG = {
68
69
  'spectre/http/basic_auth',
69
70
  'spectre/http/keystone',
70
71
  'spectre/resources',
71
- 'spectre/ssh',
72
- 'spectre/ftp',
73
- 'spectre/mysql',
74
- # 'spectre/postgres',
75
72
  ],
76
73
  'include' => [
77
74
 
@@ -126,11 +123,15 @@ Specific options:}
126
123
  cmd_options['colored'] = false
127
124
  end
128
125
 
126
+ opts.on('--ignore-failure', 'Always exit with code 0') do
127
+ cmd_options['ignore_failure'] = true
128
+ end
129
+
129
130
  opts.on('-o PATH', '--out PATH', 'Output directory path') do |path|
130
- cmd_options['out_path'] = path
131
+ cmd_options['out_path'] = File.absolute_path(path)
131
132
  end
132
133
 
133
- opts.on('-r NAME', '--reporter NAME', Array, "A list of reporters to use") do |reporters|
134
+ opts.on('-r NAME', '--reporters NAME', Array, "A list of reporters to use") do |reporters|
134
135
  cmd_options['reporters'] = reporters
135
136
  end
136
137
 
@@ -205,8 +206,9 @@ envs = {}
205
206
  read_env_files = {}
206
207
  cfg['env_patterns'].each do |pattern|
207
208
  Dir.glob(pattern).each do|f|
208
- spec_env = YAML.load_file(f)
209
- name = spec_env.delete('name') || 'default'
209
+ spec_env = YAML.load_file(f) || {}
210
+
211
+ name = spec_env['name'] || 'default'
210
212
 
211
213
  if envs.key? name
212
214
  existing_env_file = read_env_files[name]
@@ -295,7 +297,7 @@ if action == 'run'
295
297
  })
296
298
 
297
299
  log_dir = File.dirname cfg['log_file']
298
- Dir.mkdir log_dir if !Dir.exists? log_dir
300
+ FileUtils.makedirs log_dir if !Dir.exists? log_dir
299
301
 
300
302
  # Load Modules
301
303
  cfg['modules']
@@ -303,12 +305,19 @@ if action == 'run'
303
305
  .select { |mod| !cfg['exclude'].include? mod }
304
306
  .each do |mod|
305
307
  begin
306
- if !File.exists? mod
307
- require_relative File.join('../lib', mod)
308
- else
308
+ spectre_lib_mod = File.join('../lib', mod)
309
+
310
+ if File.exists? mod
309
311
  require_relative mod
312
+
313
+ elsif File.exists? spectre_lib_mod
314
+ require_relative spectre_lib_mod
315
+
316
+ else
317
+ require mod
310
318
  end
311
- rescue => e
319
+
320
+ rescue LoadError => e
312
321
  puts "Unable to load module #{mod}. Check if the module exists or remove it from your spectre config:\n#{e.message}"
313
322
  exit 1
314
323
  end
@@ -337,7 +346,11 @@ if action == 'run'
337
346
  reporter.report(run_infos)
338
347
  end
339
348
 
340
- exit 0
349
+ errors = run_infos.select { |x| x.error != nil or x.failure != nil }
350
+
351
+ exit 0 if cfg['ignore_failure'] or errors.count == 0
352
+
353
+ exit 1
341
354
  end
342
355
 
343
356
 
@@ -464,6 +477,16 @@ reports/
464
477
  **/environments/*.env.secret.yml
465
478
  ]
466
479
 
480
+ DEFAULT_GEMFILE = %[source 'https://rubygems.org'
481
+
482
+ gem 'spectre-core', '>= #{Spectre::VERSION}'
483
+ # gem 'spectre-mysql', '>= 1.0.0'
484
+ # gem 'spectre-ssh', '>= 1.0.0'
485
+ # gem 'spectre-ftp', '>= 1.0.0'
486
+ # gem 'spectre-curl', '>= 1.0.0'
487
+ # gem 'spectre-git', '>= 0.1.0'
488
+ ]
489
+
467
490
  if action == 'init'
468
491
  DEFAULT_FILES = [
469
492
  ['./environments/default.env.yml', DEFAULT_ENV_CFG],
@@ -471,6 +494,7 @@ if action == 'init'
471
494
  ['./specs/sample.spec.rb', SAMPLE_SPEC],
472
495
  ['./spectre.yml', DEFAULT_SPECTRE_CFG],
473
496
  ['./.gitignore', DEFAULT_GITIGNORE],
497
+ ['./Gemfile', DEFAULT_GEMFILE],
474
498
  ]
475
499
 
476
500
  %w(environments logs specs).each do |dir_name|
data/lib/spectre.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Spectre
2
2
  module Version
3
3
  MAJOR = 1
4
- MINOR = 8
5
- TINY = 1
4
+ MINOR = 10
5
+ TINY = 0
6
6
  end
7
7
 
8
8
  VERSION = [Version::MAJOR, Version::MINOR, Version::TINY].compact * '.'
@@ -6,7 +6,7 @@ module Spectre
6
6
  module Assertion
7
7
  class ::Object
8
8
  def should_be(val)
9
- raise AssertionFailure.new("The value '#{self.to_s.trim}' should be '#{val.to_s.trim}'", val, self) unless self.to_s == val.to_s
9
+ raise AssertionFailure.new("The value '#{self.to_s.trim}' should be '#{val.to_s.trim}'", val, self) unless self.to_s == val.to_s
10
10
  end
11
11
 
12
12
  def should_be_empty
@@ -14,11 +14,11 @@ module Spectre
14
14
  end
15
15
 
16
16
  def should_not_be(val)
17
- raise AssertionFailure.new("The value '#{self.to_s.trim}' should not be '#{val.to_s.trim}'", val, self) unless self.to_s != val.to_s
17
+ raise AssertionFailure.new("The value '#{self.to_s.trim}' should not be '#{val.to_s.trim}'", val, self) unless self.to_s != val.to_s
18
18
  end
19
19
 
20
20
  def should_not_exist
21
- raise AssertionFailure.new("The value '#{self.to_s.trim}' should not exist, but it does", val, self) unless self.to_s != nil
21
+ raise AssertionFailure.new("The value '#{self.to_s.trim}' should not exist, but it does", val, self) unless self.to_s != nil
22
22
  end
23
23
 
24
24
  def should_not_be_empty
@@ -76,7 +76,7 @@ module Spectre
76
76
  val = OpenStruct.new(val)
77
77
  end
78
78
 
79
- raise AssertionFailure.new("The list [#{list.join(', ').trim}] should contain '#{val.trim}'", val, list) unless list.include? val
79
+ raise AssertionFailure.new("The list [#{list.join(', ').trim}] should contain '#{val.to_s.trim}'", val, list) unless list.include? val
80
80
  end
81
81
 
82
82
  def should_not_contain(val)
@@ -87,7 +87,7 @@ module Spectre
87
87
  val = OpenStruct.new(val)
88
88
  end
89
89
 
90
- raise AssertionFailure.new("The list [#{list.join(', ').trim}] should not contain '#{val.trim}'", val, list) if list.include? val
90
+ raise AssertionFailure.new("The list [#{list.join(', ').trim}] should not contain '#{val.to_s.trim}'", val, list) if list.include? val
91
91
  end
92
92
 
93
93
  def should_be_empty
@@ -110,7 +110,7 @@ module Spectre
110
110
  end
111
111
 
112
112
  def should_not_be(val)
113
- raise AssertionFailure.new("The text '#{self.trim}' should not be '#{val.to_s.trim}'", val, self) unless self != val
113
+ raise AssertionFailure.new("The text '#{self.trim}' should not be '#{val.to_s.trim}'", val, self) unless self != val
114
114
  end
115
115
 
116
116
  def should_not_be_empty
@@ -118,8 +118,10 @@ module Spectre
118
118
  end
119
119
 
120
120
  def should_contain(value)
121
+ raise AssertionFailure.new("`value' must not be nil") if value.nil?
122
+
121
123
  predicate = proc { |x| self.include? x.to_s }
122
- evaluation = SingleEvaluation.new value
124
+ evaluation = SingleEvaluation.new(value)
123
125
  success = evaluation.call(predicate)
124
126
 
125
127
  return if success
@@ -165,7 +167,7 @@ module Spectre
165
167
 
166
168
  class SingleEvaluation < Evaluation
167
169
  def initialize value
168
- super value, nil
170
+ super(value, nil)
169
171
  end
170
172
 
171
173
  def call predicate
@@ -180,7 +182,7 @@ module Spectre
180
182
 
181
183
  class OrEvaluation < Evaluation
182
184
  def initialize value, other
183
- super value, other
185
+ super(value, other)
184
186
  end
185
187
 
186
188
  def call predicate
@@ -195,7 +197,7 @@ module Spectre
195
197
 
196
198
  class AndEvaluation < Evaluation
197
199
  def initialize value, other
198
- super value, other
200
+ super(value, other)
199
201
  end
200
202
 
201
203
  def call predicate
@@ -222,14 +224,6 @@ module Spectre
222
224
  class << self
223
225
  @@success = nil
224
226
 
225
- def eval_assertion predicate, val
226
- if val.is_a? Proc
227
- val.call(predicate)
228
- else
229
- predicate.call(val)
230
- end
231
- end
232
-
233
227
  def expect desc
234
228
  begin
235
229
  Logger.log_process("expect #{desc}")
@@ -2,6 +2,7 @@ require 'securerandom'
2
2
  require 'json'
3
3
  require 'date'
4
4
  require 'ostruct'
5
+ require 'jsonpath'
5
6
 
6
7
  class ::String
7
8
  def as_json
@@ -17,12 +18,22 @@ class ::String
17
18
  file_content = File.read(self)
18
19
 
19
20
  if with
20
- with.each do |key, value|
21
- file_content = file_content.gsub '#{' + key.to_s + '}', value.to_s
22
- end
21
+ file_content.with(with)
22
+ else
23
+ file_content
23
24
  end
25
+ end
26
+
27
+ def with mapping
28
+ return self unless mapping and mapping.is_a? Hash
24
29
 
25
- file_content
30
+ new_string = self
31
+
32
+ mapping.each do |key, value|
33
+ new_string = new_string.gsub '#{' + key.to_s + '}', value.to_s
34
+ end
35
+
36
+ new_string
26
37
  end
27
38
 
28
39
  def exists?
@@ -35,13 +46,24 @@ class ::String
35
46
  File.delete self
36
47
  end
37
48
 
38
- def trim count=50
49
+ def trim count = 50
39
50
  if (self.length + 3) > count
40
- return self[0..count] + '...'
51
+ return self[0..count-4] + '...'
41
52
  end
42
53
 
43
54
  self
44
55
  end
56
+
57
+ def pick path
58
+ raise ArgumentError.new("`path' must not be nil or empty") if path.nil? or path.empty?
59
+
60
+ begin
61
+ JsonPath.on(self, path)
62
+
63
+ rescue MultiJson::ParseError
64
+ # do nothing and return nil
65
+ end
66
+ end
45
67
  end
46
68
 
47
69
 
@@ -49,6 +71,12 @@ class ::OpenStruct
49
71
  def to_json *args, **kwargs
50
72
  self.to_h.inject({}) { |memo, (k,v)| memo[k] = v.is_a?(OpenStruct) ? v.to_h : v; memo }.to_json(*args, **kwargs)
51
73
  end
74
+
75
+ def pick path
76
+ raise ArgumentError.new("`path' must not be nil or empty") if path.nil? or path.empty?
77
+
78
+ JsonPath.on(self, path)
79
+ end
52
80
  end
53
81
 
54
82
 
@@ -60,5 +88,5 @@ end
60
88
 
61
89
 
62
90
  def uuid length = 5
63
- SecureRandom.uuid().gsub('-', '')[0..length]
91
+ SecureRandom.uuid().gsub('-', '')[0..length-1]
64
92
  end
data/lib/spectre/http.rb CHANGED
@@ -62,8 +62,7 @@ module Spectre
62
62
  end
63
63
 
64
64
  def body body_content
65
- raise 'Body value must be a string' if not body_content.is_a? String
66
- @__req['body'] = body_content
65
+ @__req['body'] = body_content.to_s
67
66
  end
68
67
 
69
68
  def ensure_success!
@@ -102,6 +101,7 @@ module Spectre
102
101
  end
103
102
 
104
103
  def [] key
104
+ return nil if not @headers.has_key?(key.downcase)
105
105
  @headers[key.downcase].first
106
106
  end
107
107
 
@@ -166,6 +166,7 @@ module Spectre
166
166
  @@response = nil
167
167
  @@request = nil
168
168
  @@modules = []
169
+ @@secure_keys = []
169
170
 
170
171
  def https name, &block
171
172
  http(name, secure: true, &block)
@@ -209,7 +210,8 @@ module Spectre
209
210
  return str unless str or str.empty?
210
211
 
211
212
  begin
212
- json = JSON.parse str
213
+ json = JSON.parse(str)
214
+ json.obfuscate!(@@secure_keys) if not @@debug
213
215
 
214
216
  if pretty
215
217
  str = JSON.pretty_generate(json)
@@ -223,6 +225,19 @@ module Spectre
223
225
  str
224
226
  end
225
227
 
228
+ def is_secure? key
229
+ @@secure_keys.any? { |x| key.to_s.downcase.include? x.downcase }
230
+ end
231
+
232
+ def header_to_s headers
233
+ s = ''
234
+ headers.each_header.each do |header, value|
235
+ value = '*****' if is_secure?(header) and not @@debug
236
+ s += "#{header.to_s.ljust(30, '.')}: #{value.to_s}\n"
237
+ end
238
+ s
239
+ end
240
+
226
241
  def invoke req
227
242
  @@request = nil
228
243
 
@@ -275,28 +290,28 @@ module Spectre
275
290
 
276
291
  req_id = SecureRandom.uuid()[0..5]
277
292
 
293
+ # Run HTTP modules
294
+
295
+ @@modules.each do |mod|
296
+ mod.on_req(net_http, net_req, req) if mod.respond_to? :on_req
297
+ end
298
+
278
299
  # Log request
279
300
 
280
- req_log = "[>] #{req_id} #{req['method']} #{uri}"
281
- req['headers'].each do |header|
282
- req_log += "\n#{header[0].to_s.ljust(30, '.')}: #{header[1].to_s}"
283
- end if req['headers']
284
- req_log += "\n" + try_format_json(req['body'], pretty: true) if req['body'] != nil and not req['body'].empty?
301
+ req_log = "[>] #{req_id} #{req['method']} #{uri}\n"
302
+ req_log += header_to_s(net_req)
303
+ req_log += try_format_json(req['body'], pretty: true) if req['body'] != nil and not req['body'].empty?
285
304
 
286
305
  @@logger.info req_log
287
306
 
288
307
  # Request
289
308
 
290
309
  start_time = Time.now
291
-
292
- @@modules.each do |mod|
293
- mod.on_req(net_http, net_req, req) if mod.respond_to? :on_req
294
- end
295
-
296
310
  net_res = net_http.request(net_req)
297
-
298
311
  end_time = Time.now
299
312
 
313
+ # Run HTTP modules
314
+
300
315
  @@modules.each do |mod|
301
316
  mod.on_res(net_http, net_res, req) if mod.respond_to? :on_res
302
317
  end
@@ -304,9 +319,7 @@ module Spectre
304
319
  # Log response
305
320
 
306
321
  res_log = "[<] #{req_id} #{net_res.code} #{net_res.message} (#{end_time - start_time}s)\n"
307
- net_res.each_header do |header, value|
308
- res_log += "#{header.to_s.ljust(30, '.')}: #{value}\n"
309
- end
322
+ res_log += header_to_s(net_res)
310
323
  res_log += try_format_json(net_res.body, pretty: true) if net_res.body != nil and !net_res.body.empty?
311
324
 
312
325
  @@logger.info(res_log)
@@ -328,6 +341,8 @@ module Spectre
328
341
 
329
342
  Spectre.register do |config|
330
343
  @@logger = ::Logger.new config['log_file'], progname: 'spectre/http'
344
+ @@secure_keys = config['secure_keys'] || []
345
+ @@debug = config['debug']
331
346
 
332
347
  if config.key? 'http'
333
348
  @@http_cfg = {}
@@ -97,6 +97,7 @@ module Spectre::Reporter
97
97
  str += " line.....: #{line}\n"
98
98
  str += " type.....: #{error.class}\n"
99
99
  str += " message..: #{error.message}\n"
100
+ str += " backtrace: \n #{error.backtrace.join("\n ")}\n" if @config['debug']
100
101
  str
101
102
  end
102
103
  end
metadata CHANGED
@@ -1,85 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spectre-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.1
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Neubauer
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-18 00:00:00.000000000 Z
11
+ date: 2021-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ectoplasm
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 1.1.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 1.1.0
27
- - !ruby/object:Gem::Dependency
28
- name: openssl
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: 2.2.0
19
+ version: 1.2.0
34
20
  type: :runtime
35
21
  prerelease: false
36
22
  version_requirements: !ruby/object:Gem::Requirement
37
23
  requirements:
38
- - - "~>"
24
+ - - ">="
39
25
  - !ruby/object:Gem::Version
40
- version: 2.2.0
26
+ version: 1.2.0
41
27
  - !ruby/object:Gem::Dependency
42
- name: net-ssh
28
+ name: jsonpath
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 6.1.0
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
31
+ - - ">="
53
32
  - !ruby/object:Gem::Version
54
- version: 6.1.0
55
- - !ruby/object:Gem::Dependency
56
- name: net-sftp
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 3.0.0
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 3.0.0
69
- - !ruby/object:Gem::Dependency
70
- name: mysql2
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: 0.5.3
33
+ version: 1.1.0
76
34
  type: :runtime
77
35
  prerelease: false
78
36
  version_requirements: !ruby/object:Gem::Requirement
79
37
  requirements:
80
- - - "~>"
38
+ - - ">="
81
39
  - !ruby/object:Gem::Version
82
- version: 0.5.3
40
+ version: 1.1.0
83
41
  description: A DSL and command line tool to describe and run automated tests
84
42
  email:
85
43
  - me@christianneubauer.de
@@ -93,10 +51,8 @@ files:
93
51
  - lib/spectre/assertion.rb
94
52
  - lib/spectre/bag.rb
95
53
  - lib/spectre/curl.rb
96
- - lib/spectre/database/postgres.rb
97
54
  - lib/spectre/diagnostic.rb
98
55
  - lib/spectre/environment.rb
99
- - lib/spectre/ftp.rb
100
56
  - lib/spectre/helpers.rb
101
57
  - lib/spectre/http.rb
102
58
  - lib/spectre/http/basic_auth.rb
@@ -105,20 +61,18 @@ files:
105
61
  - lib/spectre/logger/console.rb
106
62
  - lib/spectre/logger/file.rb
107
63
  - lib/spectre/mixin.rb
108
- - lib/spectre/mysql.rb
109
64
  - lib/spectre/reporter/console.rb
110
65
  - lib/spectre/reporter/junit.rb
111
66
  - lib/spectre/resources.rb
112
- - lib/spectre/ssh.rb
113
- homepage: https://bitbucket.org/cneubaur/spectre-core
67
+ homepage: https://github.com/cneubauer/spectre-core
114
68
  licenses:
115
69
  - MIT
116
70
  metadata:
117
71
  allowed_push_host: https://rubygems.org/
118
- homepage_uri: https://bitbucket.org/cneubaur/spectre-core
119
- source_code_uri: https://bitbucket.org/cneubaur/spectre-core
120
- changelog_uri: https://bitbucket.org/cneubaur/spectre-core/src/master/CHANGELOG.md
121
- post_install_message:
72
+ homepage_uri: https://github.com/cneubauer/spectre-core
73
+ source_code_uri: https://github.com/cneubauer/spectre-core
74
+ changelog_uri: https://github.com/cneubauer/spectre-core/blob/master/CHANGELOG.md
75
+ post_install_message:
122
76
  rdoc_options: []
123
77
  require_paths:
124
78
  - lib
@@ -133,8 +87,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
87
  - !ruby/object:Gem::Version
134
88
  version: '0'
135
89
  requirements: []
136
- rubygems_version: 3.2.3
137
- signing_key:
90
+ rubygems_version: 3.0.8
91
+ signing_key:
138
92
  specification_version: 4
139
93
  summary: Describe and run automated tests
140
94
  test_files: []
@@ -1,78 +0,0 @@
1
- require 'pg'
2
-
3
-
4
- class PG::Result
5
- alias :count :ntuples
6
- end
7
-
8
-
9
- module Spectre
10
- module Database
11
- module Postgres
12
- @@modules = []
13
-
14
- class SQLStatement
15
- attr_accessor :query, :params
16
-
17
- def initialize
18
- @query = nil
19
- @params = []
20
- end
21
-
22
- def statement query
23
- @query = query
24
- end
25
-
26
- def param val
27
- @params << val
28
- end
29
- end
30
-
31
-
32
- class << self
33
- def postgres name, &block
34
- raise "postgres '#{name}' not configured" unless @@db_cfg.key? name
35
-
36
- statement = SQLStatement.new
37
- statement.instance_eval &block
38
-
39
- cfg = @@db_cfg[name]
40
-
41
- begin
42
- con = PG.connect({
43
- host: cfg['host'],
44
- port: cfg['port'],
45
- dbname: cfg['database'],
46
- user: cfg['username'],
47
- password: cfg['username'],
48
- })
49
-
50
- if statement.params
51
- @@result = con.exec_params(statement.query, statement.params)
52
- else
53
- @@result = con.exec(statement.query)
54
- end
55
-
56
- ensure
57
- con.close if con
58
- end
59
- end
60
-
61
-
62
- def result
63
- @@result
64
- end
65
- end
66
-
67
- Spectre.register do |config|
68
- @@db_cfg = {}
69
-
70
- config['postgres'].each do |name, cfg|
71
- @@db_cfg[name] = cfg
72
- end
73
- end
74
-
75
- Spectre.delegate :postgres, :result, to: self
76
- end
77
- end
78
- end
data/lib/spectre/ftp.rb DELETED
@@ -1,195 +0,0 @@
1
- require 'net/ftp'
2
- require 'net/sftp'
3
- require 'logger'
4
- require 'json'
5
-
6
-
7
- module Spectre
8
- module FTP
9
- @@cfg = {}
10
-
11
- class FTPConnection < DslClass
12
- def initialize host, username, password, opts, logger
13
- @__logger = logger
14
- @__session = nil
15
-
16
- @__host = host
17
- @__username = username
18
- @__password = password
19
- @__opts = opts
20
- end
21
-
22
- def connect!
23
- return unless @__session == nil or @__session.closed?
24
- @__logger.info "Connecting to '#{@__host}' with user '#{@__username}'"
25
- @__session = Net::FTP.new(@__host, @__opts)
26
- @__session.login @__username, @__password
27
- end
28
-
29
- def close
30
- return unless @__session and not @__session.closed?
31
- @__session.close
32
- end
33
-
34
- def can_connect?
35
- begin
36
- connect!
37
- return true
38
- rescue
39
- return false
40
- end
41
- end
42
-
43
- def download remotefile, to: File.basename(remotefile)
44
- connect!
45
- @__logger.info "Downloading '#{@__username}@#{@__host}:#{File.join @__session.pwd, remotefile}' to '#{File.expand_path to}'"
46
- @__session.getbinaryfile(remotefile, to)
47
- end
48
-
49
- def upload localfile, to: File.basename(localfile)
50
- connect!
51
- @__logger.info "Uploading '#{File.expand_path localfile}' to '#{@__username}@#{@__host}:#{File.join @__session.pwd, to}'"
52
- @__session.putbinaryfile(localfile, to)
53
- end
54
-
55
- def list
56
- connect!
57
- file_list = @__session.list
58
- @__logger.info "Listing file in #{@__session.pwd}\n#{file_list}"
59
- file_list
60
- end
61
- end
62
-
63
-
64
- class SFTPConnection < DslClass
65
- def initialize host, username, opts, logger
66
- opts[:non_interactive] = true
67
-
68
- @__logger = logger
69
- @__session = nil
70
- @__host = host
71
- @__username = username
72
- @__opts = opts
73
- end
74
-
75
- def connect!
76
- return unless @__session == nil or @__session.closed?
77
- @__logger.info "Connecting to '#{@__host}' with user '#{@__username}'"
78
- @__session = Net::SFTP.start(@__host, @__username, @__opts)
79
- @__session.connect!
80
- end
81
-
82
- def close
83
- return unless @__session and not @__session.closed?
84
- # @__session.close!
85
- end
86
-
87
- def can_connect?
88
- begin
89
- connect!
90
- return true
91
- rescue
92
- return false
93
- end
94
- end
95
-
96
- def download remotefile, to: File.basename(remotefile)
97
- @__logger.info "Downloading '#{@__username}@#{@__host}:#{remotefile}' to '#{File.expand_path to}'"
98
- connect!
99
- @__session.download!(remotefile, to)
100
- end
101
-
102
- def upload localfile, to: File.basename(localfile)
103
- @__logger.info "Uploading '#{File.expand_path localfile}' to '#{@__username}@#{@__host}:#{to}'"
104
- connect!
105
- @__session.upload!(localfile, to)
106
- end
107
-
108
- def stat path
109
- connect!
110
- file_info = @__session.stat! path
111
- @__logger.info "Stat '#{path}'\n#{JSON.pretty_generate file_info.attributes}"
112
- file_info.attributes
113
- end
114
-
115
- def exists path
116
- begin
117
- file_info = @__session.stat! path
118
-
119
- rescue Net::SFTP::StatusException => e
120
- return false if e.description == 'no such file'
121
- raise e
122
- end
123
-
124
- return true
125
- end
126
- end
127
-
128
-
129
- class << self
130
- def ftp name, config={}, &block
131
- raise "FTP connection '#{name}' not configured" unless @@cfg.key?(name) or config.count > 0
132
- cfg = @@cfg[name] || {}
133
-
134
- host = config[:host] || cfg['host'] || name
135
- username = config[:username] || cfg['username']
136
- password = config[:password] || cfg['password']
137
-
138
- opts = {}
139
- opts[:ssl] = config[:ssl]
140
- opts[:port] = config[:port] || cfg['port'] || 21
141
-
142
- @@logger.info "Connecting to #{host} with user #{username}"
143
-
144
- ftp_conn = FTPConnection.new(host, username, password, opts, @@logger)
145
-
146
- begin
147
- ftp_conn.instance_eval &block
148
- ensure
149
- ftp_conn.close
150
- end
151
- end
152
-
153
- def sftp name, config={}, &block
154
- raise "FTP connection '#{name}' not configured" unless @@cfg.key?(name) or config.count > 0
155
-
156
- cfg = @@cfg[name] || {}
157
-
158
- host = config[:host] || cfg['host'] || name
159
- username = config[:username] || cfg['username']
160
- password = config[:password] || cfg['password']
161
-
162
- opts = {}
163
- opts[:password] = password
164
- opts[:port] = config[:port] || cfg['port'] || 22
165
- opts[:keys] = [cfg['key']] if cfg.key? 'key'
166
- opts[:passphrase] = cfg['passphrase'] if cfg.key? 'passphrase'
167
-
168
- opts[:auth_methods] = []
169
- opts[:auth_methods].push 'publickey' if opts[:keys]
170
- opts[:auth_methods].push 'password' if opts[:password]
171
-
172
- sftp_con = SFTPConnection.new(host, username, opts, @@logger)
173
-
174
- begin
175
- sftp_con.instance_eval &block
176
- ensure
177
- sftp_con.close
178
- end
179
- end
180
- end
181
-
182
- Spectre.register do |config|
183
- @@logger = ::Logger.new config['log_file'], progname: 'spectre/ftp'
184
-
185
- if config.key? 'ftp'
186
-
187
- config['ftp'].each do |name, cfg|
188
- @@cfg[name] = cfg
189
- end
190
- end
191
- end
192
-
193
- Spectre.delegate :ftp, :sftp, to: self
194
- end
195
- end
data/lib/spectre/mysql.rb DELETED
@@ -1,97 +0,0 @@
1
- require 'mysql2'
2
-
3
- module Spectre
4
- module MySQL
5
-
6
- class MySqlQuery < DslClass
7
- def initialize query
8
- @__query = query
9
- end
10
-
11
- def host hostname
12
- @__query['host'] = hostname
13
- end
14
-
15
- def username user
16
- @__query['username'] = user
17
- end
18
-
19
- def password pass
20
- @__query['password'] = pass
21
- end
22
-
23
- def database name
24
- @__query['database'] = name
25
- end
26
-
27
- def query statement
28
- @__query['query'] = [] if not @__query.key? 'query'
29
- @__query['query'].append(statement)
30
- end
31
- end
32
-
33
- class << self
34
- @@mysql_cfg = {}
35
- @@result = nil
36
- @@last_conn = nil
37
-
38
- def mysql name = nil, &block
39
- query = {}
40
-
41
- if name != nil and @@mysql_cfg.key? name
42
- query.merge! @@mysql_cfg[name]
43
- raise "No `host' set for MySQL client '#{name}'. Check your MySQL config in your environment." if !query['host']
44
- elsif name != nil
45
- query['host'] = name
46
- elsif @@last_conn == nil
47
- raise 'No name given and there was no previous MySQL connection to use'
48
- end
49
-
50
- MySqlQuery.new(query).instance_eval(&block) if block_given?
51
-
52
- if name != nil
53
- @@last_conn = {
54
- host: query['host'],
55
- username: query['username'],
56
- password: query['password'],
57
- database: query['database']
58
- }
59
- end
60
-
61
- @@logger.info "Connecting to database #{query['username']}@#{query['host']}:#{query['database']}"
62
-
63
- client = ::Mysql2::Client.new(**@@last_conn)
64
-
65
- res = []
66
-
67
- query['query'].each do |statement|
68
- @@logger.info 'Executing statement "' + statement + '"'
69
- res = client.query(statement, cast_booleans: true)
70
- end if query['query']
71
-
72
- @@result = res.map { |row| OpenStruct.new row } if res
73
-
74
- client.close
75
- end
76
-
77
- def result
78
- raise 'No MySQL query has been executed yet' unless @@result
79
- @@result
80
- end
81
- end
82
-
83
- Spectre.register do |config|
84
- @@logger = ::Logger.new config['log_file'], progname: 'spectre/mysql'
85
-
86
- if config.key? 'mysql'
87
- @@mysql_cfg = {}
88
-
89
- config['mysql'].each do |name, cfg|
90
- @@mysql_cfg[name] = cfg
91
- end
92
- end
93
- end
94
-
95
- Spectre.delegate :mysql, :result, to: self
96
- end
97
- end
data/lib/spectre/ssh.rb DELETED
@@ -1,149 +0,0 @@
1
- require 'net/ssh'
2
- require 'logger'
3
-
4
-
5
- module Spectre
6
- module SSH
7
- @@cfg = {}
8
-
9
- class SSHConnection < DslClass
10
- def initialize host, username, opts, logger
11
- opts[:non_interactive] = true
12
-
13
- @__logger = logger
14
- @__host = host
15
- @__username = username
16
- @__opts = opts
17
- @__session = nil
18
- @__exit_code = nil
19
- @__output = ''
20
- end
21
-
22
- def file_exists path
23
- exec "ls #{path}"
24
- exit_code == 0
25
- end
26
-
27
- def owner_of path
28
- exec "stat -c %U #{path}"
29
- output.chomp
30
- end
31
-
32
- def connect!
33
- return unless @__session == nil or @__session.closed?
34
- @__session = Net::SSH.start(@__host, @__username, @__opts)
35
- end
36
-
37
- def close
38
- return unless @__session and not @__session.closed?
39
- @__session.close
40
- end
41
-
42
- def can_connect?
43
- @__output = nil
44
-
45
- begin
46
- connect!
47
- @__session.open_channel.close
48
- @__output = "successfully connected to #{@__host} with user #{@__username}"
49
- @__exit_code = 0
50
- return true
51
- rescue Exception => e
52
- @__logger.error e.message
53
- @__output = "unable to connect to #{@__host} with user #{@__username}"
54
- @__exit_code = 1
55
- end
56
-
57
- return false
58
- end
59
-
60
- def exec command
61
- connect!
62
-
63
- log_str = "#{@__session.options[:user]}@#{@__session.host} -p #{@__session.options[:port]} #{command}"
64
-
65
- @channel = @__session.open_channel do |channel|
66
- channel.exec(command) do |ch, success|
67
- abort "could not execute #{command} on #{@__session.host}" unless success
68
-
69
- @__output = ''
70
-
71
- channel.on_data do |ch, data|
72
- @__output += data
73
- end
74
-
75
- channel.on_extended_data do |ch,type,data|
76
- @__output += data
77
- end
78
-
79
- channel.on_request('exit-status') do |ch, data|
80
- @__exit_code = data.read_long
81
- end
82
-
83
- # channel.on_request('exit-signal') do |ch, data|
84
- # exit_code = data.read_long
85
- # end
86
- end
87
-
88
- end
89
-
90
- @channel.wait
91
- @__session.loop
92
-
93
- log_str += "\n" + @__output
94
- @__logger.info log_str
95
- end
96
-
97
- def output
98
- @__output
99
- end
100
-
101
- def exit_code
102
- @__exit_code
103
- end
104
- end
105
-
106
-
107
- class << self
108
- def ssh name, config = {}, &block
109
- raise "SSH connection '#{name}' not configured" unless @@cfg.key?(name) or config.count > 0
110
-
111
- cfg = @@cfg[name] || {}
112
-
113
- host = cfg['host'] || name
114
- username = config[:username] || cfg['username']
115
- password = config[:password] || cfg['password']
116
-
117
- opts = {}
118
- opts[:password] = password
119
- opts[:port] = config[:port] || cfg['port'] || 22
120
- opts[:keys] = [cfg['key']] if cfg.key? 'key'
121
- opts[:passphrase] = cfg['passphrase'] if cfg.key? 'passphrase'
122
-
123
- opts[:auth_methods] = []
124
- opts[:auth_methods].push 'publickey' if opts[:keys]
125
- opts[:auth_methods].push 'password' if opts[:password]
126
-
127
- ssh_con = SSHConnection.new(host, username, opts, @@logger)
128
-
129
- begin
130
- ssh_con.instance_eval &block
131
- ensure
132
- ssh_con.close
133
- end
134
- end
135
- end
136
-
137
- Spectre.register do |config|
138
- @@logger = ::Logger.new config['log_file'], progname: 'spectre/ssh'
139
-
140
- if config.key? 'ssh'
141
- config['ssh'].each do |name, cfg|
142
- @@cfg[name] = cfg
143
- end
144
- end
145
- end
146
-
147
- Spectre.delegate :ssh, to: self
148
- end
149
- end