require 'test_helper'
+require 'helpers/share_object_helper'
class ProjectsControllerTest < ActionController::TestCase
+ include ShareObjectHelper
+
test "invited user is asked to sign user agreements on front page" do
get :index, {}, session_for(:inactive)
assert_response :redirect
id: readonly_project_uuid
}, session_for(which_user)
buttons = css_select('[data-method=post]').select do |el|
- el.attributes['href'].match /project.*owner_uuid.*#{readonly_project_uuid}/
+ el.attributes['data-remote-href'].match /project.*owner_uuid.*#{readonly_project_uuid}/
end
if should_show
assert_not_empty(buttons, "did not offer to create a subproject")
"JSON response missing properly formatted sharing error")
end
- def user_can_manage(user_sym, group_key)
- get(:show, {id: api_fixture("groups")[group_key]["uuid"]},
- session_for(user_sym))
- is_manager = assigns(:user_is_manager)
- assert_not_nil(is_manager, "user_is_manager flag not set")
- if not is_manager
- assert_empty(assigns(:share_links),
- "non-manager has share links set")
- end
- is_manager
- end
-
test "admin can_manage aproject" do
- assert user_can_manage(:admin, "aproject")
+ assert user_can_manage(:admin, api_fixture("groups")["aproject"])
end
test "owner can_manage aproject" do
- assert user_can_manage(:active, "aproject")
+ assert user_can_manage(:active, api_fixture("groups")["aproject"])
end
test "owner can_manage asubproject" do
- assert user_can_manage(:active, "asubproject")
+ assert user_can_manage(:active, api_fixture("groups")["asubproject"])
end
test "viewer can't manage aproject" do
- refute user_can_manage(:project_viewer, "aproject")
+ refute user_can_manage(:project_viewer, api_fixture("groups")["aproject"])
end
test "viewer can't manage asubproject" do
- refute user_can_manage(:project_viewer, "asubproject")
+ refute user_can_manage(:project_viewer, api_fixture("groups")["asubproject"])
end
test "subproject_admin can_manage asubproject" do
- assert user_can_manage(:subproject_admin, "asubproject")
+ assert user_can_manage(:subproject_admin, api_fixture("groups")["asubproject"])
end
test "detect ownership loop in project breadcrumbs" do
assert_response :success
end
- test "project admin can remove items from the project" do
+ test "project admin can remove collections from the project" do
+ # Deleting an object that supports 'trash_at' should make it
+ # completely inaccessible to API queries, not simply moved out of
+ # the project.
coll_key = "collection_to_remove_from_subproject"
coll_uuid = api_fixture("collections")[coll_key]["uuid"]
delete(:remove_item,
assert_response :success
assert_match(/\b#{coll_uuid}\b/, @response.body,
"removed object not named in response")
+
+ use_token :subproject_admin
+ assert_raise ArvadosApiClient::NotFoundException do
+ Collection.find(coll_uuid, cache: false)
+ end
+ end
+
+ test "project admin can remove items from project other than collections" do
+ # An object which does not have an trash_at field (e.g. Specimen)
+ # should be implicitly moved to the user's Home project when removed.
+ specimen_uuid = api_fixture('specimens', 'in_asubproject')['uuid']
+ delete(:remove_item,
+ { id: api_fixture('groups', 'asubproject')['uuid'],
+ item_uuid: specimen_uuid,
+ format: 'js' },
+ session_for(:subproject_admin))
+ assert_response :success
+ assert_match(/\b#{specimen_uuid}\b/, @response.body,
+ "removed object not named in response")
+
+ use_token :subproject_admin
+ new_specimen = Specimen.find(specimen_uuid)
+ assert_equal api_fixture('users', 'subproject_admin')['uuid'], new_specimen.owner_uuid
+ end
+
+ # An object which does not offer an expired_at field but has a xx_owner_uuid_name_unique constraint
+ # will be renamed when removed and another object with the same name exists in user's home project.
+ [
+ ['groups', 'subproject_in_asubproject_with_same_name_as_one_in_active_user_home'],
+ ['pipeline_templates', 'template_in_asubproject_with_same_name_as_one_in_active_user_home'],
+ ].each do |dm, fixture|
+ test "removing #{dm} from a subproject results in renaming it when there is another such object with same name in home project" do
+ object = api_fixture(dm, fixture)
+ delete(:remove_item,
+ { id: api_fixture('groups', 'asubproject')['uuid'],
+ item_uuid: object['uuid'],
+ format: 'js' },
+ session_for(:active))
+ assert_response :success
+ assert_match(/\b#{object['uuid']}\b/, @response.body,
+ "removed object not named in response")
+ use_token :active
+ if dm.eql?('groups')
+ found = Group.find(object['uuid'])
+ else
+ found = PipelineTemplate.find(object['uuid'])
+ end
+ assert_equal api_fixture('users', 'active')['uuid'], found.owner_uuid
+ assert_equal true, found.name.include?(object['name'] + ' removed from ')
+ end
end
test 'projects#show tab infinite scroll partial obeys limit' do
}]
get :show, encoded_params, session_for(:active)
end
+
+ test "visit non-public project as anonymous when anonymous browsing is enabled and expect page not found" do
+ Rails.configuration.anonymous_user_token = api_fixture('api_client_authorizations')['anonymous']['api_token']
+ get(:show, {id: api_fixture('groups')['aproject']['uuid']})
+ assert_response 404
+ assert_match(/log ?in/i, @response.body)
+ end
+
+ test "visit home page as anonymous when anonymous browsing is enabled and expect login" do
+ Rails.configuration.anonymous_user_token = api_fixture('api_client_authorizations')['anonymous']['api_token']
+ get(:index)
+ assert_response :redirect
+ assert_match /\/users\/welcome/, @response.redirect_url
+ end
+
+ [
+ nil,
+ :active,
+ ].each do |user|
+ test "visit public projects page when anon config is enabled, as user #{user}, and expect page" do
+ Rails.configuration.anonymous_user_token = api_fixture('api_client_authorizations')['anonymous']['api_token']
+
+ if user
+ get :public, {}, session_for(user)
+ else
+ get :public
+ end
+
+ assert_response :success
+ assert_not_nil assigns(:objects)
+ project_names = assigns(:objects).collect(&:name)
+ assert_includes project_names, 'Unrestricted public data'
+ assert_not_includes project_names, 'A Project'
+ refute_empty css_select('[href="/projects/public"]')
+ end
+ end
+
+ test "visit public projects page when anon config is not enabled as active user and expect 404" do
+ get :public, {}, session_for(:active)
+ assert_response 404
+ end
+
+ test "visit public projects page when anon config is enabled but public projects page is disabled as active user and expect 404" do
+ Rails.configuration.anonymous_user_token = api_fixture('api_client_authorizations')['anonymous']['api_token']
+ Rails.configuration.enable_public_projects_page = false
+ get :public, {}, session_for(:active)
+ assert_response 404
+ end
+
+ test "visit public projects page when anon config is not enabled as anonymous and expect login page" do
+ get :public
+ assert_response :redirect
+ assert_match /\/users\/welcome/, @response.redirect_url
+ assert_empty css_select('[href="/projects/public"]')
+ end
+
+ test "visit public projects page when anon config is enabled and public projects page is disabled and expect login page" do
+ Rails.configuration.anonymous_user_token = api_fixture('api_client_authorizations')['anonymous']['api_token']
+ Rails.configuration.enable_public_projects_page = false
+ get :index
+ assert_response :redirect
+ assert_match /\/users\/welcome/, @response.redirect_url
+ assert_empty css_select('[href="/projects/public"]')
+ end
+
+ test "visit public projects page when anon config is not enabled and public projects page is enabled and expect login page" do
+ Rails.configuration.enable_public_projects_page = true
+ get :index
+ assert_response :redirect
+ assert_match /\/users\/welcome/, @response.redirect_url
+ assert_empty css_select('[href="/projects/public"]')
+ end
+
+ test "find a project and edit its description" do
+ project = api_fixture('groups')['aproject']
+ use_token :active
+ found = Group.find(project['uuid'])
+ found.description = 'test description update'
+ found.save!
+ get(:show, {id: project['uuid']}, session_for(:active))
+ assert_includes @response.body, 'test description update'
+ end
+
+ test "find a project and edit description to textile description" do
+ project = api_fixture('groups')['aproject']
+ use_token :active
+ found = Group.find(project['uuid'])
+ found.description = '*test bold description for textile formatting*'
+ found.save!
+ get(:show, {id: project['uuid']}, session_for(:active))
+ assert_includes @response.body, '<strong>test bold description for textile formatting</strong>'
+ end
+
+ test "find a project and edit description to html description" do
+ project = api_fixture('groups')['aproject']
+ use_token :active
+ found = Group.find(project['uuid'])
+ found.description = 'Textile description with link to home page <a href="/">take me home</a>.'
+ found.save!
+ get(:show, {id: project['uuid']}, session_for(:active))
+ assert_includes @response.body, 'Textile description with link to home page <a href="/">take me home</a>.'
+ end
+
+ test "find a project and edit description to textile description with link to object" do
+ project = api_fixture('groups')['aproject']
+ use_token :active
+ found = Group.find(project['uuid'])
+
+ # uses 'Link to object' as a hyperlink for the object
+ found.description = '"Link to object":' + api_fixture('groups')['asubproject']['uuid']
+ found.save!
+ get(:show, {id: project['uuid']}, session_for(:active))
+
+ # check that input was converted to textile, not staying as inputted
+ refute_includes @response.body,'"Link to object"'
+ refute_empty css_select('[href="/groups/zzzzz-j7d0g-axqo7eu9pwvna1x"]')
+ end
+
+ test "project viewer can't see project sharing tab" do
+ project = api_fixture('groups')['aproject']
+ get(:show, {id: project['uuid']}, session_for(:project_viewer))
+ refute_includes @response.body, '<div id="Sharing"'
+ assert_includes @response.body, '<div id="Data_collections"'
+ end
+
+ [
+ 'admin',
+ 'active',
+ ].each do |username|
+ test "#{username} can see project sharing tab" do
+ project = api_fixture('groups')['aproject']
+ get(:show, {id: project['uuid']}, session_for(username))
+ assert_includes @response.body, '<div id="Sharing"'
+ assert_includes @response.body, '<div id="Data_collections"'
+ end
+ end
+
+ [
+ ['admin',true],
+ ['active',true],
+ ['project_viewer',false],
+ ].each do |user, can_move|
+ test "#{user} can move subproject from project #{can_move}" do
+ get(:show, {id: api_fixture('groups')['aproject']['uuid']}, session_for(user))
+ if can_move
+ assert_includes @response.body, 'Move project...'
+ else
+ refute_includes @response.body, 'Move project...'
+ end
+ end
+ end
+
+ [
+ [:admin, true],
+ [:active, false],
+ ].each do |user, expect_all_nodes|
+ test "in dashboard other index page links as #{user}" do
+ get :index, {}, session_for(user)
+
+ [["processes", "/all_processes"],
+ ["collections", "/collections"],
+ ].each do |target, path|
+ assert_includes @response.body, "href=\"#{path}\""
+ assert_includes @response.body, "All #{target}"
+ end
+
+ if expect_all_nodes
+ assert_includes @response.body, "href=\"/nodes\""
+ assert_includes @response.body, "All nodes"
+ else
+ assert_not_includes @response.body, "href=\"/nodes\""
+ assert_not_includes @response.body, "All nodes"
+ end
+ end
+ end
+
+ test "dashboard should show the correct status for processes" do
+ get :index, {}, session_for(:active)
+ assert_select 'div.panel-body.recent-processes' do
+ [
+ {
+ fixture: 'container_requests',
+ state: 'completed',
+ selectors: [['div.progress', false],
+ ['span.label.label-success', true, 'Complete']]
+ },
+ {
+ fixture: 'container_requests',
+ state: 'uncommitted',
+ selectors: [['div.progress', false],
+ ['span.label.label-default', true, 'Uncommitted']]
+ },
+ {
+ fixture: 'container_requests',
+ state: 'queued',
+ selectors: [['div.progress', false],
+ ['span.label.label-default', true, 'Queued']]
+ },
+ {
+ fixture: 'container_requests',
+ state: 'running',
+ selectors: [['div.progress', true]]
+ },
+ {
+ fixture: 'pipeline_instances',
+ state: 'new_pipeline',
+ selectors: [['div.progress', false],
+ ['span.label.label-default', true, 'Not started']]
+ },
+ {
+ fixture: 'pipeline_instances',
+ state: 'pipeline_in_running_state',
+ selectors: [['div.progress', true]]
+ },
+ ].each do |c|
+ uuid = api_fixture(c[:fixture])[c[:state]]['uuid']
+ assert_select "div.dashboard-panel-info-row.row-#{uuid}" do
+ if c.include? :selectors
+ c[:selectors].each do |selector, should_show, label|
+ assert_select selector, should_show, "UUID #{uuid} should #{should_show ? '' : 'not'} show '#{selector}'"
+ if should_show and not label.nil?
+ assert_select selector, label, "UUID #{uuid} state label should show #{label}"
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ test "visit a public project and verify the public projects page link exists" do
+ Rails.configuration.anonymous_user_token = api_fixture('api_client_authorizations')['anonymous']['api_token']
+ uuid = api_fixture('groups')['anonymously_accessible_project']['uuid']
+ get :show, {id: uuid}
+ project = assigns(:object)
+ assert_equal uuid, project['uuid']
+ refute_empty css_select("[href=\"/projects/#{project['uuid']}\"]")
+ assert_includes @response.body, "<a href=\"/projects/public\">Public Projects</a>"
+ end
+
+ test 'all_projects unaffected by params after use by ProjectsController (#6640)' do
+ @controller = ProjectsController.new
+ project_uuid = api_fixture('groups')['aproject']['uuid']
+ get :index, {
+ filters: [['uuid', '<', project_uuid]].to_json,
+ limit: 0,
+ offset: 1000,
+ }, session_for(:active)
+ assert_select "#projects-menu + ul li.divider ~ li a[href=/projects/#{project_uuid}]"
+ end
+
+ [
+ ["active", 5, ["aproject", "asubproject"], "anonymously_accessible_project"],
+ ["user1_with_load", 2, ["project_with_10_collections"], "project_with_2_pipelines_and_60_crs"],
+ ["admin", 5, ["anonymously_accessible_project", "subproject_in_anonymous_accessible_project"], "aproject"],
+ ].each do |user, page_size, tree_segment, unexpected|
+ # Note: this test is sensitive to database collation. It passes
+ # with en_US.UTF-8.
+ test "build my projects tree for #{user} user and verify #{unexpected} is omitted" do
+ use_token user
+
+ tree, _, _ = @controller.send(:my_wanted_projects_tree,
+ User.current,
+ page_size)
+
+ tree_segment_at_depth_1 = api_fixture('groups')[tree_segment[0]]
+ tree_segment_at_depth_2 = api_fixture('groups')[tree_segment[1]] if tree_segment[1]
+
+ node_depth = {}
+ tree.each do |x|
+ node_depth[x[:object]['uuid']] = x[:depth]
+ end
+
+ assert_equal(1, node_depth[tree_segment_at_depth_1['uuid']])
+ assert_equal(2, node_depth[tree_segment_at_depth_2['uuid']]) if tree_segment[1]
+
+ unexpected_project = api_fixture('groups')[unexpected]
+ assert_nil(node_depth[unexpected_project['uuid']], node_depth.inspect)
+ end
+ end
+
+ [
+ ["active", 1],
+ ["project_viewer", 1],
+ ["admin", 0],
+ ].each do |user, size|
+ test "starred projects for #{user}" do
+ use_token user
+ ctrl = ProjectsController.new
+ current_user = User.find(api_fixture('users')[user]['uuid'])
+ my_starred_project = ctrl.send :my_starred_projects, current_user
+ assert_equal(size, my_starred_project.andand.size)
+
+ ctrl2 = ProjectsController.new
+ current_user = User.find(api_fixture('users')[user]['uuid'])
+ my_starred_project = ctrl2.send :my_starred_projects, current_user
+ assert_equal(size, my_starred_project.andand.size)
+ end
+ end
+
+ test "unshare project and verify that it is no longer included in shared user's starred projects" do
+ # remove sharing link
+ use_token :system_user
+ Link.find(api_fixture('links')['share_starred_project_with_project_viewer']['uuid']).destroy
+
+ # verify that project is no longer included in starred projects
+ use_token :project_viewer
+ current_user = User.find(api_fixture('users')['project_viewer']['uuid'])
+ ctrl = ProjectsController.new
+ my_starred_project = ctrl.send :my_starred_projects, current_user
+ assert_equal(0, my_starred_project.andand.size)
+
+ # share it again
+ @controller = LinksController.new
+ post :create, {
+ link: {
+ link_class: 'permission',
+ name: 'can_read',
+ head_uuid: api_fixture('groups')['starred_and_shared_active_user_project']['uuid'],
+ tail_uuid: api_fixture('users')['project_viewer']['uuid'],
+ },
+ format: :json
+ }, session_for(:system_user)
+
+ # verify that the project is again included in starred projects
+ use_token :project_viewer
+ ctrl = ProjectsController.new
+ my_starred_project = ctrl.send :my_starred_projects, current_user
+ assert_equal(1, my_starred_project.andand.size)
+ end
end