File: signal_spec.cr

package info (click to toggle)
crystal 1.14.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 24,384 kB
  • sloc: javascript: 6,400; sh: 695; makefile: 269; ansic: 121; python: 105; cpp: 77; xml: 32
file content (113 lines) | stat: -rw-r--r-- 2,670 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
{% skip_file if flag?(:wasm32) %}

require "./spec_helper"
require "signal"

# interpreted code never receives signals (#12241)
pending_interpreted describe: "Signal" do
  typeof(Signal::ABRT.reset)
  typeof(Signal::ABRT.ignore)
  typeof(Signal::ABRT.trap { 1 })

  it "has constants required by C" do
    Signal::INT.should be_a(Signal)
    Signal::ILL.should be_a(Signal)
    Signal::FPE.should be_a(Signal)
    Signal::SEGV.should be_a(Signal)
    Signal::TERM.should be_a(Signal)
    Signal::ABRT.should be_a(Signal)
  end

  {% unless flag?(:win32) %}
    it "runs a signal handler" do
      ran = false
      Signal::USR1.trap do
        ran = true
      end
      Process.signal Signal::USR1, Process.pid
      10.times do |i|
        break if ran
        sleep 0.1.seconds
      end
      ran.should be_true
    ensure
      Signal::USR1.reset
    end

    it "ignores a signal" do
      Signal::USR2.ignore
      Process.signal Signal::USR2, Process.pid
    end

    it "allows chaining of signals" do
      ran_first = false
      ran_second = false

      Signal::USR1.trap { ran_first = true }
      existing = Signal::USR1.trap_handler?

      Signal::USR1.trap do |signal|
        existing.try &.call(signal)
        ran_second = true
      end

      Process.signal Signal::USR1, Process.pid
      sleep 0.1.seconds
      ran_first.should be_true
      ran_second.should be_true
    ensure
      Signal::USR1.reset
    end

    it "CHLD.reset sets default Crystal child handler" do
      Signal::CHLD.reset
      child = Process.new("true", shell: true)
      child.wait # doesn't block forever
    end

    it "CHLD.ignore sets default Crystal child handler" do
      Signal::CHLD.ignore
      child = Process.new("true", shell: true)
      child.wait # doesn't block forever
    end

    it "CHLD.trap is called after default Crystal child handler" do
      chan = Channel(Process).new
      existed = Channel(Bool).new

      Signal::CHLD.trap do
        child_process = chan.receive
        existed.send(Process.exists?(child_process.pid))
      end

      child = Process.new("true", shell: true)
      child.wait # doesn't block forever
      chan.send(child)
      existed.receive.should be_false
    ensure
      Signal::CHLD.reset
    end

    it "CHLD.reset removes previously set trap" do
      call_count = 0

      Signal::CHLD.trap do
        call_count += 1
      end

      Process.new("true", shell: true).wait
      Fiber.yield

      call_count.should eq(1)

      Signal::CHLD.reset

      Process.new("true", shell: true).wait
      Fiber.yield

      call_count.should eq(1)
    end

    # TODO: test Signal::X.reset
  {% end %}
end