instana 1.195.2 → 1.197.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -2
  3. data/Rakefile +1 -1
  4. data/instana.gemspec +3 -7
  5. data/lib/instana.rb +3 -0
  6. data/lib/instana/activator.rb +2 -0
  7. data/lib/instana/backend/agent.rb +60 -0
  8. data/lib/instana/backend/gc_snapshot.rb +41 -0
  9. data/lib/instana/backend/host_agent.rb +74 -0
  10. data/lib/instana/backend/host_agent_activation_observer.rb +97 -0
  11. data/lib/instana/backend/host_agent_lookup.rb +57 -0
  12. data/lib/instana/backend/host_agent_reporting_observer.rb +106 -0
  13. data/lib/instana/backend/process_info.rb +64 -0
  14. data/lib/instana/backend/request_client.rb +73 -0
  15. data/lib/instana/backend/serverless_agent.rb +118 -0
  16. data/lib/instana/base.rb +8 -27
  17. data/lib/instana/config.rb +8 -22
  18. data/lib/instana/instrumentation/excon.rb +17 -8
  19. data/lib/instana/instrumentation/instrumented_request.rb +62 -7
  20. data/lib/instana/instrumentation/net-http.rb +7 -5
  21. data/lib/instana/instrumentation/rack.rb +12 -7
  22. data/lib/instana/logger_delegator.rb +31 -0
  23. data/lib/instana/{opentracing → open_tracing}/carrier.rb +0 -0
  24. data/lib/instana/open_tracing/instana_tracer.rb +99 -0
  25. data/lib/instana/secrets.rb +6 -2
  26. data/lib/instana/setup.rb +20 -11
  27. data/lib/instana/snapshot/deltable.rb +25 -0
  28. data/lib/instana/snapshot/docker_container.rb +151 -0
  29. data/lib/instana/snapshot/fargate_container.rb +88 -0
  30. data/lib/instana/snapshot/fargate_process.rb +67 -0
  31. data/lib/instana/snapshot/fargate_task.rb +72 -0
  32. data/lib/instana/snapshot/lambda_function.rb +36 -0
  33. data/lib/instana/snapshot/ruby_process.rb +48 -0
  34. data/lib/instana/tracer.rb +25 -143
  35. data/lib/instana/tracing/processor.rb +14 -22
  36. data/lib/instana/tracing/span.rb +31 -34
  37. data/lib/instana/tracing/span_context.rb +15 -10
  38. data/lib/instana/util.rb +8 -69
  39. data/lib/instana/version.rb +1 -1
  40. data/lib/opentracing.rb +26 -3
  41. data/test/backend/agent_test.rb +54 -0
  42. data/test/backend/gc_snapshot_test.rb +11 -0
  43. data/test/backend/host_agent_activation_observer_test.rb +72 -0
  44. data/test/backend/host_agent_lookup_test.rb +78 -0
  45. data/test/backend/host_agent_reporting_observer_test.rb +192 -0
  46. data/test/backend/host_agent_test.rb +47 -0
  47. data/test/backend/process_info_test.rb +63 -0
  48. data/test/backend/request_client_test.rb +39 -0
  49. data/test/backend/serverless_agent_test.rb +73 -0
  50. data/test/config_test.rb +10 -0
  51. data/test/instana_test.rb +11 -4
  52. data/test/instrumentation/excon_test.rb +15 -1
  53. data/test/instrumentation/rack_instrumented_request_test.rb +5 -2
  54. data/test/instrumentation/rack_test.rb +2 -14
  55. data/test/secrets_test.rb +41 -22
  56. data/test/snapshot/deltable_test.rb +17 -0
  57. data/test/snapshot/docker_container_test.rb +82 -0
  58. data/test/snapshot/fargate_container_test.rb +82 -0
  59. data/test/snapshot/fargate_process_test.rb +35 -0
  60. data/test/snapshot/fargate_task_test.rb +49 -0
  61. data/test/snapshot/ruby_process_test.rb +14 -0
  62. data/test/support/mock_timer.rb +20 -0
  63. data/test/test_helper.rb +16 -4
  64. data/test/tracing/custom_test.rb +1 -3
  65. data/test/tracing/id_management_test.rb +4 -0
  66. data/test/tracing/opentracing_test.rb +15 -2
  67. data/test/tracing/processor_test.rb +58 -0
  68. data/test/tracing/span_context_test.rb +21 -0
  69. data/test/tracing/span_test.rb +136 -0
  70. data/test/tracing/tracer_async_test.rb +29 -0
  71. data/test/tracing/tracer_test.rb +82 -16
  72. data/test/util_test.rb +10 -0
  73. metadata +71 -43
  74. data/lib/instana/agent.rb +0 -508
  75. data/lib/instana/agent/helpers.rb +0 -87
  76. data/lib/instana/agent/hooks.rb +0 -44
  77. data/lib/instana/agent/tasks.rb +0 -51
  78. data/lib/instana/collector.rb +0 -119
  79. data/lib/instana/collectors/gc.rb +0 -60
  80. data/lib/instana/collectors/memory.rb +0 -37
  81. data/lib/instana/collectors/thread.rb +0 -33
  82. data/lib/instana/eum/eum-test.js.erb +0 -17
  83. data/lib/instana/eum/eum.js.erb +0 -17
  84. data/lib/instana/helpers.rb +0 -47
  85. data/lib/instana/opentracing/tracer.rb +0 -21
  86. data/lib/instana/thread_local.rb +0 -18
  87. data/lib/oj_check.rb +0 -19
  88. data/test/agent/agent_test.rb +0 -151
@@ -0,0 +1,11 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class GcSnapshotTest < Minitest::Test
7
+ def test_report
8
+ subject = Instana::Backend::GCSnapshot.instance
9
+ assert subject.report.is_a?(Hash)
10
+ end
11
+ end
@@ -0,0 +1,72 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class HostAgentActivationObserverTest < Minitest::Test
7
+ def setup
8
+ @socket_proc = ->(_c) { OpenStruct.new(fileno: 0) }
9
+ end
10
+
11
+ def test_standard_discovery
12
+ stub_request(:put, "http://10.10.10.10:9292/com.instana.plugin.ruby.discovery")
13
+ .and_timeout
14
+ .and_return(status: 500, body: '{"ok": false}')
15
+ .and_return(status: 200, body: '{"pid": 1234}')
16
+
17
+ stub_request(:head, "http://10.10.10.10:9292/com.instana.plugin.ruby.1234")
18
+ .and_return(status: 500, body: '{"ok": false}')
19
+ .and_return(status: 200, body: '{"ok": true}')
20
+
21
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
22
+ discovery = Concurrent::Atom.new(nil)
23
+
24
+ subject = Instana::Backend::HostAgentActivationObserver.new(client, discovery, wait_time: 0, logger: Logger.new('/dev/null'), max_wait_tries: 1, socket_proc: @socket_proc)
25
+
26
+ subject.update(nil, nil, nil)
27
+ assert_equal({'pid' => 1234}, discovery.value)
28
+ end
29
+
30
+ def test_linux_discovery
31
+ stub_request(:put, "http://10.10.10.10:9292/com.instana.plugin.ruby.discovery")
32
+ .and_return(status: 200, body: '{"pid": 1234}')
33
+
34
+ stub_request(:head, "http://10.10.10.10:9292/com.instana.plugin.ruby.1234")
35
+ .and_return(status: 200, body: '{"ok": true}')
36
+
37
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
38
+ discovery = Concurrent::Atom.new(nil)
39
+
40
+ subject = Instana::Backend::HostAgentActivationObserver.new(client, discovery, wait_time: 0, logger: Logger.new('/dev/null'), max_wait_tries: 1, socket_proc: @socket_proc)
41
+
42
+ FakeFS.with_fresh do
43
+ FakeFS::FileSystem.clone('test/support/proc', '/proc')
44
+ FakeFS::FileSystem.clone('test/support/proc/0', "/proc/#{Process.pid}")
45
+ Dir.mkdir('/proc/self/fd')
46
+ File.symlink('/proc/self/sched', "/proc/self/fd/0")
47
+
48
+ subject.update(nil, nil, nil)
49
+ end
50
+
51
+ assert_equal({'pid' => 1234}, discovery.value)
52
+ end
53
+
54
+ def test_discovery_standard_error
55
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
56
+ discovery = Concurrent::Atom.new(nil)
57
+
58
+ subject = Instana::Backend::HostAgentActivationObserver.new(client, discovery, wait_time: 0, logger: Logger.new('/dev/null'), proc_table: nil, socket_proc: @socket_proc)
59
+
60
+ subject.update(nil, nil, nil)
61
+ assert_nil discovery.value
62
+ end
63
+
64
+ def test_value_present
65
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
66
+ discovery = Concurrent::Atom.new(nil)
67
+
68
+ subject = Instana::Backend::HostAgentActivationObserver.new(client, discovery, socket_proc: @socket_proc)
69
+ assert_nil subject.update(nil, nil, true)
70
+ assert_nil discovery.value
71
+ end
72
+ end
@@ -0,0 +1,78 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class HostAgentLookupTest < Minitest::Test
7
+ def test_lookup
8
+ stub_request(:get, "http://10.10.10.10:42699/")
9
+ .to_return(status: 200)
10
+
11
+ subject = Instana::Backend::HostAgentLookup.new('10.10.10.10', 42699)
12
+ client = subject.call
13
+
14
+ assert client
15
+ assert client.send_request('GET', '/').ok?
16
+ end
17
+
18
+ def test_lookup_no_agent
19
+ stub_request(:get, "http://10.10.10.10:42699/")
20
+ .to_timeout
21
+
22
+ subject = Instana::Backend::HostAgentLookup.new('10.10.10.10', 42699)
23
+
24
+ client = FakeFS.with_fresh do
25
+ FakeFS::FileSystem.clone('test/support/ecs', '/proc')
26
+
27
+ subject.call
28
+ end
29
+
30
+ assert_nil client
31
+ end
32
+
33
+ def test_lookup_agent_error
34
+ stub_request(:get, "http://10.10.10.10:42699/")
35
+ .to_return(status: 500)
36
+
37
+ subject = Instana::Backend::HostAgentLookup.new('10.10.10.10', 42699)
38
+
39
+ client = FakeFS.with_fresh do
40
+ FakeFS::FileSystem.clone('test/support/ecs', '/proc')
41
+
42
+ subject.call
43
+ end
44
+
45
+ assert_nil client
46
+ end
47
+
48
+ def test_lookup_with_gateway
49
+ stub_request(:get, "http://10.10.10.10:42699/")
50
+ .to_timeout
51
+ stub_request(:get, "http://172.18.0.1:42699/")
52
+ .to_return(status: 200)
53
+
54
+ subject = Instana::Backend::HostAgentLookup.new('10.10.10.10', 42699)
55
+
56
+ client = FakeFS do
57
+ FakeFS::FileSystem.clone('test/support/proc', '/proc')
58
+ subject.call
59
+ end
60
+
61
+ assert client
62
+ assert client.send_request('GET', '/').ok?
63
+ end
64
+
65
+ def test_lookup_with_gateway_no_destination
66
+ stub_request(:get, "http://10.10.10.10:42699/")
67
+ .to_timeout
68
+
69
+ subject = Instana::Backend::HostAgentLookup.new('10.10.10.10', 42699, destination: '11111111')
70
+
71
+ client = FakeFS do
72
+ FakeFS::FileSystem.clone('test/support/proc', '/proc')
73
+ subject.call
74
+ end
75
+
76
+ assert_nil client
77
+ end
78
+ end
@@ -0,0 +1,192 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class HostAgentReportingObserverTest < Minitest::Test
7
+ def test_start_stop
8
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
9
+ discovery = Concurrent::Atom.new(nil)
10
+
11
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer)
12
+
13
+ refute subject.report_timer.running
14
+
15
+ subject.update(Time.now, nil, true)
16
+ assert subject.report_timer.running
17
+
18
+ subject.update(Time.now, nil, nil)
19
+ refute subject.report_timer.running
20
+
21
+ subject.update(Time.now - 500, nil, true)
22
+ refute subject.report_timer.running
23
+ end
24
+
25
+ def test_report
26
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby.0")
27
+ .to_return(status: 200)
28
+
29
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
30
+ discovery = Concurrent::Atom.new({'pid' => 0})
31
+
32
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer)
33
+
34
+ subject.report_timer.block.call
35
+ end
36
+
37
+ def test_report_fail
38
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby.0")
39
+ .to_return(status: 500)
40
+
41
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
42
+ discovery = Concurrent::Atom.new({'pid' => 0})
43
+
44
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer)
45
+
46
+ subject.report_timer.block.call
47
+ assert_nil discovery.value
48
+ end
49
+
50
+ def test_agent_action
51
+ action = JSON.dump(
52
+ action: 'ruby.source',
53
+ messageId: 'test',
54
+ args: {file: 'test_helper.rb'}
55
+ )
56
+
57
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby.0")
58
+ .to_return(status: 200, body: action)
59
+
60
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby/response.0?messageId=test")
61
+ .to_return(status: 200)
62
+
63
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
64
+ discovery = Concurrent::Atom.new({'pid' => 0})
65
+
66
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer)
67
+
68
+ subject.report_timer.block.call
69
+ end
70
+
71
+ def test_agent_actions
72
+ action = JSON.dump([
73
+ action: 'ruby.source',
74
+ messageId: 'test',
75
+ args: {file: 'test_helper.rb'}
76
+ ])
77
+
78
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby.0")
79
+ .to_return(status: 200, body: action)
80
+
81
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby/response.0?messageId=test")
82
+ .to_return(status: 200)
83
+
84
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
85
+ discovery = Concurrent::Atom.new({'pid' => 0})
86
+
87
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer)
88
+
89
+ subject.report_timer.block.call
90
+ end
91
+
92
+ def test_agent_action_error
93
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby.0")
94
+ .to_return(status: 200, body: 'INVALID')
95
+
96
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
97
+ discovery = Concurrent::Atom.new({'pid' => 0})
98
+
99
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer)
100
+
101
+ subject.report_timer.block.call
102
+ end
103
+
104
+ def test_disable_metrics
105
+ ::Instana.config[:metrics][:enabled] = false
106
+
107
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
108
+ discovery = Concurrent::Atom.new(nil)
109
+
110
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer)
111
+
112
+ subject.report_timer.block.call
113
+ ensure
114
+ ::Instana.config[:metrics][:enabled] = true
115
+ end
116
+
117
+ def test_disable_tracing
118
+ ::Instana.config[:tracing][:enabled] = false
119
+
120
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
121
+ discovery = Concurrent::Atom.new(nil)
122
+
123
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer)
124
+
125
+ subject.report_timer.block.call
126
+ ensure
127
+ ::Instana.config[:tracing][:enabled] = true
128
+ end
129
+
130
+ def test_report_traces
131
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby.1234")
132
+ .to_return(status: 200)
133
+
134
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby/traces.1234")
135
+ .to_return(status: 200)
136
+
137
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
138
+ discovery = Concurrent::Atom.new({'pid' => 1234})
139
+
140
+ processor = Class.new do
141
+ def send
142
+ yield([{n: 'test'}])
143
+ end
144
+ end.new
145
+
146
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer, processor: processor)
147
+
148
+ subject.report_timer.block.call
149
+ refute_nil discovery.value
150
+ end
151
+
152
+ def test_report_traces_error
153
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby.1234")
154
+ .to_return(status: 200)
155
+
156
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby/traces.1234")
157
+ .to_return(status: 500)
158
+
159
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
160
+ discovery = Concurrent::Atom.new({'pid' => 1234})
161
+
162
+ processor = Class.new do
163
+ def send
164
+ yield([{n: 'test'}])
165
+ end
166
+ end.new
167
+
168
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer, processor: processor)
169
+
170
+ subject.report_timer.block.call
171
+ assert_nil discovery.value
172
+ end
173
+
174
+ def test_report_standard_error
175
+ stub_request(:post, "http://10.10.10.10:9292/com.instana.plugin.ruby.1234")
176
+ .to_return(status: 200)
177
+
178
+ client = Instana::Backend::RequestClient.new('10.10.10.10', 9292)
179
+ discovery = Concurrent::Atom.new({'pid' => 1234})
180
+
181
+ processor = Class.new do
182
+ def send
183
+ raise 'Standard Error'
184
+ end
185
+ end.new
186
+
187
+ subject = Instana::Backend::HostAgentReportingObserver.new(client, discovery, timer_class: MockTimer, processor: processor, logger: Logger.new('/dev/null'))
188
+
189
+ subject.report_timer.block.call
190
+ assert_equal({"pid" => 1234}, discovery.value)
191
+ end
192
+ end
@@ -0,0 +1,47 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class HostAgentTest < Minitest::Test
7
+ def test_spawn_background_thread
8
+ ENV['INSTANA_TEST'] = nil
9
+ ::Instana.config[:agent_host] = '10.10.10.10'
10
+
11
+ if File.exist?('/sbin/ip')
12
+ addr = `/sbin/ip route | awk '/default/ { print $3 }'`.strip
13
+ stub_request(:get, "http://#{addr}:42699/")
14
+ .to_timeout
15
+ end
16
+
17
+ stub_request(:get, "http://10.10.10.10:42699/")
18
+ .to_timeout.times(3).then
19
+ .to_return(status: 200, body: "", headers: {})
20
+
21
+ discovery = Minitest::Mock.new
22
+ discovery.expect(:delete_observers, discovery, [])
23
+ discovery.expect(:with_observer, discovery, [Instana::Backend::HostAgentActivationObserver])
24
+ discovery.expect(:with_observer, discovery, [Instana::Backend::HostAgentReportingObserver])
25
+ discovery.expect(:swap, discovery, [])
26
+
27
+ subject = Instana::Backend::HostAgent.new(discovery: discovery)
28
+
29
+ FakeFS.with_fresh do
30
+ FakeFS::FileSystem.clone('test/support/ecs', '/proc')
31
+ subject.spawn_background_thread
32
+ end
33
+
34
+ subject.future.value!
35
+
36
+ discovery.verify
37
+ ensure
38
+ ::Instana.config[:agent_host] = '127.0.0.1'
39
+ ENV['INSTANA_TEST'] = 'true'
40
+ end
41
+
42
+ def test_discovery_value
43
+ discovery = Concurrent::Atom.new({'pid' => 1})
44
+ subject = Instana::Backend::HostAgent.new(discovery: discovery)
45
+ assert_equal 1, subject.source[:e]
46
+ end
47
+ end
@@ -0,0 +1,63 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class ProcessInfoTest < Minitest::Test
7
+ def test_osx_argument_stripping
8
+ host_os = RbConfig::CONFIG['host_os']
9
+ RbConfig::CONFIG['host_os'] = 'darwin'
10
+
11
+ subject = Instana::Backend::ProcessInfo.new(OpenStruct.new(cmdline: 'test INSTANA_TEST=1 KV=2'))
12
+ assert_equal ['KV=2'], subject.arguments
13
+ ensure
14
+ RbConfig::CONFIG['host_os'] = host_os
15
+ end
16
+
17
+ def test_linux_argument_stripping
18
+ host_os = RbConfig::CONFIG['host_os']
19
+ RbConfig::CONFIG['host_os'] = 'linux'
20
+
21
+ subject = Instana::Backend::ProcessInfo.new(OpenStruct.new(cmdline: 'test INSTANA_TEST=1 KV=2'))
22
+ assert_equal ['INSTANA_TEST=1', 'KV=2'], subject.arguments
23
+ ensure
24
+ RbConfig::CONFIG['host_os'] = host_os
25
+ end
26
+
27
+ def test_no_proc
28
+ subject = Instana::Backend::ProcessInfo.new(OpenStruct.new(pid: 0))
29
+
30
+ FakeFS.with_fresh do
31
+ FakeFS::FileSystem.clone('test/support/ecs', '/proc')
32
+
33
+ assert_equal 0, subject.parent_pid
34
+ assert_nil subject.cpuset
35
+ assert_nil subject.sched_pid
36
+ refute subject.in_container?
37
+ end
38
+ end
39
+
40
+ def test_cpuset_proc
41
+ subject = Instana::Backend::ProcessInfo.new(OpenStruct.new(pid: 0))
42
+
43
+ FakeFS do
44
+ FakeFS::FileSystem.clone('test/support/proc', '/proc')
45
+ assert_equal '/', subject.cpuset
46
+ refute subject.in_container?
47
+ end
48
+ end
49
+
50
+ def test_sched_pid
51
+ subject = Instana::Backend::ProcessInfo.new(OpenStruct.new(pid: 1))
52
+
53
+ FakeFS do
54
+ FakeFS::FileSystem.clone('test/support/proc', '/proc')
55
+ refute_equal '/', subject.cpuset
56
+
57
+ assert subject.in_container?
58
+ assert_equal 35, subject.sched_pid
59
+ assert subject.from_parent_namespace
60
+ assert_equal subject.sched_pid, subject.parent_pid
61
+ end
62
+ end
63
+ end