3 class ArvadosModelTest < ActiveSupport::TestCase
6 def create_with_attrs attrs
7 a = Specimen.create({material: 'caloric'}.merge(attrs))
11 test 'non-admin cannot assign uuid' do
12 set_user_from_auth :active_trustedclient
13 want_uuid = Specimen.generate_uuid
14 a = create_with_attrs(uuid: want_uuid)
15 assert_nil a, "Non-admin should not assign uuid."
18 test 'admin can assign valid uuid' do
19 set_user_from_auth :admin_trustedclient
20 want_uuid = Specimen.generate_uuid
21 a = create_with_attrs(uuid: want_uuid)
22 assert_equal want_uuid, a.uuid, "Admin should assign valid uuid."
23 assert a.uuid.length==27, "Auto assigned uuid length is wrong."
26 test 'admin cannot assign uuid with wrong object type' do
27 set_user_from_auth :admin_trustedclient
28 want_uuid = Human.generate_uuid
29 a = create_with_attrs(uuid: want_uuid)
30 assert_nil a, "Admin should not be able to assign invalid uuid."
33 test 'admin cannot assign badly formed uuid' do
34 set_user_from_auth :admin_trustedclient
35 a = create_with_attrs(uuid: "ntoheunthaoesunhasoeuhtnsaoeunhtsth")
36 assert_nil a, "Admin should not be able to assign invalid uuid."
39 test 'admin cannot assign empty uuid' do
40 set_user_from_auth :admin_trustedclient
41 a = create_with_attrs(uuid: "")
42 assert_nil a, "Admin cannot assign empty uuid."
47 {:a => ['foo', 'bar']},
48 {'a' => [:foo, 'bar']},
49 {'a' => ['foo', :bar]},
51 {:a => {'foo' => {'bar' => 'baz'}}},
52 {'a' => {:foo => {'bar' => 'baz'}}},
53 {'a' => {'foo' => {:bar => 'baz'}}},
54 {'a' => {'foo' => {'bar' => :baz}}},
55 {'a' => {'foo' => ['bar', :baz]}},
57 test "prevent symbol keys in serialized db columns: #{x.inspect}" do
58 set_user_from_auth :active
59 link = Link.create!(link_class: 'test',
61 raw = ActiveRecord::Base.connection.
62 select_value("select properties from links where uuid='#{link.uuid}'")
63 refute_match(/:[fb]/, raw)
68 {'a' => {['foo', :foo] => 'bar'}},
69 {'a' => {{'foo' => 'bar'} => 'bar'}},
70 {'a' => {['foo', :foo] => ['bar', 'baz']}},
72 test "refuse non-string keys in serialized db columns: #{x.inspect}" do
73 set_user_from_auth :active
74 assert_raises(ArgumentError) do
75 Link.create!(link_class: 'test',
81 test "Stringify symbols coming from serialized attribute in database" do
82 set_user_from_auth :admin_trustedclient
83 fixed = Link.find_by_uuid(links(:has_symbol_keys_in_database_somehow).uuid)
84 assert_equal(["baz", "foo"], fixed.properties.keys.sort,
85 "Hash symbol keys from DB did not get stringified.")
86 assert_equal(['waz', 'waz', 'waz', 1, nil, false, true],
87 fixed.properties['baz'],
88 "Array symbol values from DB did not get stringified.")
89 assert_equal true, fixed.save, "Failed to save fixed model back to db."
92 test "No HashWithIndifferentAccess in database" do
93 set_user_from_auth :admin_trustedclient
94 link = Link.create!(link_class: 'test',
95 properties: {'foo' => 'bar'}.with_indifferent_access)
96 raw = ActiveRecord::Base.connection.
97 select_value("select properties from links where uuid='#{link.uuid}'")
98 assert_equal '{"foo":"bar"}', raw
101 test "store long string" do
102 set_user_from_auth :active
104 while longstring.length < 2**16
105 longstring = longstring + longstring
107 g = Group.create! name: 'Has a long description', description: longstring
108 g = Group.find_by_uuid g.uuid
109 assert_equal g.description, longstring
112 [['uuid', {unique: true}],
113 ['owner_uuid', {}]].each do |the_column, requires|
114 test "unique index on all models with #{the_column}" do
116 ActiveRecord::Base.connection.tables.each do |table|
117 columns = ActiveRecord::Base.connection.columns(table)
119 next unless columns.collect(&:name).include? the_column
121 indexes = ActiveRecord::Base.connection.indexes(table).reject do |index|
122 requires.map do |key, val|
123 index.send(key) == val
126 assert_includes indexes.collect(&:columns), [the_column], 'no index'
129 # Sanity check: make sure we didn't just systematically miss everything.
130 assert_operator(10, :<, checked,
131 "Only #{checked} tables have a #{the_column}?!")
135 test "search index exists on models that go into projects" do
136 all_tables = ActiveRecord::Base.connection.tables
137 all_tables.delete 'schema_migrations'
139 all_tables.each do |table|
140 table_class = table.classify.constantize
141 if table_class.respond_to?('searchable_columns')
142 search_index_columns = table_class.searchable_columns('ilike')
143 # Disappointing, but text columns aren't indexed yet.
144 search_index_columns -= table_class.columns.select { |c|
145 c.type == :text or c.name == 'description' or c.name == 'file_names'
148 indexes = ActiveRecord::Base.connection.indexes(table)
149 search_index_by_columns = indexes.select do |index|
150 index.columns.sort == search_index_columns.sort
152 search_index_by_name = indexes.select do |index|
153 index.name == "#{table}_search_index"
155 assert !search_index_by_columns.empty?, "#{table} has no search index with columns #{search_index_columns}. Instead found search index with columns #{search_index_by_name.first.andand.columns}"
160 test "full text search index exists on models" do
162 conn = ActiveRecord::Base.connection
163 conn.exec_query("SELECT i.relname as indname,
164 i.relowner as indowner,
165 idx.indrelid::regclass::text as table,
169 SELECT pg_get_indexdef(idx.indexrelid, k + 1, true)
170 FROM generate_subscripts(idx.indkey, 1) as k
173 idx.indexprs IS NOT NULL as indexprs,
174 idx.indpred IS NOT NULL as indpred
177 ON i.oid = idx.indexrelid
180 JOIN pg_namespace as ns
181 ON ns.oid = i.relnamespace
182 AND ns.nspname = ANY(current_schemas(false))").each do |idx|
183 if idx['keys'].match(/to_tsvector/)
184 indexes[idx['table']] ||= []
185 indexes[idx['table']] << idx
188 fts_tables = ["collections", "container_requests", "groups", "jobs",
189 "pipeline_instances", "pipeline_templates", "workflows"]
190 fts_tables.each do |table|
191 table_class = table.classify.constantize
192 if table_class.respond_to?('full_text_searchable_columns')
193 expect = table_class.full_text_searchable_columns
195 indexes[table].andand.each do |idx|
196 if expect == idx['keys'].scan(/COALESCE\(([A-Za-z_]+)/).flatten
200 assert ok, "#{table} has no full-text index\nexpect: #{expect.inspect}\nfound: #{indexes[table].inspect}"
205 test "selectable_attributes includes database attributes" do
206 assert_includes(Job.selectable_attributes, "success")
209 test "selectable_attributes includes non-database attributes" do
210 assert_includes(Job.selectable_attributes, "node_uuids")
213 test "selectable_attributes includes common attributes in extensions" do
214 assert_includes(Job.selectable_attributes, "uuid")
217 test "selectable_attributes does not include unexposed attributes" do
218 refute_includes(Job.selectable_attributes, "nodes")
221 test "selectable_attributes on a non-default template" do
222 attr_a = Job.selectable_attributes(:common)
223 assert_includes(attr_a, "uuid")
224 refute_includes(attr_a, "success")
227 test 'create and retrieve using created_at time' do
228 set_user_from_auth :active
229 group = Group.create! name: 'test create and retrieve group'
230 assert group.valid?, "group is not valid"
232 results = Group.where(created_at: group.created_at)
233 assert_includes results.map(&:uuid), group.uuid,
234 "Expected new group uuid in results when searched with its created_at timestamp"
237 test 'create and update twice and expect different update times' do
238 set_user_from_auth :active
239 group = Group.create! name: 'test create and retrieve group'
240 assert group.valid?, "group is not valid"
243 group.update_attributes!(name: "test create and update name 1")
244 results = Group.where(uuid: group.uuid)
245 assert_equal "test create and update name 1", results.first.name, "Expected name to be updated to 1"
246 updated_at_1 = results.first.updated_at.to_f
249 group.update_attributes!(name: "test create and update name 2")
250 results = Group.where(uuid: group.uuid)
251 assert_equal "test create and update name 2", results.first.name, "Expected name to be updated to 2"
252 updated_at_2 = results.first.updated_at.to_f
254 assert_equal true, (updated_at_2 > updated_at_1), "Expected updated time 2 to be newer than 1"