@@ -97,6 +97,69 @@ defmodule Systemd.ManagerIntegrationTest do
9797 end
9898 end
9999
100+ test "links, starts, reads, stops, and disables a runtime unit file" do
101+ assert { :ok , conn } = Manager . connect ( )
102+
103+ name = "systemd-elixir-linked-test-#{ System . unique_integer ( [ :positive ] ) } .service"
104+ path = Path . join ( System . tmp_dir! ( ) , name )
105+
106+ File . write! (
107+ path ,
108+ "[Unit]\n Description=systemdkit linked integration test\n [Service]\n Type=oneshot\n ExecStart=/bin/true\n RemainAfterExit=yes\n "
109+ )
110+
111+ try do
112+ case Manager . link_unit_files ( conn , [ path ] , runtime: true , force: true ) do
113+ { :ok , % UnitFileOperation { } } ->
114+ assert :ok = Manager . reload ( conn )
115+ assert { :ok , state } = Manager . unit_file_state ( conn , name )
116+ assert state in [ "linked" , "linked-runtime" , "static" , "disabled" ]
117+
118+ assert { :ok , job } = Manager . start_unit ( conn , name )
119+ assert :ok = Job . await ( conn , job , timeout: 5_000 )
120+ assert { :ok , unit } = Manager . get_unit ( conn , name )
121+ assert { :ok , unit_state } = UnitObject . state ( conn , unit )
122+ assert unit_state . active_state in [ "active" , "activating" ]
123+
124+ assert :ok = Manager . stop_unit ( conn , name ) |> await_or_ok ( conn )
125+ assert_operation_or_permission ( Manager . disable_unit_files ( conn , [ name ] , runtime: true ) )
126+
127+ { :error , % Error { } = error } ->
128+ assert Error . permission? ( error )
129+ end
130+ after
131+ File . rm ( path )
132+ end
133+ end
134+
135+ test "starts, restarts, kills, and resets a long-running transient unit" do
136+ assert { :ok , conn } = Manager . connect ( )
137+
138+ name = "systemd-elixir-lifecycle-test-#{ System . unique_integer ( [ :positive ] ) } .service"
139+
140+ properties = [
141+ TransientUnit . string ( "Description" , "systemd Elixir lifecycle integration test" ) ,
142+ TransientUnit . string ( "Type" , "simple" ) ,
143+ TransientUnit . exec_start ( "/bin/sleep" , [ "/bin/sleep" , "60" ] )
144+ ]
145+
146+ case Manager . start_transient_unit ( conn , name , properties ) do
147+ { :ok , % Job { } = job } ->
148+ assert :ok = Job . await_signal ( conn , job , timeout: 5_000 )
149+ assert { :ok , unit } = Manager . get_unit ( conn , name )
150+ assert { :ok , state } = UnitObject . state ( conn , unit )
151+ assert state . active_state == "active"
152+
153+ assert :ok = Manager . try_restart_unit ( conn , name ) |> await_or_ok ( conn )
154+ assert :ok = Manager . kill_unit ( conn , name , "main" , 15 )
155+ assert :ok = eventually_inactive ( conn , unit , 5_000 )
156+ assert :ok = Manager . reset_failed_unit ( conn , name )
157+
158+ { :error , % Error { } = error } ->
159+ assert Error . permission? ( error )
160+ end
161+ end
162+
100163 test "starts a transient unit with resource controls" do
101164 assert { :ok , conn } = Manager . connect ( )
102165
@@ -170,6 +233,32 @@ defmodule Systemd.ManagerIntegrationTest do
170233 end
171234 end
172235
236+ defp eventually_inactive ( conn , unit , timeout ) do
237+ deadline = System . monotonic_time ( :millisecond ) + timeout
238+ do_eventually_inactive ( conn , unit , deadline )
239+ end
240+
241+ defp do_eventually_inactive ( conn , unit , deadline ) do
242+ case UnitObject . state ( conn , unit ) do
243+ { :ok , % { active_state: state } } when state in [ "inactive" , "failed" ] ->
244+ :ok
245+
246+ { :ok , _state } ->
247+ if System . monotonic_time ( :millisecond ) >= deadline do
248+ { :error , :timeout }
249+ else
250+ Process . sleep ( 100 )
251+ do_eventually_inactive ( conn , unit , deadline )
252+ end
253+
254+ { :error , % Error { reason: reason } } when reason in [ :unknown_object , :not_found ] ->
255+ :ok
256+
257+ { :error , error } ->
258+ { :error , error }
259+ end
260+ end
261+
173262 defp service_property ( conn , unit , property ) do
174263 Properties . get ( conn , unit . object_path , "org.freedesktop.systemd1.Service" , property )
175264 end
0 commit comments