train 0.28.0 → 0.29.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -2
  3. data/lib/train/extras.rb +0 -5
  4. data/lib/train/extras/os_common.rb +1 -1
  5. data/lib/train/extras/os_detect_unix.rb +6 -0
  6. data/lib/train/{extras/file_common.rb → file.rb} +65 -92
  7. data/lib/train/file/local.rb +70 -0
  8. data/lib/train/file/local/unix.rb +77 -0
  9. data/lib/train/file/local/windows.rb +63 -0
  10. data/lib/train/file/remote.rb +28 -0
  11. data/lib/train/file/remote/aix.rb +21 -0
  12. data/lib/train/file/remote/linux.rb +19 -0
  13. data/lib/train/file/remote/qnx.rb +41 -0
  14. data/lib/train/file/remote/unix.rb +110 -0
  15. data/lib/train/file/remote/windows.rb +94 -0
  16. data/lib/train/plugins/base_connection.rb +2 -1
  17. data/lib/train/transports/docker.rb +8 -1
  18. data/lib/train/transports/local.rb +6 -2
  19. data/lib/train/transports/mock.rb +7 -6
  20. data/lib/train/transports/ssh.rb +1 -2
  21. data/lib/train/transports/ssh_connection.rb +24 -4
  22. data/lib/train/transports/winrm_connection.rb +11 -5
  23. data/lib/train/version.rb +1 -1
  24. data/test/integration/tests/path_block_device_test.rb +2 -2
  25. data/test/integration/tests/path_character_device_test.rb +2 -2
  26. data/test/integration/tests/path_file_test.rb +2 -2
  27. data/test/integration/tests/path_folder_test.rb +5 -5
  28. data/test/integration/tests/path_missing_test.rb +0 -1
  29. data/test/integration/tests/path_pipe_test.rb +2 -3
  30. data/test/integration/tests/path_symlink_test.rb +2 -2
  31. data/test/unit/extras/os_detect_linux_test.rb +3 -3
  32. data/test/unit/extras/os_detect_windows_test.rb +1 -1
  33. data/test/unit/file/local/unix_test.rb +112 -0
  34. data/test/unit/file/local/windows_test.rb +41 -0
  35. data/test/unit/file/local_test.rb +110 -0
  36. data/test/unit/{extras/linux_file_test.rb → file/remote/linux_test.rb} +7 -7
  37. data/test/unit/file/remote/unix_test.rb +44 -0
  38. data/test/unit/file/remote_test.rb +62 -0
  39. data/test/unit/file_test.rb +156 -0
  40. data/test/unit/plugins/transport_test.rb +1 -1
  41. data/test/unit/transports/mock_test.rb +3 -3
  42. data/test/windows/local_test.rb +106 -0
  43. data/test/windows/winrm_test.rb +125 -0
  44. metadata +26 -16
  45. data/lib/train/extras/file_aix.rb +0 -20
  46. data/lib/train/extras/file_linux.rb +0 -16
  47. data/lib/train/extras/file_unix.rb +0 -79
  48. data/lib/train/extras/file_windows.rb +0 -100
  49. data/lib/train/transports/local_file.rb +0 -98
  50. data/test/unit/extras/file_common_test.rb +0 -180
  51. data/test/unit/extras/windows_file_test.rb +0 -44
  52. data/test/unit/transports/local_file_test.rb +0 -202
@@ -1,15 +1,15 @@
1
- # encoding: utf-8
2
1
  require 'helper'
2
+ require 'train/transports/local'
3
+ require 'train/file/remote/linux'
3
4
  require 'train/transports/mock'
4
- require 'train/extras'
5
5
 
6
- describe 'file common' do
7
- let(:cls) { Train::Extras::LinuxFile }
6
+ describe Train::File::Remote::Linux do
7
+ let(:cls) { Train::File::Remote::Linux }
8
8
  let(:backend) {
9
9
  backend = Train::Transports::Mock.new.connection
10
10
  backend.mock_os({ family: 'linux' })
11
11
  backend
12
- }
12
+ }
13
13
 
14
14
  def mock_stat(args, out, err = '', code = 0)
15
15
  backend.mock_command(
@@ -39,7 +39,7 @@ describe 'file common' do
39
39
  it 'reads file contents' do
40
40
  backend.mock_command('cat path || echo -n', '')
41
41
  mock_stat('-L path', '', 'some error...', 1)
42
- cls.new(backend, 'path').content.must_equal nil
42
+ cls.new(backend, 'path').content.must_be_nil
43
43
  end
44
44
 
45
45
  it 'checks for file existance' do
@@ -164,4 +164,4 @@ describe 'file common' do
164
164
  f.selinux_label.must_equal 'labels'
165
165
  end
166
166
  end
167
- end
167
+ end
@@ -0,0 +1,44 @@
1
+ require 'helper'
2
+ require 'train/file/remote/unix'
3
+
4
+ describe Train::File::Remote::Unix do
5
+ let(:cls) { Train::File::Remote::Unix }
6
+
7
+ def mockup(stubs)
8
+ Class.new(cls) do
9
+ stubs.each do |k,v|
10
+ define_method k.to_sym do
11
+ v
12
+ end
13
+ end
14
+ end.new(nil, nil, false)
15
+ end
16
+
17
+ describe 'unix_mode_mask' do
18
+ let(:fc) { mockup(type: :file) }
19
+
20
+ it 'check owner mode calculation' do
21
+ fc.unix_mode_mask('owner', 'x').must_equal 0100
22
+ fc.unix_mode_mask('owner', 'w').must_equal 0200
23
+ fc.unix_mode_mask('owner', 'r').must_equal 0400
24
+ end
25
+
26
+ it 'check group mode calculation' do
27
+ fc.unix_mode_mask('group', 'x').must_equal 0010
28
+ fc.unix_mode_mask('group', 'w').must_equal 0020
29
+ fc.unix_mode_mask('group', 'r').must_equal 0040
30
+ end
31
+
32
+ it 'check other mode calculation' do
33
+ fc.unix_mode_mask('other', 'x').must_equal 0001
34
+ fc.unix_mode_mask('other', 'w').must_equal 0002
35
+ fc.unix_mode_mask('other', 'r').must_equal 0004
36
+ end
37
+
38
+ it 'check all mode calculation' do
39
+ fc.unix_mode_mask('all', 'x').must_equal 0111
40
+ fc.unix_mode_mask('all', 'w').must_equal 0222
41
+ fc.unix_mode_mask('all', 'r').must_equal 0444
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,62 @@
1
+ require 'helper'
2
+ require 'train/file/remote'
3
+
4
+ describe Train::File::Remote do
5
+ let(:cls) { Train::File::Remote }
6
+
7
+ def mockup(stubs)
8
+ Class.new(cls) do
9
+ stubs.each do |k,v|
10
+ define_method k.to_sym do
11
+ v
12
+ end
13
+ end
14
+ end.new(nil, nil, false)
15
+ end
16
+
17
+ describe 'basename helper' do
18
+ def fc(path)
19
+ mockup(type: :file, path: path)
20
+ end
21
+
22
+ it 'works with an empty path' do
23
+ fc('').basename.must_equal ''
24
+ end
25
+
26
+ it 'separates a simple path (defaults to unix mode)' do
27
+ fc('/dir/file').basename.must_equal 'file'
28
+ end
29
+
30
+ it 'separates a simple path (Unix mode)' do
31
+ fc('/dir/file').basename(nil, '/').must_equal 'file'
32
+ end
33
+
34
+ it 'separates a simple path (Windows mode)' do
35
+ fc('C:\dir\file').basename(nil, '\\').must_equal 'file'
36
+ end
37
+
38
+ it 'identifies a folder name (Unix mode)' do
39
+ fc('/dir/file/').basename(nil, '/').must_equal 'file'
40
+ end
41
+
42
+ it 'identifies a folder name (Windows mode)' do
43
+ fc('C:\dir\file\\').basename(nil, '\\').must_equal 'file'
44
+ end
45
+
46
+ it 'ignores tailing separators (Unix mode)' do
47
+ fc('/dir/file///').basename(nil, '/').must_equal 'file'
48
+ end
49
+
50
+ it 'ignores tailing separators (Windows mode)' do
51
+ fc('C:\dir\file\\\\\\').basename(nil, '\\').must_equal 'file'
52
+ end
53
+
54
+ it 'doesnt work with backward slashes (Unix mode)' do
55
+ fc('C:\dir\file').basename(nil, '/').must_equal 'C:\\dir\file'
56
+ end
57
+
58
+ it 'doesnt work with forward slashes (Windows mode)' do
59
+ fc('/dir/file').basename(nil, '\\').must_equal '/dir/file'
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,156 @@
1
+ require 'helper'
2
+
3
+ describe Train::File do
4
+ let(:cls) { Train::File }
5
+ let(:new_cls) { cls.new(nil, '/temp/file', false) }
6
+
7
+ def mockup(stubs)
8
+ Class.new(cls) do
9
+ stubs.each do |k,v|
10
+ define_method k.to_sym do
11
+ v
12
+ end
13
+ end
14
+ end.new(nil, nil, false)
15
+ end
16
+
17
+ it 'has the default type of unknown' do
18
+ new_cls.type.must_equal :unknown
19
+ end
20
+
21
+ it 'calculates md5sum from content' do
22
+ content = 'hello world'
23
+ new_cls.stub :content, content do |i|
24
+ i.md5sum.must_equal '5eb63bbbe01eeed093cb22bb8f5acdc3'
25
+ end
26
+ end
27
+
28
+ it 'sets md5sum of nil content to nil' do
29
+ new_cls.stub :content, nil do |i|
30
+ i.md5sum.must_be_nil
31
+ end
32
+ end
33
+
34
+ it 'calculates sha256sum from content' do
35
+ content = 'hello world'
36
+ new_cls.stub :content, content do |i|
37
+ i.sha256sum.must_equal 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
38
+ end
39
+ end
40
+
41
+ it 'sets sha256sum of nil content to nil' do
42
+ new_cls.stub :content, nil do |i|
43
+ i.sha256sum.must_be_nil
44
+ end
45
+ end
46
+
47
+ it 'throws Not implemented error for exist?' do
48
+ # proc { Train.validate_backend({ host: rand }) }.must_raise Train::UserError
49
+ proc { new_cls.exist?}.must_raise NotImplementedError
50
+ end
51
+
52
+ it 'throws Not implemented error for mode' do
53
+ proc { new_cls.mode }.must_raise NotImplementedError
54
+ end
55
+
56
+ it 'throws Not implemented error for owner' do
57
+ proc { new_cls.owner }.must_raise NotImplementedError
58
+ end
59
+
60
+ it 'throws Not implemented error for group' do
61
+ proc { new_cls.group }.must_raise NotImplementedError
62
+ end
63
+
64
+ it 'throws Not implemented error for uid' do
65
+ proc { new_cls.uid }.must_raise NotImplementedError
66
+ end
67
+
68
+ it 'throws Not implemented error for gid' do
69
+ proc { new_cls.gid }.must_raise NotImplementedError
70
+ end
71
+
72
+ it 'throws Not implemented error for content' do
73
+ proc { new_cls.content }.must_raise NotImplementedError
74
+ end
75
+
76
+ it 'throws Not implemented error for mtime' do
77
+ proc { new_cls.mtime }.must_raise NotImplementedError
78
+ end
79
+
80
+ it 'throws Not implemented error for size' do
81
+ proc { new_cls.size }.must_raise NotImplementedError
82
+ end
83
+
84
+ it 'throws Not implemented error for selinux_label' do
85
+ proc { new_cls.selinux_label }.must_raise NotImplementedError
86
+ end
87
+
88
+ it 'return path of file' do
89
+ new_cls.path.must_equal('/temp/file')
90
+ end
91
+
92
+ it 'set product_version to nil' do
93
+ new_cls.product_version.must_be_nil
94
+ end
95
+
96
+ it 'set product_version to nil' do
97
+ new_cls.file_version.must_be_nil
98
+ end
99
+
100
+
101
+ describe 'type' do
102
+ it 'recognized type == file' do
103
+ fc = mockup(type: :file)
104
+ fc.file?.must_equal true
105
+ end
106
+
107
+ it 'recognized type == block_device' do
108
+ fc = mockup(type: :block_device)
109
+ fc.block_device?.must_equal true
110
+ end
111
+
112
+ it 'recognized type == character_device' do
113
+ fc = mockup(type: :character_device)
114
+ fc.character_device?.must_equal true
115
+ end
116
+
117
+ it 'recognized type == socket' do
118
+ fc = mockup(type: :socket)
119
+ fc.socket?.must_equal true
120
+ end
121
+
122
+ it 'recognized type == directory' do
123
+ fc = mockup(type: :directory)
124
+ fc.directory?.must_equal true
125
+ end
126
+
127
+ it 'recognized type == pipe' do
128
+ fc = mockup(type: :pipe)
129
+ fc.pipe?.must_equal true
130
+ end
131
+
132
+ it 'recognized type == symlink' do
133
+ fc = mockup(type: :symlink)
134
+ fc.symlink?.must_equal true
135
+ end
136
+ end
137
+
138
+ describe 'version' do
139
+ it 'recognized wrong version' do
140
+ fc = mockup(product_version: rand, file_version: rand)
141
+ fc.version?(rand).must_equal false
142
+ end
143
+
144
+ it 'recognized product_version' do
145
+ x = rand
146
+ fc = mockup(product_version: x, file_version: rand)
147
+ fc.version?(x).must_equal true
148
+ end
149
+
150
+ it 'recognized file_version' do
151
+ x = rand
152
+ fc = mockup(product_version: rand, file_version: x)
153
+ fc.version?(x).must_equal true
154
+ end
155
+ end
156
+ end
@@ -86,7 +86,7 @@ describe 'v1 Transport Plugin' do
86
86
 
87
87
  it 'default option must not be required' do
88
88
  name, plugin = train_class
89
- plugin.default_options[name][:required].must_equal nil
89
+ plugin.default_options[name][:required].must_be_nil
90
90
  end
91
91
 
92
92
  it 'can include options from another module' do
@@ -94,11 +94,11 @@ describe 'mock transport' do
94
94
 
95
95
  # tests if all fields between the local json and resulting mock file
96
96
  # are equal
97
- JSON = Train.create('local').connection.file(__FILE__).to_json
98
- RES = Train::Transports::Mock::Connection::File.from_json(JSON)
97
+ JSON_DATA = Train.create('local').connection.file(__FILE__).to_json
98
+ RES = Train::Transports::Mock::Connection::File.from_json(JSON_DATA)
99
99
  %w{ content mode owner group }.each do |f|
100
100
  it "can be initialized from json (field #{f})" do
101
- RES.method(f).call.must_equal JSON[f]
101
+ RES.method(f).call.must_equal JSON_DATA[f]
102
102
  end
103
103
  end
104
104
  end
@@ -6,6 +6,7 @@ require 'minitest/autorun'
6
6
  require 'minitest/spec'
7
7
  require 'mocha/setup'
8
8
  require 'train'
9
+ require 'tempfile'
9
10
 
10
11
  describe 'windows local command' do
11
12
  let(:conn) {
@@ -39,6 +40,111 @@ describe 'windows local command' do
39
40
  cmd.stderr.must_equal ''
40
41
  end
41
42
 
43
+ describe 'file' do
44
+ before do
45
+ @temp = Tempfile.new('foo')
46
+ @temp.write("hello world")
47
+ @temp.rewind
48
+ end
49
+
50
+ let(:file) { conn.file(@temp.path) }
51
+
52
+ it 'exists' do
53
+ file.exist?.must_equal(true)
54
+ end
55
+
56
+ it 'is a file' do
57
+ file.file?.must_equal(true)
58
+ end
59
+
60
+ it 'has type :file' do
61
+ file.type.must_equal(:file)
62
+ end
63
+
64
+ it 'has content' do
65
+ file.content.must_equal("hello world")
66
+ end
67
+
68
+ it 'returns basename of file' do
69
+ file_name = ::File.basename(@temp)
70
+ file.basename.must_equal(file_name)
71
+ end
72
+
73
+ it 'has owner name' do
74
+ file.owner.wont_be_nil
75
+ end
76
+
77
+ it 'has no group name' do
78
+ file.group.must_be_nil
79
+ end
80
+
81
+ it 'has no mode' do
82
+ file.mode.wont_be_nil
83
+ end
84
+
85
+ it 'has an md5sum' do
86
+ file.md5sum.wont_be_nil
87
+ end
88
+
89
+ it 'has an sha256sum' do
90
+ file.sha256sum.wont_be_nil
91
+ end
92
+
93
+ it 'has no modified time' do
94
+ file.mtime.wont_be_nil
95
+ end
96
+
97
+ it 'has no size' do
98
+ file.size.wont_be_nil
99
+ end
100
+
101
+ it 'has size 11' do
102
+ size = ::File.size(@temp)
103
+ file.size.must_equal size
104
+ end
105
+
106
+ it 'has no selinux_label handling' do
107
+ file.selinux_label.must_be_nil
108
+ end
109
+
110
+ it 'has product_version' do
111
+ file.product_version.wont_be_nil
112
+ end
113
+
114
+ it 'has file_version' do
115
+ file.file_version.wont_be_nil
116
+ end
117
+
118
+ it 'provides a json representation' do
119
+ j = file.to_json
120
+ j.must_be_kind_of Hash
121
+ j['type'].must_equal :file
122
+ end
123
+
124
+ after do
125
+ @temp.close
126
+ @temp.unlink
127
+ end
128
+ end
129
+
130
+ describe 'file' do
131
+ before do
132
+ @temp = Tempfile.new('foo bar')
133
+ @temp.rewind
134
+ end
135
+
136
+ let(:file) { conn.file(@temp.path) }
137
+
138
+ it 'provides the full path with whitespace for path #{@temp.path}' do
139
+ file.path.must_equal @temp.path
140
+ end
141
+
142
+ after do
143
+ @temp.close
144
+ @temp.unlink
145
+ end
146
+ end
147
+
42
148
  after do
43
149
  # close the connection
44
150
  conn.close
@@ -45,6 +45,131 @@ describe 'windows winrm command' do
45
45
  cmd.stderr.must_equal ''
46
46
  end
47
47
 
48
+
49
+ describe 'file' do
50
+ before do
51
+ @temp = Tempfile.new('foo')
52
+ @temp.write("hello world")
53
+ @temp.rewind
54
+ end
55
+
56
+ let(:file) { conn.file(@temp.path) }
57
+
58
+ it 'exists' do
59
+ file.exist?.must_equal(true)
60
+ end
61
+
62
+ it 'is a file' do
63
+ file.file?.must_equal(true)
64
+ end
65
+
66
+ it 'has type :file' do
67
+ file.type.must_equal(:file)
68
+ end
69
+
70
+ it 'has content' do
71
+ # TODO: this shouldn't include newlines that aren't in the original file
72
+ file.content.must_equal("hello world\r\n")
73
+ end
74
+
75
+ it 'has owner name' do
76
+ file.owner.wont_be_nil
77
+ end
78
+
79
+ it 'has no group name' do
80
+ file.group.must_be_nil
81
+ end
82
+
83
+ it 'has no mode' do
84
+ file.mode.must_be_nil
85
+ end
86
+
87
+ it 'has an md5sum' do
88
+ file.md5sum.wont_be_nil
89
+ end
90
+
91
+ it 'has an sha256sum' do
92
+ file.sha256sum.wont_be_nil
93
+ end
94
+
95
+ it 'has no modified time' do
96
+ file.mtime.must_be_nil
97
+ end
98
+
99
+ it 'has no size' do
100
+ file.size.wont_be_nil
101
+ end
102
+
103
+ it 'has size 11' do
104
+ size = ::File.size(@temp)
105
+ file.size.must_equal size
106
+ end
107
+
108
+ it 'has no selinux_label handling' do
109
+ file.selinux_label.must_be_nil
110
+ end
111
+
112
+ it 'has product_version' do
113
+ file.product_version.wont_be_nil
114
+ end
115
+
116
+ # TODO: This is not failing in manual testing
117
+ # it 'returns basname of file' do
118
+ # basename = ::File.basename(@temp)
119
+ # file.basename.must_equal basename
120
+ # end
121
+
122
+ it 'has file_version' do
123
+ file.file_version.wont_be_nil
124
+ end
125
+
126
+ it 'returns nil for mounted' do
127
+ file.mounted.must_be_nil
128
+ end
129
+
130
+ it 'has no link_path' do
131
+ file.link_path.must_be_nil
132
+ end
133
+
134
+ it 'has no uid' do
135
+ file.uid.must_be_nil
136
+ end
137
+
138
+ it 'has no gid' do
139
+ file.gid.must_be_nil
140
+ end
141
+
142
+ it 'provides a json representation' do
143
+ j = file.to_json
144
+ j.must_be_kind_of Hash
145
+ j['type'].must_equal :file
146
+ end
147
+
148
+ after do
149
+ @temp.close
150
+ @temp.unlink
151
+ end
152
+ end
153
+
154
+ describe 'file' do
155
+ before do
156
+ @temp = Tempfile.new('foo bar')
157
+ @temp.write("hello world")
158
+ @temp.rewind
159
+ end
160
+
161
+ let(:file) { conn.file(@temp.path) }
162
+
163
+ it 'provides the full path with whitespace for path #{@temp.path}' do
164
+ file.path.must_equal @temp.path
165
+ end
166
+
167
+ after do
168
+ @temp.close
169
+ @temp.unlink
170
+ end
171
+ end
172
+
48
173
  after do
49
174
  # close the connection
50
175
  conn.close