3 class ContainerTest < ActiveSupport::TestCase
7 command: ['echo', 'foo'],
8 container_image: 'img',
11 runtime_constraints: {"vcpus" => 1, "ram" => 1},
14 def minimal_new attrs={}
15 cr = ContainerRequest.new DEFAULT_ATTRS.merge(attrs)
16 act_as_user users(:active) do
19 c = Container.new DEFAULT_ATTRS.merge(attrs)
22 assert cr.update_attributes(container_uuid: c.uuid,
23 state: ContainerRequest::Committed,
29 def check_illegal_updates c, bad_updates
30 bad_updates.each do |u|
31 refute c.update_attributes(u), u.inspect
32 refute c.valid?, u.inspect
37 def check_illegal_modify c
38 check_illegal_updates c, [{command: ["echo", "bar"]},
39 {container_image: "img2"},
41 {environment: {"FOO" => "BAR"}},
42 {mounts: {"FOO" => "BAR"}},
43 {output_path: "/tmp3"},
44 {locked_by_uuid: "zzzzz-gj3su-027z32aux8dg2s1"},
45 {auth_uuid: "zzzzz-gj3su-017z32aux8dg2s1"},
46 {runtime_constraints: {"FOO" => "BAR"}}]
49 def check_bogus_states c
50 check_illegal_updates c, [{state: nil},
54 def check_no_change_from_cancelled c
55 check_illegal_modify c
57 check_illegal_updates c, [{ priority: 3 },
58 { state: Container::Queued },
59 { state: Container::Locked },
60 { state: Container::Running },
61 { state: Container::Complete }]
64 test "Container create" do
66 c, _ = minimal_new(environment: {},
67 mounts: {"BAR" => "FOO"},
70 runtime_constraints: {"vcpus" => 1, "ram" => 1})
72 check_illegal_modify c
81 test "Container serialized hash attributes sorted before save" do
82 env = {"C" => 3, "B" => 2, "A" => 1}
83 m = {"F" => 3, "E" => 2, "D" => 1}
84 rc = {"vcpus" => 1, "ram" => 1}
85 c, _ = minimal_new(environment: env, mounts: m, runtime_constraints: rc)
86 assert_equal c.environment.to_json, Container.deep_sort_hash(env).to_json
87 assert_equal c.mounts.to_json, Container.deep_sort_hash(m).to_json
88 assert_equal c.runtime_constraints.to_json, Container.deep_sort_hash(rc).to_json
91 test 'deep_sort_hash on array of hashes' do
92 a = {'z' => [[{'a' => 'a', 'b' => 'b'}]]}
93 b = {'z' => [[{'b' => 'b', 'a' => 'a'}]]}
94 assert_equal Container.deep_sort_hash(a).to_json, Container.deep_sort_hash(b).to_json
98 ["completed", :completed_older],
99 ["running", :running_older],
100 ["locked", :locked_higher_priority],
101 ["queued", :queued_higher_priority],
102 ["completed_vs_running", :completed_vs_running_winner],
103 ["running_vs_locked", :running_vs_locked_winner],
104 ["locked_vs_queued", :locked_vs_queued_winner]
105 ].each do |state, c_to_be_selected|
106 test "find reusable method for #{state} container" do
107 set_user_from_auth :active
108 c = Container.find_reusable(container_image: "test",
110 command: ["echo", "hello"],
112 runtime_constraints: {"vcpus" => 4, "ram" => 12000000000},
113 mounts: {"test" => {"kind" => "json"}},
114 environment: {"var" => state})
116 assert_equal c.uuid, containers(c_to_be_selected).uuid
120 test "Container find reusable method should not select failed" do
121 set_user_from_auth :active
122 attrs = {container_image: "test",
124 command: ["echo", "hello"],
126 runtime_constraints: {"vcpus" => 4, "ram" => 12000000000},
127 mounts: {"test" => {"kind" => "json"}},
128 environment: {"var" => "failed"}}
129 cf = containers(:failed_container)
130 assert_equal cf.container_image, attrs[:container_image]
131 assert_equal cf.cwd, attrs[:cwd]
132 assert_equal cf.command, attrs[:command]
133 assert_equal cf.output_path, attrs[:output_path]
134 assert_equal cf.runtime_constraints, attrs[:runtime_constraints]
135 assert_equal cf.mounts, attrs[:mounts]
136 assert_equal cf.environment, attrs[:environment]
137 assert cf.exit_code != 0
138 c = Container.find_reusable(attrs)
142 test "Container running" do
143 c, _ = minimal_new priority: 1
145 set_user_from_auth :dispatch1
146 check_illegal_updates c, [{state: Container::Running},
147 {state: Container::Complete}]
149 c.update_attributes! state: Container::Locked
150 c.update_attributes! state: Container::Running
152 check_illegal_modify c
155 check_illegal_updates c, [{state: Container::Queued}]
158 c.update_attributes! priority: 3
161 test "Lock and unlock" do
162 c, cr = minimal_new priority: 0
164 set_user_from_auth :dispatch1
165 assert_equal Container::Queued, c.state
167 refute c.update_attributes(state: Container::Locked), "no priority"
169 assert cr.update_attributes priority: 1
171 refute c.update_attributes(state: Container::Running), "not locked"
173 refute c.update_attributes(state: Container::Complete), "not locked"
176 assert c.update_attributes(state: Container::Locked), show_errors(c)
177 assert c.locked_by_uuid
180 assert c.update_attributes(state: Container::Queued), show_errors(c)
181 refute c.locked_by_uuid
184 refute c.update_attributes(state: Container::Running), "not locked"
186 refute c.locked_by_uuid
189 assert c.update_attributes(state: Container::Locked), show_errors(c)
190 assert c.update_attributes(state: Container::Running), show_errors(c)
191 assert c.locked_by_uuid
194 auth_uuid_was = c.auth_uuid
196 refute c.update_attributes(state: Container::Locked), "already running"
198 refute c.update_attributes(state: Container::Queued), "already running"
201 assert c.update_attributes(state: Container::Complete), show_errors(c)
202 refute c.locked_by_uuid
205 auth_exp = ApiClientAuthorization.find_by_uuid(auth_uuid_was).expires_at
206 assert_operator auth_exp, :<, db_current_time
209 test "Container queued cancel" do
211 set_user_from_auth :dispatch1
212 assert c.update_attributes(state: Container::Cancelled), show_errors(c)
213 check_no_change_from_cancelled c
216 test "Container locked cancel" do
218 set_user_from_auth :dispatch1
219 assert c.update_attributes(state: Container::Locked), show_errors(c)
220 assert c.update_attributes(state: Container::Cancelled), show_errors(c)
221 check_no_change_from_cancelled c
224 test "Container running cancel" do
226 set_user_from_auth :dispatch1
227 c.update_attributes! state: Container::Queued
228 c.update_attributes! state: Container::Locked
229 c.update_attributes! state: Container::Running
230 c.update_attributes! state: Container::Cancelled
231 check_no_change_from_cancelled c
234 test "Container create forbidden for non-admin" do
235 set_user_from_auth :active_trustedclient
236 c = Container.new DEFAULT_ATTRS
238 c.mounts = {"BAR" => "FOO"}
239 c.output_path = "/tmp"
241 c.runtime_constraints = {}
242 assert_raises(ArvadosModel::PermissionDeniedError) do
247 test "Container only set exit code on complete" do
249 set_user_from_auth :dispatch1
250 c.update_attributes! state: Container::Locked
251 c.update_attributes! state: Container::Running
253 check_illegal_updates c, [{exit_code: 1},
254 {exit_code: 1, state: Container::Cancelled}]
256 assert c.update_attributes(exit_code: 1, state: Container::Complete)