Skip to content

Commit f20c31d

Browse files
samuel-williams-shopifyioquatix
authored andcommitted
Linux specific tests.
1 parent 086a334 commit f20c31d

3 files changed

Lines changed: 69 additions & 12 deletions

File tree

lib/process/metrics/general/linux.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ def self.capture(pid: nil, ppid: nil, memory: Memory.supported?)
5151

5252
comm = stat[1...rparen]
5353
fields = stat[(rparen + 2)..].split(/\s+/)
54-
# After comm: state(3), ppid(4), pgrp(5), ... utime(14), stime(15), ... starttime(22), vsz(23), rss(24). 0-based: ppid=1, pgrp=2, utime=11, stime=12, starttime=20, vsz=21, rss=22
54+
# After comm: state(3), ppid(4), pgrp(5), ... utime(14), stime(15), ... starttime(22), vsz(23), rss(24). 0-based: ppid=1, pgrp=2, utime=11, stime=12, starttime=19, vsz=20, rss=21.
5555
ppid_val = fields[1].to_i
5656
pgrp = fields[2].to_i
5757
utime = fields[11].to_i
5858
stime = fields[12].to_i
59-
starttime = fields[20].to_i
60-
vsz = fields[21].to_i
61-
rss_pages = fields[22].to_i
59+
starttime = fields[19].to_i
60+
vsz = fields[20].to_i
61+
rss_pages = fields[21].to_i
6262

6363
# Read /proc/uptime once per capture and reuse for every process (starttime is in jiffies since boot).
6464
uptime_jiffies ||= begin

test/process/general.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,29 @@
2828
it "can extract memory usage" do
2929
expect(capture[pid].memory_usage).to be > 0.0
3030
end
31-
31+
3232
it "sets parent_process_id and process_group_id" do
3333
process = capture[pid]
3434
expect(process.process_id).to be == pid
3535
expect(process.parent_process_id).to be_a(Integer)
3636
expect(process.process_group_id).to be_a(Integer)
3737
end
3838
end
39-
39+
4040
with ".capture with ppid only" do
4141
def before
4242
super
4343
@child_pid = Process.spawn("sleep 10")
4444
end
45-
45+
4646
def after(error = nil)
4747
super
4848
Process.kill(:TERM, @child_pid) if @child_pid
4949
Process.wait(@child_pid) if @child_pid
5050
end
51-
52-
let(:capture) { Process::Metrics::General.capture(ppid: Process.pid) }
53-
51+
52+
let(:capture) {Process::Metrics::General.capture(ppid: Process.pid)}
53+
5454
it "includes descendants of the given ppid" do
5555
expect(capture).to be(:include?, @child_pid)
5656
child = capture[@child_pid]
@@ -59,7 +59,7 @@ def after(error = nil)
5959
expect(child.parent_process_id).to be == Process.pid
6060
end
6161
end
62-
62+
6363
with ".capture with parent pid" do
6464
def before
6565
super
@@ -92,7 +92,7 @@ def after(error = nil)
9292
expect(command[:processor_time]).to be >= 0.0
9393
expect(command[:processor_utilization]).to be >= 0.0
9494
end
95-
95+
9696
it "sets parent_process_id and process_group_id on child" do
9797
child = capture[@pid]
9898
expect(child).not.to be_nil

test/process/general/linux.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2024-2025, by Samuel Williams.
5+
6+
require "process/metrics"
7+
# Load ProcessStatus backend so we can compare General (Linux) vs General::ProcessStatus.
8+
require "process/metrics/general/process_status"
9+
10+
describe Process::Metrics::General do
11+
with "Linux backend matches ProcessStatus backend" do
12+
def assert_backends_match(linux, ps)
13+
expect(linux.keys.sort).to be == ps.keys.sort
14+
15+
linux.each_key do |pid|
16+
linux_process = linux[pid]
17+
ps_process = ps[pid]
18+
19+
expect(ps_process).not.to be_nil
20+
expect(linux_process.process_id).to be == ps_process.process_id
21+
expect(linux_process.parent_process_id).to be == ps_process.parent_process_id
22+
expect(linux_process.process_group_id).to be == ps_process.process_group_id
23+
24+
# VSZ and RSS differ because ps excludes device mappings while /proc/stat includes them.
25+
expect(linux_process.virtual_size).to be_within(10.0).percent_of(ps_process.virtual_size)
26+
expect(linux_process.resident_size).to be_within(10.0).percent_of(ps_process.resident_size)
27+
28+
expect(linux_process.command).to be == ps_process.command
29+
expect((linux_process.processor_time - ps_process.processor_time).abs).to be < 1.0
30+
expect((linux_process.elapsed_time - ps_process.elapsed_time).abs).to be < 1.0
31+
end
32+
end
33+
34+
it "single pid capture matches" do
35+
skip "Linux with ps required" unless RUBY_PLATFORM.include?("linux") && Process::Metrics::General::ProcessStatus.supported?
36+
37+
pid = Process.pid
38+
linux = Process::Metrics::General.capture(pid: pid, memory: false)
39+
ps = Process::Metrics::General::ProcessStatus.capture(pid: pid, memory: false)
40+
assert_backends_match(linux, ps)
41+
end
42+
43+
it "pid and ppid capture matches" do
44+
skip "Linux with ps required" unless RUBY_PLATFORM.include?("linux") && Process::Metrics::General::ProcessStatus.supported?
45+
46+
child_pid = Process.spawn("sleep 10")
47+
begin
48+
linux = Process::Metrics::General.capture(pid: child_pid, ppid: child_pid, memory: false)
49+
ps = Process::Metrics::General::ProcessStatus.capture(pid: child_pid, ppid: child_pid, memory: false)
50+
assert_backends_match(linux, ps)
51+
ensure
52+
Process.kill(:TERM, child_pid)
53+
Process.wait(child_pid)
54+
end
55+
end
56+
end
57+
end

0 commit comments

Comments
 (0)