pdi 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.
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-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
+ module Pdi
11
+ class Spoon
12
+ # This class knows how to parse feedback from Pentaho and make sense of it.
13
+ class Parser
14
+ NEW_LINE = "\n"
15
+
16
+ def version(string)
17
+ string.to_s
18
+ .chomp
19
+ .split(NEW_LINE)
20
+ .last
21
+ .to_s
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-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
+ module Pdi
11
+ class Spoon
12
+ # General return object for wrapping up a execution call result (execution) and
13
+ # a usable result (value)
14
+ class Result
15
+ attr_reader :execution, :value
16
+
17
+ def initialize(execution, value)
18
+ @execution = execution
19
+ @value = value
20
+
21
+ freeze
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-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
+ module Pdi
11
+ VERSION = '2.0.0-alpha'
12
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './lib/pdi/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'pdi'
7
+ s.version = Pdi::VERSION
8
+ s.summary = 'Ruby wrapper for invoking Pentaho Data Integration'
9
+
10
+ s.description = <<-DESCRIPTION
11
+ Pentaho Data Integration allows for the creation of ETL transformation and jobs. This library allows those ETL tasks to be executed from Ruby.
12
+ DESCRIPTION
13
+
14
+ s.authors = ['Matthew Ruggio']
15
+ s.email = ['mruggio@bluemarblepayroll.com']
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
19
+ s.homepage = 'https://github.com/bluemarblepayroll/pdi'
20
+ s.license = 'MIT'
21
+
22
+ s.required_ruby_version = '>= 2.3.8'
23
+
24
+ s.add_dependency('acts_as_hashable', '~>1')
25
+
26
+ s.add_development_dependency('guard-rspec', '~>4.7')
27
+ s.add_development_dependency('pry', '~>0')
28
+ s.add_development_dependency('rake', '~> 13')
29
+ s.add_development_dependency('rspec')
30
+ s.add_development_dependency('rubocop', '~>0.79.0')
31
+ s.add_development_dependency('simplecov', '~>0.17.0')
32
+ s.add_development_dependency('simplecov-console', '~>0.6.0')
33
+ end
@@ -0,0 +1,14 @@
1
+ #!/bin/bash
2
+
3
+ error(){
4
+ echo "$1" >&2
5
+ }
6
+
7
+ output(){
8
+ echo "$1"
9
+ }
10
+
11
+ output "output to stdout"
12
+ error "output to sterr"
13
+
14
+ exit $1
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+
3
+ echo 'std_out'
4
+ echo 'err_out' >&2
5
+
6
+ sleep $1
7
+
8
+ echo 'after_sleep'
9
+
10
+ exit $2
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+
3
+ echo 'random info'
4
+ echo 'random info'
5
+ echo 'random info'
6
+ echo 'random info'
7
+ echo 'random info'
8
+ echo '2020/01/30 13:31:04 - Pan - Kettle version 6.1.0.1-196, build 1, build date : 2016-04-07 12.08.49'
9
+
10
+ exit 0
@@ -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
@@ -0,0 +1,42 @@
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::Spoon::KitchenError do
13
+ describe 'initialization' do
14
+ [1, 2, 7, 8, 9].each do |code|
15
+ specify "code #{code} should have message" do
16
+ result = Pdi::Executor::Result.new(
17
+ args: [],
18
+ status: {
19
+ code: code,
20
+ pid: 123
21
+ }
22
+ )
23
+
24
+ expect(described_class.new(result).message).not_to eq('Unknown')
25
+ end
26
+ end
27
+
28
+ [-1, 0, 3, 4, 5, 6, 10, 11].each do |code|
29
+ specify "code #{code} should not have message" do
30
+ result = Pdi::Executor::Result.new(
31
+ args: [],
32
+ status: {
33
+ code: code,
34
+ pid: 123
35
+ }
36
+ )
37
+
38
+ expect(described_class.new(result).message).to eq('Unknown')
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,73 @@
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::Spoon::Options::Arg do
13
+ let(:key) { :param }
14
+ let(:value) { 'v1' }
15
+ let(:value_with_space) { 'v 1' }
16
+
17
+ describe '#initialize' do
18
+ subject { described_class.new(key, value) }
19
+
20
+ it 'requires a key' do
21
+ expect { described_class.new('') }.to raise_error(ArgumentError)
22
+ end
23
+
24
+ it 'sets key' do
25
+ expect(subject.key).to eq(key)
26
+ end
27
+
28
+ it 'sets value' do
29
+ expect(subject.value).to eq(value)
30
+ end
31
+ end
32
+
33
+ describe '#to_s' do
34
+ it 'works without a value' do
35
+ subject = described_class.new(key)
36
+ expected = "-#{key}"
37
+
38
+ expect(subject.to_s).to eq(expected)
39
+ end
40
+
41
+ it 'works with a value (with no space)' do
42
+ subject = described_class.new(key, value)
43
+ expected = "-#{key}:#{value}"
44
+
45
+ expect(subject.to_s).to eq(expected)
46
+ end
47
+
48
+ it 'works with a value (with a space)' do
49
+ subject = described_class.new(key, value_with_space)
50
+ expected = "\"-#{key}:#{value_with_space}\""
51
+
52
+ expect(subject.to_s).to eq(expected)
53
+ end
54
+ end
55
+
56
+ describe 'equality' do
57
+ let(:subject2) { described_class.new(key, value) }
58
+
59
+ subject { described_class.new(key, value) }
60
+
61
+ specify '#hash compares key and value' do
62
+ expect(subject.hash).to eq(subject2.hash)
63
+ end
64
+
65
+ specify '#== compares #to_s values' do
66
+ expect(subject).to eq(subject2)
67
+ end
68
+
69
+ specify '#eql? compares #to_s values' do
70
+ expect(subject).to eql(subject2)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,39 @@
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::Spoon::Options::Param do
13
+ let(:key) { 'k1' }
14
+ let(:value) { 'v1' }
15
+ let(:value_with_space) { 'v 1' }
16
+
17
+ describe '#to_s' do
18
+ it 'works without a value' do
19
+ subject = described_class.new(key)
20
+ expected = "-param:#{key}="
21
+
22
+ expect(subject.to_s).to eq(expected)
23
+ end
24
+
25
+ it 'works with a value (with no space)' do
26
+ subject = described_class.new(key, value)
27
+ expected = "-param:#{key}=#{value}"
28
+
29
+ expect(subject.to_s).to eq(expected)
30
+ end
31
+
32
+ it 'works with a value (with a space)' do
33
+ subject = described_class.new(key, value_with_space)
34
+ expected = "\"-param:#{key}=#{value_with_space}\""
35
+
36
+ expect(subject.to_s).to eq(expected)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,102 @@
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::Spoon::Options do
13
+ describe '#to_args' do
14
+ let(:params) do
15
+ {
16
+ key1: 'value1',
17
+ key2: 'value2',
18
+ key3: 'value with spaces'
19
+ }
20
+ end
21
+
22
+ let(:repository) { 'some repo' }
23
+ let(:name) { 'some_transformation' }
24
+
25
+ subject do
26
+ described_class.new(
27
+ params: params,
28
+ repository: repository,
29
+ name: name,
30
+ type: type
31
+ )
32
+ end
33
+
34
+ context 'when type is transformation' do
35
+ let(:type) { 'transformation' }
36
+
37
+ it 'wraps any args with spaces inside double quotes' do
38
+ args = subject.to_args
39
+ args_with_spaces = args.select { |a| a.to_s.include?(' ') }
40
+
41
+ raise ArgumentError, 'no examples to assert!' if args_with_spaces.empty?
42
+
43
+ args_with_spaces.each do |arg|
44
+ actual = arg.to_s
45
+
46
+ expect(actual).to start_with('"')
47
+ expect(actual).to end_with('"')
48
+ end
49
+ end
50
+
51
+ it 'includes each option' do
52
+ expected = [
53
+ '"-rep:some repo"',
54
+ '-trans:some_transformation',
55
+ '-level:Basic',
56
+ '-param:key1=value1',
57
+ '-param:key2=value2',
58
+ '"-param:key3=value with spaces"'
59
+ ]
60
+
61
+ expected_set = Set[*expected]
62
+ actual_set = Set[*subject.to_args.map(&:to_s)]
63
+
64
+ expect(actual_set).to eq(expected_set)
65
+ end
66
+ end
67
+
68
+ context 'when type is job' do
69
+ let(:type) { 'job' }
70
+
71
+ it 'wraps any args with spaces inside double quotes' do
72
+ args = subject.to_args
73
+ args_with_spaces = args.select { |a| a.to_s.include?(' ') }
74
+
75
+ raise ArgumentError, 'no examples to assert!' if args_with_spaces.empty?
76
+
77
+ args_with_spaces.each do |arg|
78
+ actual = arg.to_s
79
+
80
+ expect(actual).to start_with('"')
81
+ expect(actual).to end_with('"')
82
+ end
83
+ end
84
+
85
+ it 'includes each option' do
86
+ expected = [
87
+ '"-rep:some repo"',
88
+ '-job:some_transformation',
89
+ '-level:Basic',
90
+ '-param:key1=value1',
91
+ '-param:key2=value2',
92
+ '"-param:key3=value with spaces"'
93
+ ]
94
+
95
+ expected_set = Set[*expected]
96
+ actual_set = Set[*subject.to_args.map(&:to_s)]
97
+
98
+ expect(actual_set).to eq(expected_set)
99
+ end
100
+ end
101
+ end
102
+ end