pdi 1.0.1 → 2.0.0.pre.alpha
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/CHANGELOG.md +10 -0
- data/README.md +1 -0
- data/lib/pdi.rb +2 -0
- data/lib/pdi/executor.rb +33 -11
- data/lib/pdi/executor/result.rb +1 -1
- data/lib/pdi/executor/status.rb +2 -3
- data/lib/pdi/spoon.rb +3 -2
- data/lib/pdi/version.rb +1 -1
- data/spec/mocks/spoon/sleep.sh +10 -0
- data/spec/pdi/executor_spec.rb +52 -0
- data/spec/pdi/spoon_spec.rb +17 -4
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3adae07a9c634b7075a87a47c810c0d4e3c90137ee85a08e01e09038baf990e1
|
4
|
+
data.tar.gz: 9f7ecf0e06ace02def29a7e710ea87d5ed5e2af82282a1dba935fa3628116533
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5104d4d97f12a70e7f2d492dee6f8f870c388fea8091bc26d60fd87efb826331479a5efa851de7cbeb278d48aad9368d12cbad7bbb675b9cd9a20baee50f087e
|
7
|
+
data.tar.gz: 3ff6caa7e64806a1f03f918b7a6692e25c7493aa6280c0f9edabc99dd937e8890d76f3e8e0f060584964b993791c990621dc3cd8c908f91b5e81a25ac3e9f5ff
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# 2.0.0 (May 7th, 2020)
|
2
|
+
|
3
|
+
Breaking Changes:
|
4
|
+
|
5
|
+
* Standard error and output have been combined into one stream (out). Early feedback indicated that reading both at the same time was preferable.
|
6
|
+
|
7
|
+
Enhancements:
|
8
|
+
|
9
|
+
* Added optional `timeout_in_seconds` argument to Pdi::Spoon#initialize.
|
10
|
+
|
1
11
|
# 1.0.1 (February 19th, 2020)
|
2
12
|
|
3
13
|
Fixes:
|
data/README.md
CHANGED
@@ -50,6 +50,7 @@ Notes:
|
|
50
50
|
|
51
51
|
* You can also override the names of the scripts using the `kitchen` and `pan` constructor keyword arguments. The defaults are `kitchen.sh` and `pan.sh`, respectively.
|
52
52
|
* For other command line arguments that are not supported first-class in the Options objects below you can utilize the `args` argument when instantiating a `Spoon` instance.
|
53
|
+
* Another optional argument is `timeout_in_seconds`. If set it will ensure the sub-process runs within a given window. If it times out the sub-process will be terminated and a Timeout::Error will be raised.
|
53
54
|
|
54
55
|
### Executing a Job/Transformation
|
55
56
|
|
data/lib/pdi.rb
CHANGED
data/lib/pdi/executor.rb
CHANGED
@@ -13,20 +13,42 @@ module Pdi
|
|
13
13
|
# This class is the library's "metal" layer, the one which actually makes the system call and
|
14
14
|
# interacts with the operating system (through Ruby's standard library.)
|
15
15
|
class Executor
|
16
|
+
attr_reader :timeout_in_seconds
|
17
|
+
|
18
|
+
def initialize(timeout_in_seconds: nil)
|
19
|
+
@timeout_in_seconds = timeout_in_seconds
|
20
|
+
|
21
|
+
freeze
|
22
|
+
end
|
23
|
+
|
16
24
|
def run(args)
|
17
25
|
args = Array(args).map(&:to_s)
|
18
26
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
IO.popen(args, err: %i[child out]) do |io|
|
28
|
+
begin
|
29
|
+
io_read =
|
30
|
+
if timeout_in_seconds
|
31
|
+
Timeout.timeout(timeout_in_seconds) { io.read }
|
32
|
+
else
|
33
|
+
io.read
|
34
|
+
end
|
35
|
+
|
36
|
+
io.close
|
37
|
+
status = $CHILD_STATUS
|
38
|
+
|
39
|
+
Result.new(
|
40
|
+
args: args,
|
41
|
+
status: {
|
42
|
+
code: status.exitstatus,
|
43
|
+
out: io_read,
|
44
|
+
pid: status.pid
|
45
|
+
}
|
46
|
+
)
|
47
|
+
rescue Timeout::Error => e
|
48
|
+
Process.kill(9, io.pid)
|
49
|
+
raise e
|
50
|
+
end
|
51
|
+
end
|
30
52
|
end
|
31
53
|
end
|
32
54
|
end
|
data/lib/pdi/executor/result.rb
CHANGED
data/lib/pdi/executor/status.rb
CHANGED
@@ -13,12 +13,11 @@ module Pdi
|
|
13
13
|
class Status
|
14
14
|
acts_as_hashable
|
15
15
|
|
16
|
-
attr_reader :code, :out, :
|
16
|
+
attr_reader :code, :out, :pid
|
17
17
|
|
18
|
-
def initialize(code:, out: '',
|
18
|
+
def initialize(code:, out: '', pid:)
|
19
19
|
@code = code
|
20
20
|
@out = out
|
21
|
-
@err = err
|
22
21
|
@pid = pid
|
23
22
|
|
24
23
|
freeze
|
data/lib/pdi/spoon.rb
CHANGED
@@ -30,7 +30,8 @@ module Pdi
|
|
30
30
|
args: [],
|
31
31
|
dir:,
|
32
32
|
kitchen: DEFAULT_KITCHEN,
|
33
|
-
pan: DEFAULT_PAN
|
33
|
+
pan: DEFAULT_PAN,
|
34
|
+
timeout_in_seconds: nil
|
34
35
|
)
|
35
36
|
assert_required(:dir, dir)
|
36
37
|
assert_required(:kitchen, kitchen)
|
@@ -40,7 +41,7 @@ module Pdi
|
|
40
41
|
@dir = File.expand_path(dir.to_s)
|
41
42
|
@kitchen = kitchen.to_s
|
42
43
|
@pan = pan.to_s
|
43
|
-
@executor = Executor.new
|
44
|
+
@executor = Executor.new(timeout_in_seconds: timeout_in_seconds)
|
44
45
|
@parser = Parser.new
|
45
46
|
|
46
47
|
freeze
|
data/lib/pdi/version.rb
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2018-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
describe Pdi::Executor do
|
13
|
+
let(:script) { File.join('spec', 'mocks', 'spoon', 'sleep.sh') }
|
14
|
+
let(:one_second) { 1 }
|
15
|
+
let(:return_code) { 33 }
|
16
|
+
|
17
|
+
describe '#run' do
|
18
|
+
context 'with a timeout' do
|
19
|
+
# do not make these too high, bugs could cause the entire script to still be executed without
|
20
|
+
# killing it so these high values could draw out results.
|
21
|
+
let(:thirty_seconds) { 30 }
|
22
|
+
|
23
|
+
subject { described_class.new(timeout_in_seconds: one_second) }
|
24
|
+
|
25
|
+
# This will run a script that will take 30 seconds to process, but by limiting the
|
26
|
+
# timeout using the #run argument, it should raise an error after one second.
|
27
|
+
it 'times out and kills process after 5 seconds' do
|
28
|
+
args = [script, thirty_seconds]
|
29
|
+
|
30
|
+
expect { subject.run(args) }.to raise_error(Timeout::Error)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'without a timeout' do
|
35
|
+
it 'returns right exit status as code' do
|
36
|
+
args = [script, one_second, return_code]
|
37
|
+
|
38
|
+
result = subject.run(args)
|
39
|
+
|
40
|
+
expect(result.code).to eq(return_code)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns right standard output and error as out' do
|
44
|
+
args = [script, one_second, return_code]
|
45
|
+
|
46
|
+
result = subject.run(args)
|
47
|
+
|
48
|
+
expect(result.out).to eq("std_out\nerr_out\nafter_sleep\n")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/spec/pdi/spoon_spec.rb
CHANGED
@@ -14,6 +14,21 @@ describe Pdi::Spoon do
|
|
14
14
|
let(:mocks_dir) { %w[spec mocks spoon] }
|
15
15
|
let(:dir) { File.join(*mocks_dir) }
|
16
16
|
|
17
|
+
describe '#initialize' do
|
18
|
+
it 'sets executor' do
|
19
|
+
timeout_in_seconds = 987
|
20
|
+
|
21
|
+
subject = described_class.new(dir: dir, timeout_in_seconds: timeout_in_seconds)
|
22
|
+
|
23
|
+
# Private/internal testing is not recommended, but I really wanted to ensure
|
24
|
+
# this class is properly configuring the Executor instance, that way I can rely
|
25
|
+
# mainly on the Executor unit tests instead of integration tests at this level.
|
26
|
+
executor = subject.send('executor')
|
27
|
+
|
28
|
+
expect(executor.timeout_in_seconds).to eq(timeout_in_seconds)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
17
32
|
describe '#run' do
|
18
33
|
context 'transformations' do
|
19
34
|
let(:options) do
|
@@ -43,8 +58,7 @@ describe Pdi::Spoon do
|
|
43
58
|
|
44
59
|
result = subject.run(options)
|
45
60
|
|
46
|
-
expect(result.out).to eq("output to stdout\n")
|
47
|
-
expect(result.err).to eq("output to sterr\n")
|
61
|
+
expect(result.out).to eq("output to stdout\noutput to sterr\n")
|
48
62
|
expect(result.code).to eq(0)
|
49
63
|
end
|
50
64
|
end
|
@@ -97,8 +111,7 @@ describe Pdi::Spoon do
|
|
97
111
|
|
98
112
|
result = subject.run(options)
|
99
113
|
|
100
|
-
expect(result.out).to eq("output to stdout\n")
|
101
|
-
expect(result.err).to eq("output to sterr\n")
|
114
|
+
expect(result.out).to eq("output to stdout\noutput to sterr\n")
|
102
115
|
expect(result.code).to eq(0)
|
103
116
|
end
|
104
117
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.pre.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Ruggio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-05-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acts_as_hashable
|
@@ -160,7 +160,9 @@ files:
|
|
160
160
|
- lib/pdi/version.rb
|
161
161
|
- pdi.gemspec
|
162
162
|
- spec/mocks/spoon/return_code.sh
|
163
|
+
- spec/mocks/spoon/sleep.sh
|
163
164
|
- spec/mocks/spoon/version.sh
|
165
|
+
- spec/pdi/executor_spec.rb
|
164
166
|
- spec/pdi/spoon/kitchen_error_spec.rb
|
165
167
|
- spec/pdi/spoon/options/arg_spec.rb
|
166
168
|
- spec/pdi/spoon/options/param_spec.rb
|
@@ -183,9 +185,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
185
|
version: 2.3.8
|
184
186
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
185
187
|
requirements:
|
186
|
-
- - "
|
188
|
+
- - ">"
|
187
189
|
- !ruby/object:Gem::Version
|
188
|
-
version:
|
190
|
+
version: 1.3.1
|
189
191
|
requirements: []
|
190
192
|
rubygems_version: 3.0.3
|
191
193
|
signing_key:
|
@@ -193,7 +195,9 @@ specification_version: 4
|
|
193
195
|
summary: Ruby wrapper for invoking Pentaho Data Integration
|
194
196
|
test_files:
|
195
197
|
- spec/mocks/spoon/return_code.sh
|
198
|
+
- spec/mocks/spoon/sleep.sh
|
196
199
|
- spec/mocks/spoon/version.sh
|
200
|
+
- spec/pdi/executor_spec.rb
|
197
201
|
- spec/pdi/spoon/kitchen_error_spec.rb
|
198
202
|
- spec/pdi/spoon/options/arg_spec.rb
|
199
203
|
- spec/pdi/spoon/options/param_spec.rb
|