-
Headers
+
-
Response body
+
<%= log_entry.response_body %>
diff --git a/spec/controllers/wiki_controller_spec.rb b/spec/controllers/wiki_controller_spec.rb
index bd623e6339..a161d33837 100644
--- a/spec/controllers/wiki_controller_spec.rb
+++ b/spec/controllers/wiki_controller_spec.rb
@@ -34,6 +34,7 @@ describe WikiController, type: :controller do
shared_let(:project) do
create(:project).tap(&:reload)
end
+ shared_let(:wiki) { project.wiki }
shared_let(:existing_page) do
create(:wiki_page, wiki_id: project.wiki.id, title: 'ExistingPage')
@@ -47,7 +48,29 @@ describe WikiController, type: :controller do
describe 'actions' do
before do
allow(controller).to receive(:set_localization)
- login_as admin
+ end
+
+ current_user { admin }
+
+ describe 'index' do
+ before do
+ get :index, params: { project_id: project.identifier }
+ end
+
+ it 'is successful' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the index template' do
+ expect(response)
+ .to render_template(:index)
+ end
+
+ it 'assigns pages' do
+ expect(assigns[:pages])
+ .to eq project.wiki.pages
+ end
end
shared_examples_for "a 'new' action" do
@@ -105,27 +128,255 @@ describe WikiController, type: :controller do
end
describe 'show' do
- let(:get_page) { get :show, params: { project_id: project, id: 'wiki' } }
+ let(:permissions) { %w[view_wiki_pages] }
+ let(:user) { create(:user, member_in_project: project, member_with_permissions: permissions) }
- describe 'with an empty wiki and no permission to edit' do
- let(:view_role) { create :role, permissions: %w[view_wiki_pages] }
- let(:user) { create(:user, member_in_project: project, member_through_role: view_role) }
+ current_user { user }
- it 'visiting the start page redirects to index' do
- login_as user
- get_page
+ before do
+ get_page
+ end
+
+ context 'when querying for an existing page' do
+ let(:get_page) { get :show, params: { project_id: project, id: existing_page.title } }
+
+ it 'is a success' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the show template' do
+ expect(response)
+ .to render_template(:show)
+ end
+
+ it 'assigns the page' do
+ expect(assigns[:page])
+ .to eql existing_page
+ end
+
+ it 'assigns the content' do
+ expect(assigns[:content])
+ .to eql existing_content
+ end
+ end
+
+ context 'when querying for the wiki root page with edit permissions' do
+ let(:get_page) { get :show, params: { project_id: project, id: 'wiki' } }
+ let(:permissions) { %w[view_wiki_pages edit_wiki_pages] }
+
+ it 'is a success' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the new template' do
+ expect(response)
+ .to render_template(:new)
+ end
+
+ it 'assigns a new page that is unpersisted' do
+ expect(assigns[:page])
+ .to be_a WikiPage
+
+ expect(assigns[:page])
+ .to be_new_record
+ end
+
+ it 'assigns a new content that is unpersisted' do
+ expect(assigns[:content])
+ .to be_a WikiContent
+
+ expect(assigns[:content])
+ .to be_new_record
+ end
+ end
+
+ context 'when querying for an unexisting page with edit permissions' do
+ let(:get_page) { get :show, params: { project_id: project, id: 'new_page' } }
+ let(:permissions) { %w[view_wiki_pages edit_wiki_pages] }
+
+ it 'is a success' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the new template' do
+ expect(response)
+ .to render_template(:new)
+ end
+
+ it 'assigns a new page that is unpersisted' do
+ expect(assigns[:page])
+ .to be_a WikiPage
+
+ expect(assigns[:page])
+ .to be_new_record
+ end
+
+ it 'assigns a new content that is unpersisted' do
+ expect(assigns[:content])
+ .to be_a WikiContent
+
+ expect(assigns[:content])
+ .to be_new_record
+ end
+ end
+
+ context 'when querying for no specific page' do
+ let(:get_page) do
+ project.wiki.update_column(:start_page, existing_page.title)
+
+ get :show, params: { project_id: project }
+ end
+
+ it 'is a success' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the show template' do
+ expect(response)
+ .to render_template(:show)
+ end
+
+ it 'assigns the wiki start page' do
+ expect(assigns[:page])
+ .to eql existing_page
+ end
+
+ it 'assigns the wiki start page content' do
+ expect(assigns[:content])
+ .to eql existing_content
+ end
+ end
+
+ context 'when querying for the wiki root page without edit permissions' do
+ let(:get_page) { get :show, params: { project_id: project, id: 'wiki' } }
+
+ it 'redirects to index' do
expect(response).to redirect_to action: :index
+ end
+
+ it 'shows a flash info' do
expect(flash[:info]).to include I18n.t('wiki.page_not_editable_index')
end
end
+
+ context 'when querying for a non existing page without edit permissions' do
+ let(:get_page) { get :show, params: { project_id: project, id: 'new_page' } }
+
+ it 'returns 404' do
+ expect(response)
+ .to have_http_status(:not_found)
+ end
+ end
end
describe 'edit' do
- it 'will link to a parent page if it was set' do
- get 'edit', params: { project_id: project, id: 'foobar' }, flash: { _related_wiki_page_id: 1234 }
+ let(:permissions) { %i[view_wiki_pages edit_wiki_pages] }
+
+ let(:params) do
+ { project_id: project, id: existing_page.title }
+ end
+ let(:flash) do
+ {}
+ end
+
+ current_user { create(:user, member_in_project: project, member_with_permissions: permissions) }
+
+ before do
+ get :edit, params:, flash:
+ end
+
+ context 'with an existing wiki page' do
+ let(:params) do
+ { project_id: project, id: existing_page.title }
+ end
+
+ it 'is sucessful' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the edit template' do
+ expect(response)
+ .to render_template :edit
+ end
- page = assigns[:page]
- expect(page.parent_id).to eq 1234
+ it 'assigns the page' do
+ expect(assigns[:page])
+ .to eq existing_page
+
+ expect(assigns[:page])
+ .not_to be_changed
+ end
+ end
+
+ context 'with an existing wiki page that is protected' do
+ let(:params) do
+ existing_page.update_column(:protected, true)
+ { project_id: project, id: existing_page.title }
+ end
+
+ it 'is forbiddend' do
+ expect(response)
+ .to have_http_status(:forbidden)
+ end
+ end
+
+ context 'with an existing wiki page that is protected and having the necessary permission' do
+ let(:permissions) do
+ existing_page.update_column(:protected, true)
+
+ %i[view_wiki_pages edit_wiki_pages protect_wiki_pages]
+ end
+
+ it 'is sucessful' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the edit template' do
+ expect(response)
+ .to render_template :edit
+ end
+
+ it 'assigns the page' do
+ expect(assigns[:page])
+ .to eq existing_page
+
+ expect(assigns[:page])
+ .not_to be_changed
+ end
+ end
+
+ context 'with a related wiki page in the flash and a non existing wiki page' do
+ let(:flash) { { _related_wiki_page_id: 1234 } }
+ let(:params) do
+ { project_id: project, id: 'foobar' }
+ end
+
+ it 'is sucessful' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the edit template' do
+ expect(response)
+ .to render_template :edit
+ end
+
+ it 'assigns @page to a new wiki page with the parent id set' do
+ expect(assigns[:page])
+ .to be_a WikiPage
+
+ expect(assigns[:page])
+ .to be_new_record
+
+ expect(assigns[:page].parent_id)
+ .to eql flash[:_related_wiki_page_id]
+ end
end
end
@@ -233,26 +484,521 @@ describe WikiController, type: :controller do
end
describe 'destroy' do
- describe 'successful action' do
- context 'when it is not the only wiki page' do
- let(:wiki) { project.wiki }
- let(:redirect_page_after_destroy) { wiki.find_page(wiki.start_page) || wiki.pages.first }
+ shared_let(:parent_page) { create(:wiki_page, wiki:) }
+ shared_let(:child_page) { create(:wiki_page, wiki:, parent: parent_page) }
- before do
- create :wiki_page, wiki:
- end
+ let(:redirect_page_after_destroy) { wiki.find_page(wiki.start_page) || wiki.pages.first }
- it 'redirects to wiki#index' do
- delete :destroy, params: { project_id: project, id: existing_page }
- expect(response).to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy
- end
+ let(:params) do
+ { project_id: project, id: existing_page }
+ end
+
+ subject do
+ delete :destroy, params: params
+
+ response
+ end
+
+ context 'when it is not the only wiki page' do
+ it 'redirects to wiki#index' do
+ expect(subject)
+ .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy
end
- context 'when it is the only wiki page' do
- it 'redirects to projects#show' do
- delete :destroy, params: { project_id: project, id: existing_page }
- expect(response).to redirect_to project_path(project)
- end
+ it 'destroys the page' do
+ expect { subject }
+ .to change { WikiPage.where(id: existing_page.id).count }
+ .from(1)
+ .to(0)
+ end
+ end
+
+ context 'when it is the only wiki page' do
+ before do
+ WikiPage.where.not(id: existing_page.id).destroy_all
+ end
+
+ it 'redirects to projects#show' do
+ expect(subject)
+ .to redirect_to project_path(project)
+ end
+
+ it 'destroys the page' do
+ expect { subject }
+ .to change { WikiPage.where(id: existing_page.id).count }
+ .from(1)
+ .to(0)
+ end
+ end
+
+ context 'when destroying a child' do
+ let(:params) do
+ { project_id: project, id: child_page }
+ end
+
+ it 'redirects to wiki#index' do
+ expect(subject)
+ .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy
+ end
+
+ it 'destroys the page' do
+ expect { subject }
+ .to change { WikiPage.where(id: child_page.id).count }
+ .from(1)
+ .to(0)
+ end
+ end
+
+ context 'when destroying a parent without specifying todo' do
+ let(:params) do
+ { project_id: project, id: parent_page }
+ end
+
+ it 'responds with success' do
+ expect(subject)
+ .to have_http_status(:ok)
+ end
+
+ it 'destroys the page' do
+ expect { subject }
+ .not_to change(WikiPage, :count)
+ end
+ end
+
+ context 'when destroying a parent with nullify' do
+ let(:params) do
+ { project_id: project, id: parent_page, todo: 'nullify' }
+ end
+
+ it 'redirects to wiki#index' do
+ expect(subject)
+ .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy
+ end
+
+ it 'destroys the page' do
+ expect { subject }
+ .to change { WikiPage.where(id: parent_page.id).count }
+ .from(1)
+ .to(0)
+ end
+
+ it 'sets the parent_id of the child to nil' do
+ subject
+
+ expect(child_page.parent_id)
+ .to be_nil
+ end
+ end
+
+ context 'when destroying a parent with todo = destroy' do
+ let(:params) do
+ { project_id: project, id: parent_page, todo: 'destroy' }
+ end
+
+ it 'redirects to wiki#index' do
+ expect(subject)
+ .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy
+ end
+
+ it 'destroys the page' do
+ expect { subject }
+ .to change { WikiPage.where(id: [parent_page, child_page]).count }
+ .from(2)
+ .to(0)
+ end
+ end
+
+ context 'when destroying a parent with reassign' do
+ let(:params) do
+ { project_id: project, id: parent_page, todo: 'reassign', reassign_to_id: existing_page.id }
+ end
+
+ it 'redirects to wiki#index' do
+ expect(subject)
+ .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy
+ end
+
+ it 'destroys the page' do
+ expect { subject }
+ .to change { WikiPage.where(id: parent_page).count }
+ .from(1)
+ .to(0)
+ end
+
+ it 'sets the parent_id of the child to the specified page' do
+ subject
+
+ expect(child_page.parent_id)
+ .to eq existing_page.id
+ end
+ end
+ end
+
+ describe 'rename' do
+ shared_let(:parent_page) { create(:wiki_page, wiki:) }
+ shared_let(:child_page) { create(:wiki_page, wiki:, parent: parent_page) }
+
+ let(:permissions) { %i[view_wiki_pages rename_wiki_pages edit_wiki_pages] }
+
+ let(:params) do
+ { project_id: project, id: existing_page.title }
+ end
+
+ let(:request) do
+ get :rename, params:
+ end
+
+ current_user { create(:user, member_in_project: project, member_with_permissions: permissions) }
+
+ subject do
+ request
+
+ response
+ end
+
+ context 'when getting for a page' do
+ it 'is success' do
+ expect(subject)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the template' do
+ expect(subject)
+ .to render_template :rename
+ end
+ end
+
+ context 'when getting for a child page' do
+ let(:params) do
+ { project_id: project, id: child_page.title }
+ end
+
+ it 'is success' do
+ expect(subject)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the template' do
+ expect(subject)
+ .to render_template :rename
+ end
+ end
+
+ context 'when getting for a page without permissions' do
+ let(:permissions) { %i[view_wiki_pages] }
+
+ it 'is forbidden' do
+ expect(subject)
+ .to have_http_status(:forbidden)
+ end
+ end
+
+ context 'when patching with redirect' do
+ let(:new_title) { 'The new page title' }
+ let!(:old_title) { existing_page.title }
+
+ let(:params) do
+ {
+ project_id: project,
+ id: existing_page.title,
+ page: {
+ title: new_title,
+ redirect_existing_links: 1
+ }
+ }
+ end
+
+ let(:request) do
+ patch :rename, params:
+ end
+
+ it 'redirects to the show page with the altered name' do
+ expect(subject)
+ .to redirect_to action: 'show', project_id: project.identifier, id: 'the-new-page-title'
+ end
+
+ it 'renames the page' do
+ subject
+
+ expect(existing_page.reload.title)
+ .to eql new_title
+ end
+
+ it 'finds the page by the old name' do
+ subject
+
+ expect(wiki.find_page(old_title))
+ .to eql existing_page
+ end
+ end
+
+ context 'when patching without redirect' do
+ let(:new_title) { 'The new page title' }
+ let!(:old_title) { existing_page.title }
+
+ let(:params) do
+ {
+ project_id: project,
+ id: existing_page.title,
+ page: {
+ title: new_title,
+ redirect_existing_links: '0'
+ }
+ }
+ end
+
+ let(:request) do
+ patch :rename, params:
+ end
+
+ it 'redirects to the show page with the altered name' do
+ expect(subject)
+ .to redirect_to action: 'show', project_id: project.identifier, id: 'the-new-page-title'
+ end
+
+ it 'renames the page' do
+ subject
+
+ expect(existing_page.reload.title)
+ .to eql new_title
+ end
+
+ it 'does not find the page by the old name' do
+ subject
+
+ expect(wiki.find_page(old_title))
+ .to be_nil
+ end
+ end
+ end
+
+ describe 'diffs' do
+ let!(:journal_from) { existing_content.journals.last }
+ let!(:journal_to) do
+ existing_content.text = 'new_text'
+ existing_content.save
+
+ existing_content.journals.reload.last
+ end
+
+ let(:permissions) { %i[view_wiki_pages view_wiki_edits] }
+
+ let(:params) do
+ {
+ project_id: project,
+ id: existing_page.title,
+ version: journal_to.version,
+ version_from: journal_from.version
+ }
+ end
+
+ let(:request) do
+ get :diff, params:
+ end
+
+ current_user { create(:user, member_in_project: project, member_with_permissions: permissions) }
+
+ subject do
+ request
+
+ response
+ end
+
+ it 'is success' do
+ expect(subject)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the template' do
+ expect(subject)
+ .to render_template :diff
+ end
+
+ it 'assigns html_diff' do
+ subject
+
+ expect(assigns[:html_diff])
+ .to be_a(String)
+ end
+ end
+
+ describe 'annotates' do
+ let!(:journal_from) { existing_content.journals.last }
+ let!(:journal_to) do
+ existing_content.text = 'new_text'
+ existing_content.save
+
+ existing_content.journals.reload.last
+ end
+
+ let(:permissions) { %i[view_wiki_pages view_wiki_edits] }
+
+ let(:params) do
+ { project_id: project, id: existing_page.title, version: journal_to.version }
+ end
+
+ let(:request) do
+ get :annotate, params:
+ end
+
+ current_user { create(:user, member_in_project: project, member_with_permissions: permissions) }
+
+ subject do
+ request
+
+ response
+ end
+
+ it 'is success' do
+ expect(subject)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the template' do
+ expect(subject)
+ .to render_template :annotate
+ end
+ end
+
+ describe 'export' do
+ let(:permissions) { %i[view_wiki_pages export_wiki_pages] }
+
+ current_user { create(:user, member_in_project: project, member_with_permissions: permissions) }
+
+ before do
+ get :export, params: { project_id: project.identifier }
+ end
+
+ it 'is successful' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'assigns pages' do
+ expect(assigns[:pages])
+ .to eq project.wiki.pages
+ end
+
+ it 'is an html response' do
+ expect(response.content_type)
+ .to eq 'text/html'
+ end
+
+ context 'for an unauthorized user' do
+ let(:permissions) { %i[view_wiki_pages] }
+
+ it 'prevents access' do
+ expect(response)
+ .to have_http_status(:forbidden)
+ end
+ end
+ end
+
+ describe 'protect' do
+ let(:permissions) { %i[view_wiki_pages protect_wiki_pages] }
+
+ let(:params) do
+ { project_id: project, id: existing_page.title, protected: '1' }
+ end
+
+ let(:request) do
+ post :protect, params:
+ end
+
+ current_user { create(:user, member_in_project: project, member_with_permissions: permissions) }
+
+ subject do
+ request
+ response
+ end
+
+ context 'with an existing wiki page' do
+ it 'set the protected property of the page' do
+ expect { subject }
+ .to change { existing_page.reload.protected? }
+ .from(false)
+ .to(true)
+ end
+
+ it 'redirects to the show page' do
+ expect(subject)
+ .to redirect_to action: 'show', project_id: project.identifier, id: existing_page.title.downcase
+ end
+ end
+
+ context 'with an existing wiki page that is protected' do
+ let(:permissions) do
+ existing_page.update_column :protected, true
+
+ %i[view_wiki_pages protect_wiki_pages]
+ end
+
+ let(:params) do
+ { project_id: project, id: existing_page.title, protected: '0' }
+ end
+
+ it 'set the protected property of the page' do
+ expect { subject }
+ .to change { existing_page.reload.protected? }
+ .from(true)
+ .to(false)
+ end
+
+ it 'redirects to the show page' do
+ expect(subject)
+ .to redirect_to action: 'show', project_id: project.identifier, id: existing_page.title.downcase
+ end
+ end
+
+ context 'with an existing wiki page but missing permissions' do
+ let(:permissions) do
+ %i[view_wiki_pages]
+ end
+
+ it 'does not change the protected property of the page' do
+ expect { subject }
+ .not_to change { existing_page.reload.protected? }
+ end
+
+ it 'return forbidden' do
+ expect(subject)
+ .to have_http_status(:forbidden)
+ end
+ end
+ end
+
+ describe 'history' do
+ let(:permissions) { %i[view_wiki_edits] }
+
+ current_user { create(:user, member_in_project: project, member_with_permissions: permissions) }
+
+ before do
+ get :history, params: { project_id: project.identifier, id: existing_page.title }
+ end
+
+ it 'is successful' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the template' do
+ expect(response)
+ .to render_template :history
+ end
+
+ it 'assigns versions' do
+ expect(assigns[:versions])
+ .to eq existing_content.journals
+ end
+
+ context 'for a non existing page' do
+ before do
+ get :history, params: { project_id: project.identifier, id: 'bogus' }
+ end
+
+ it 'states not found' do
+ expect(response)
+ .to have_http_status(:not_found)
end
end
end
diff --git a/spec/controllers/workflows_controller_spec.rb b/spec/controllers/workflows_controller_spec.rb
index c1f7bbfbda..2346393c56 100644
--- a/spec/controllers/workflows_controller_spec.rb
+++ b/spec/controllers/workflows_controller_spec.rb
@@ -29,30 +29,45 @@
require 'spec_helper'
describe WorkflowsController, type: :controller do
- let(:current_user) { build_stubbed(:admin) }
let!(:role) do
build_stubbed(:role).tap do |r|
allow(Role)
.to receive(:find)
- .with(r.id.to_s)
- .and_return(r)
+ .with(r.id.to_s)
+ .and_return(r)
+
+ allow(Role)
+ .to receive(:find_by)
+ .and_return(nil)
+
+ allow(Role)
+ .to receive(:find_by)
+ .with(id: r.id.to_s)
+ .and_return(r)
end
end
let!(:type) do
- build_stubbed(:type) do |t|
+ build_stubbed(:type).tap do |t|
allow(Type)
.to receive(:find)
- .with(t.id.to_s)
- .and_return(t)
+ .with(t.id.to_s)
+ .and_return(t)
+
+ allow(Type)
+ .to receive(:find_by)
+ .and_return(nil)
+
+ allow(Type)
+ .to receive(:find_by)
+ .with(id: t.id.to_s)
+ .and_return(t)
end
end
- before do
- login_as(current_user)
- end
+ current_user { build_stubbed(:admin) }
describe '#index' do
- let(:counts) { double('wf counts') }
+ let(:counts) { instance_double(Hash) }
before do
allow(Workflow)
@@ -73,10 +88,151 @@ describe WorkflowsController, type: :controller do
end
end
+ describe '#edit' do
+ let(:non_type_status) { build_stubbed(:status) }
+ let(:type_status) { build_stubbed(:status) }
+
+ before do
+ allow(type)
+ .to receive(:statuses)
+ .and_return [type_status]
+
+ allow(Status)
+ .to receive(:all)
+ .and_return [type_status, non_type_status]
+
+ allow(Type)
+ .to receive(:order)
+ .and_return([type])
+
+ allow(Role)
+ .to receive(:order)
+ .and_return([role])
+ end
+
+ context 'without parameters' do
+ before do
+ get :edit
+ end
+
+ it 'is successful' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the edit template' do
+ expect(response)
+ .to render_template :edit
+ end
+
+ it 'does not assign role' do
+ expect(assigns[:role])
+ .to be_nil
+ end
+
+ it 'does not assign type' do
+ expect(assigns[:type])
+ .to be_nil
+ end
+
+ it 'assigns roles' do
+ expect(assigns[:roles])
+ .to eq [role]
+ end
+
+ it 'assigns types' do
+ expect(assigns[:types])
+ .to eq [type]
+ end
+ end
+
+ context 'with role and type params' do
+ before do
+ get :edit, params: { role_id: role.id.to_s, type_id: type.id.to_s }
+ end
+
+ it 'is successful' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the edit template' do
+ expect(response)
+ .to render_template :edit
+ end
+
+ it 'assigns role' do
+ expect(assigns[:role])
+ .to eq role
+ end
+
+ it 'assign type' do
+ expect(assigns[:type])
+ .to eq type
+ end
+
+ it 'assigns roles' do
+ expect(assigns[:roles])
+ .to eq [role]
+ end
+
+ it 'assigns types' do
+ expect(assigns[:types])
+ .to eq [type]
+ end
+
+ it 'assigns statuses' do
+ expect(assigns[:statuses])
+ .to eq type.statuses
+ end
+ end
+
+ context 'with role and type params and with all statuses' do
+ before do
+ get :edit, params: { role_id: role.id.to_s, type_id: type.id.to_s, used_statuses_only: '0' }
+ end
+
+ it 'is successful' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the edit template' do
+ expect(response)
+ .to render_template :edit
+ end
+
+ it 'assigns role' do
+ expect(assigns[:role])
+ .to eq role
+ end
+
+ it 'assign type' do
+ expect(assigns[:type])
+ .to eq type
+ end
+
+ it 'assigns roles' do
+ expect(assigns[:roles])
+ .to eq [role]
+ end
+
+ it 'assigns types' do
+ expect(assigns[:types])
+ .to eq [type]
+ end
+
+ it 'assigns statuses' do
+ expect(assigns[:statuses])
+ .to eq Status.all
+ end
+ end
+ end
+
describe '#update' do
let(:status_params) { { "1" => "2" } }
let(:service) do
- service = double('service')
+ service = instance_double(Workflows::BulkUpdateService)
allow(Workflows::BulkUpdateService)
.to receive(:new)
@@ -109,4 +265,244 @@ describe WorkflowsController, type: :controller do
.to redirect_to edit_workflows_path(role_id: role.id, type_id: type.id)
end
end
+
+ describe '#copy' do
+ let(:target_type1) { build_stubbed(:type) }
+ let(:target_type2) { build_stubbed(:type) }
+
+ let(:target_role1) { build_stubbed(:role) }
+ let(:target_role2) { build_stubbed(:role) }
+
+ let(:params) do
+ {
+ source_type_id: type.id.to_s,
+ source_role_id: role.id.to_s,
+ target_type_ids: [target_type1.id.to_s, target_type2.id.to_s],
+ target_role_ids: [target_role1.id.to_s, target_role2.id.to_s]
+ }
+ end
+
+ before do
+ allow(Role)
+ .to receive(:where)
+ .with(id: [target_role1.id.to_s, target_role2.id.to_s])
+ .and_return([target_role1, target_role2])
+
+ allow(Type)
+ .to receive(:where)
+ .with(id: [target_type1.id.to_s, target_type2.id.to_s])
+ .and_return([target_type1, target_type2])
+
+ allow(Workflow)
+ .to receive(:copy)
+ end
+
+ context 'with a get request' do
+ before do
+ get :copy, params:
+ end
+
+ it 'is a success' do
+ expect(response)
+ .to have_http_status(:ok)
+ end
+
+ it 'renders the copy template' do
+ expect(response)
+ .to render_template :copy
+ end
+
+ it 'assigns the source_type' do
+ expect(assigns[:source_type])
+ .to eq type
+ end
+
+ it 'assigns the source_role' do
+ expect(assigns[:source_role])
+ .to eq role
+ end
+
+ it 'assigns the target_types' do
+ expect(assigns[:target_types])
+ .to eq [target_type1, target_type2]
+ end
+
+ it 'assigns the target_roles' do
+ expect(assigns[:target_roles])
+ .to eq [target_role1, target_role2]
+ end
+ end
+
+ context 'when posting with all the params' do
+ before do
+ post :copy, params:
+ end
+
+ it 'calls the Workflow.copy method' do
+ expect(Workflow)
+ .to have_received(:copy)
+ .with(type, role, [target_type1, target_type2], [target_role1, target_role2])
+ end
+
+ it 'sets a flash notice' do
+ expect(flash[:notice])
+ .to eq I18n.t(:notice_successful_update)
+ end
+
+ it 'redirects to the copy action' do
+ expect(response)
+ .to redirect_to copy_workflows_path(source_type_id: type, source_role_id: role)
+ end
+ end
+
+ context 'when posting with \'any\' for source_type' do
+ let(:params) do
+ {
+ source_type_id: 'any',
+ source_role_id: role.id.to_s,
+ target_type_ids: [target_type1.id.to_s, target_type2.id.to_s],
+ target_role_ids: [target_role1.id.to_s, target_role2.id.to_s]
+ }
+ end
+
+ before do
+ post :copy, params:
+ end
+
+ it 'calls the Workflow.copy method' do
+ expect(Workflow)
+ .to have_received(:copy)
+ .with(nil, role, [target_type1, target_type2], [target_role1, target_role2])
+ end
+
+ it 'sets a flash notice' do
+ expect(flash[:notice])
+ .to eq I18n.t(:notice_successful_update)
+ end
+
+ it 'redirects to the copy action' do
+ expect(response)
+ .to redirect_to copy_workflows_path(source_role_id: role)
+ end
+ end
+
+ context 'when posting with \'any\' for source_role' do
+ let(:params) do
+ {
+ source_type_id: type.id.to_s,
+ source_role_id: 'any',
+ target_type_ids: [target_type1.id.to_s, target_type2.id.to_s],
+ target_role_ids: [target_role1.id.to_s, target_role2.id.to_s]
+ }
+ end
+
+ before do
+ post :copy, params:
+ end
+
+ it 'calls the Workflow.copy method' do
+ expect(Workflow)
+ .to have_received(:copy)
+ .with(type, nil, [target_type1, target_type2], [target_role1, target_role2])
+ end
+
+ it 'sets a flash notice' do
+ expect(flash[:notice])
+ .to eq I18n.t(:notice_successful_update)
+ end
+
+ it 'redirects to the copy action' do
+ expect(response)
+ .to redirect_to copy_workflows_path(source_type_id: type)
+ end
+ end
+
+ context 'when posting with \'any\' for both sources' do
+ let(:params) do
+ {
+ source_type_id: 'any',
+ source_role_id: 'any',
+ target_type_ids: [target_type1.id.to_s, target_type2.id.to_s],
+ target_role_ids: [target_role1.id.to_s, target_role2.id.to_s]
+ }
+ end
+
+ before do
+ post :copy, params:
+ end
+
+ it 'does not call the Workflow.copy method' do
+ expect(Workflow)
+ .not_to have_received(:copy)
+ end
+
+ it 'sets a flash error' do
+ expect(flash[:error])
+ .to eq I18n.t(:error_workflow_copy_source)
+ end
+
+ it 'renders the copy action' do
+ expect(response)
+ .to render_template :copy
+ end
+ end
+
+ context 'when posting without target_type_ids' do
+ let(:params) do
+ {
+ source_type_id: type.id.to_s,
+ source_role_id: role.id.to_s,
+ target_role_ids: [target_role1.id.to_s, target_role2.id.to_s]
+ }
+ end
+
+ before do
+ post :copy, params:
+ end
+
+ it 'does not call the Workflow.copy method' do
+ expect(Workflow)
+ .not_to have_received(:copy)
+ end
+
+ it 'sets a flash error' do
+ expect(flash[:error])
+ .to eq I18n.t(:error_workflow_copy_target)
+ end
+
+ it 'renders the copy action' do
+ expect(response)
+ .to render_template :copy
+ end
+ end
+
+ context 'when posting without target_role_ids' do
+ let(:params) do
+ {
+ source_type_id: type.id.to_s,
+ source_role_id: role.id.to_s,
+ target_type_ids: [target_type1.id.to_s, target_type2.id.to_s]
+ }
+ end
+
+ before do
+ post :copy, params:
+ end
+
+ it 'does not call the Workflow.copy method' do
+ expect(Workflow)
+ .not_to have_received(:copy)
+ end
+
+ it 'sets a flash error' do
+ expect(flash[:error])
+ .to eq I18n.t(:error_workflow_copy_target)
+ end
+
+ it 'renders the copy action' do
+ expect(response)
+ .to render_template :copy
+ end
+ end
+ end
end
diff --git a/spec/factories/custom_field_factory.rb b/spec/factories/custom_field_factory.rb
index e9c004cac1..366633704d 100644
--- a/spec/factories/custom_field_factory.rb
+++ b/spec/factories/custom_field_factory.rb
@@ -136,6 +136,47 @@ FactoryBot.define do
end
end
+ factory :group_custom_field, class: 'GroupCustomField' do
+ sequence(:name) { |n| "User Custom Field #{n}" }
+ type { 'GroupCustomField' }
+
+ factory :boolean_group_custom_field do
+ name { 'BooleanGroupCustomField' }
+ field_format { 'bool' }
+ end
+
+ factory :integer_group_custom_field do
+ name { 'IntegerGroupCustomField' }
+ field_format { 'int' }
+ end
+
+ factory :text_group_custom_field do
+ name { 'TextGroupCustomField' }
+ field_format { 'text' }
+ end
+
+ factory :string_group_custom_field do
+ name { 'StringGroupCustomField' }
+ field_format { 'string' }
+ end
+
+ factory :float_group_custom_field do
+ name { 'FloatGroupCustomField' }
+ field_format { 'float' }
+ end
+
+ factory :list_group_custom_field do
+ name { 'ListGroupCustomField' }
+ field_format { 'list' }
+ possible_values { ['1', '2', '3', '4', '5', '6', '7'] }
+ end
+
+ factory :date_group_custom_field do
+ name { 'DateGroupCustomField' }
+ field_format { 'date' }
+ end
+ end
+
factory :wp_custom_field, class: 'WorkPackageCustomField' do
sequence(:name) { |n| "Work package custom field #{n}" }
type { 'WorkPackageCustomField' }
@@ -208,8 +249,44 @@ FactoryBot.define do
end
factory :time_entry_custom_field, class: 'TimeEntryCustomField' do
- field_format { 'text' }
- sequence(:name) { |n| "TimeEntryCustomField #{n}" }
+ sequence(:name) { |n| "User Custom Field #{n}" }
+ type { 'TimeEntryCustomField' }
+
+ factory :boolean_time_entry_custom_field do
+ name { 'BooleanTimeEntryCustomField' }
+ field_format { 'bool' }
+ end
+
+ factory :integer_time_entry_custom_field do
+ name { 'IntegerTimeEntryCustomField' }
+ field_format { 'int' }
+ end
+
+ factory :text_time_entry_custom_field do
+ name { 'TextTimeEntryCustomField' }
+ field_format { 'text' }
+ end
+
+ factory :string_time_entry_custom_field do
+ name { 'StringTimeEntryCustomField' }
+ field_format { 'string' }
+ end
+
+ factory :float_time_entry_custom_field do
+ name { 'FloatTimeEntryCustomField' }
+ field_format { 'float' }
+ end
+
+ factory :list_time_entry_custom_field do
+ name { 'ListTimeEntryCustomField' }
+ field_format { 'list' }
+ possible_values { ['A', 'B'] }
+ end
+
+ factory :date_time_entry_custom_field do
+ name { 'DateTimeEntryCustomField' }
+ field_format { 'date' }
+ end
end
factory :version_custom_field, class: 'VersionCustomField' do
diff --git a/spec/factories/notification_setting_factory.rb b/spec/factories/notification_setting_factory.rb
index f94a0c237e..bbd022b49d 100644
--- a/spec/factories/notification_setting_factory.rb
+++ b/spec/factories/notification_setting_factory.rb
@@ -1,6 +1,7 @@
FactoryBot.define do
factory :notification_setting do
- involved { true }
+ assignee { true }
+ responsible { true }
mentioned { true }
watched { true }
work_package_commented { false }
diff --git a/spec/features/notifications/reminder_mail_spec.rb b/spec/features/notifications/reminder_mail_spec.rb
index cd1cd2dfec..b58757d0a8 100644
--- a/spec/features/notifications/reminder_mail_spec.rb
+++ b/spec/features/notifications/reminder_mail_spec.rb
@@ -36,7 +36,8 @@ describe "Reminder email sending", type: :feature, js: true do
},
notification_settings: [
build(:notification_setting,
- involved: true,
+ assignee: true,
+ responsible: true,
watched: true,
mentioned: true,
work_package_commented: true,
diff --git a/spec/features/projects/copy_spec.rb b/spec/features/projects/copy_spec.rb
index ec10e2e36b..51dadf85ae 100644
--- a/spec/features/projects/copy_spec.rb
+++ b/spec/features/projects/copy_spec.rb
@@ -105,7 +105,8 @@ describe 'Projects copy',
category:,
version:,
description: 'Some description',
- custom_field_values: { wp_custom_field.id => 'Some wp cf text' })
+ custom_field_values: { wp_custom_field.id => 'Some wp cf text' },
+ attachments: [build(:attachment, filename: 'work_package_attachment.pdf')])
end
let!(:wiki) { project.wiki }
@@ -113,7 +114,7 @@ describe 'Projects copy',
create :wiki_page_with_content,
title: 'Attached',
wiki:,
- attachments: [build(:attachment, container: nil, filename: 'attachment.pdf')]
+ attachments: [build(:attachment, container: nil, filename: 'wiki_page_attachment.pdf')]
end
let(:parent_field) { ::FormFields::SelectFormField.new :parent }
@@ -201,8 +202,8 @@ describe 'Projects copy',
expect(copied_project.wiki.pages.count).to eq(project.wiki.pages.count)
copied_page = copied_project.wiki.find_page 'Attached'
expect(copied_page).not_to be_nil
- expect(copied_page.attachments.count).to eq 1
- expect(copied_page.attachments.first.filename).to eq 'attachment.pdf'
+ expect(copied_page.attachments.map(&:filename))
+ .to eq ['wiki_page_attachment.pdf']
# Expect ProjectStores and their FileLinks were copied
expect(copied_project.projects_storages.count).to eq(project.projects_storages.count)
@@ -237,6 +238,8 @@ describe 'Projects copy',
.to eql copied_project.versions.find_by(name: version.name)
expect(copied_work_package.custom_value_attributes)
.to eql(wp_custom_field.id => 'Some wp cf text')
+ expect(copied_work_package.attachments.map(&:filename))
+ .to eq ['work_package_attachment.pdf']
expect(ActionMailer::Base.deliveries.count)
.to eql(1)
diff --git a/spec/features/projects/template_spec.rb b/spec/features/projects/template_spec.rb
index c63f18e5ef..f249dd0ab4 100644
--- a/spec/features/projects/template_spec.rb
+++ b/spec/features/projects/template_spec.rb
@@ -124,7 +124,7 @@ describe 'Project templates', type: :feature, js: true do
expect(page).to have_selector('[data-qa-field-name="sendNotifications"]')
# And allows to deselect copying the members.
- uncheck 'Members'
+ uncheck I18n.t(:'projects.copy.members')
page.find('button:not([disabled])', text: 'Save').click
diff --git a/spec/features/users/notifications/shared_examples.rb b/spec/features/users/notifications/shared_examples.rb
index 17ea5bde9d..7eeb576b23 100644
--- a/spec/features/users/notifications/shared_examples.rb
+++ b/spec/features/users/notifications/shared_examples.rb
@@ -15,7 +15,8 @@ shared_examples 'notification settings workflow' do
settings_page.add_project project_alt
# Set settings for project email
- settings_page.configure_global involved: true,
+ settings_page.configure_global assignee: true,
+ responsible: true,
work_package_commented: true,
work_package_created: true,
work_package_processed: true,
@@ -24,7 +25,8 @@ shared_examples 'notification settings workflow' do
# Set settings for project email
settings_page.configure_project project: project,
- involved: true,
+ assignee: true,
+ responsible: true,
work_package_commented: false,
work_package_created: false,
work_package_processed: false,
@@ -39,7 +41,8 @@ shared_examples 'notification settings workflow' do
expect(notification_settings.where(project:).count).to eq 1
project_settings = notification_settings.find_by(project:)
- expect(project_settings.involved).to be_truthy
+ expect(project_settings.assignee).to be_truthy
+ expect(project_settings.responsible).to be_truthy
expect(project_settings.mentioned).to be_truthy
expect(project_settings.watched).to be_truthy
expect(project_settings.work_package_commented).to be_falsey
diff --git a/spec/lib/api/v3/user_preferences/user_preference_representer_parsing_spec.rb b/spec/lib/api/v3/user_preferences/user_preference_representer_parsing_spec.rb
index 892a954781..d6745ee8f9 100644
--- a/spec/lib/api/v3/user_preferences/user_preference_representer_parsing_spec.rb
+++ b/spec/lib/api/v3/user_preferences/user_preference_representer_parsing_spec.rb
@@ -43,7 +43,8 @@ describe ::API::V3::UserPreferences::UserPreferenceRepresenter,
{
'notifications' => [
{
- 'involved' => true,
+ 'assignee' => true,
+ 'responsible' => true,
'_links' => {
'project' => {
'href' => '/api/v3/projects/1'
@@ -51,7 +52,8 @@ describe ::API::V3::UserPreferences::UserPreferenceRepresenter,
}
},
{
- 'involved' => false,
+ 'assignee' => false,
+ 'responsible' => false,
'mentioned' => true,
'_links' => {
'project' => {
@@ -69,11 +71,13 @@ describe ::API::V3::UserPreferences::UserPreferenceRepresenter,
in_project, global = subject.notification_settings
expect(in_project[:project_id]).to eq "1"
- expect(in_project[:involved]).to be_truthy
+ expect(in_project[:assignee]).to be_truthy
+ expect(in_project[:responsible]).to be_truthy
expect(in_project[:mentioned]).to be_nil
expect(global[:project_id]).to be_nil
- expect(global[:involved]).to be false
+ expect(global[:assignee]).to be_falsey
+ expect(global[:responsible]).to be_falsey
expect(global[:mentioned]).to be true
end
end
diff --git a/spec/lib/redmine/menu_manager/menu_item_spec.rb b/spec/lib/redmine/menu_manager/menu_item_spec.rb
new file mode 100644
index 0000000000..f4ee3331b4
--- /dev/null
+++ b/spec/lib/redmine/menu_manager/menu_item_spec.rb
@@ -0,0 +1,86 @@
+# OpenProject is an open source project management software.
+# Copyright (C) 2010-2022 the OpenProject GmbH
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License version 3.
+#
+# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
+# Copyright (C) 2006-2013 Jean-Philippe Lang
+# Copyright (C) 2010-2013 the ChiliProject Team
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# See COPYRIGHT and LICENSE files for more details.
+
+require 'spec_helper'
+
+describe Redmine::MenuManager::MenuItem do
+ describe '.new' do
+ it 'creates an item with all required parameters' do
+ expect(described_class.new(:test_good_menu, '/test', {}))
+ .to be_a described_class
+ end
+
+ it 'creates an item with an if condition' do
+ expect(described_class.new(:test_good_menu, '/test', if: ->(*) {}))
+ .to be_a described_class
+ end
+
+ it 'creates an item with extra html options' do
+ expect(described_class.new(:test_good_menu, '/test', html: { data: 'foo' }))
+ .to be_a described_class
+ end
+
+ it 'creates an item with a children proc' do
+ expect(described_class.new(:test_good_menu, '/test', children: ->(*) {}))
+ .to be_a described_class
+ end
+
+ it 'fails without a name' do
+ expect { described_class.new }
+ .to raise_error ArgumentError
+ end
+
+ it 'fails without a url' do
+ expect { described_class.new(:missing_url) }
+ .to raise_error ArgumentError
+ end
+
+ it 'fails without an options' do
+ expect { described_class.new(:missing_url, '/test') }
+ .to raise_error ArgumentError
+ end
+
+ it 'fails when setting the parent item to the current item' do
+ expect { described_class.new(:test_error, '/test', parent: :test_error) }
+ .to raise_error ArgumentError
+ end
+
+ it 'fails for an if condition without a proc' do
+ expect { described_class.new(:test_error, '/test', if: ['not_a_proc']) }
+ .to raise_error ArgumentError
+ end
+
+ it 'fails for an html condition without a hash' do
+ expect { described_class.new(:test_error, '/test', html: ['not_a_hash']) }
+ .to raise_error ArgumentError
+ end
+
+ it 'fails for an children optiono without a proc' do
+ expect { described_class.new(:test_error, '/test', children: ['not_a_proc']) }
+ .to raise_error ArgumentError
+ end
+ end
+end
diff --git a/spec/lib/redmine/menu_manager_spec.rb b/spec/lib/redmine/menu_manager_spec.rb
index cca9558127..b57017ab5d 100644
--- a/spec/lib/redmine/menu_manager_spec.rb
+++ b/spec/lib/redmine/menu_manager_spec.rb
@@ -81,6 +81,13 @@ describe Redmine::MenuManager do
:authentication,
:announcements)
end
+
+ it 'has children defined for the authentication item' do
+ expect(described_class.items(:admin_menu).find { |item| item.name == :authentication }.map(&:name))
+ .to include(:authentication_settings,
+ :ldap_authentication,
+ :oauth_applications)
+ end
end
end
end
diff --git a/spec/models/issue_priority_spec.rb b/spec/models/issue_priority_spec.rb
index 1f69bacaf7..fd3326d2dc 100644
--- a/spec/models/issue_priority_spec.rb
+++ b/spec/models/issue_priority_spec.rb
@@ -28,8 +28,10 @@
require 'spec_helper'
describe IssuePriority, type: :model do
+ shared_let(:priority) { create(:priority) }
+ shared_let(:default_priority) { create(:default_priority) }
+
let(:stubbed_priority) { build_stubbed(:priority) }
- let(:priority) { create(:priority) }
describe '.ancestors' do
it 'is an enumeration' do
@@ -90,4 +92,97 @@ describe IssuePriority, type: :model do
.to match_array [work_package3, work_package1]
end
end
+
+ describe '#in_use?' do
+ context 'with a work package that uses the priority' do
+ let!(:work_package) { create(:work_package, priority:) }
+
+ it 'is true' do
+ expect(priority)
+ .to be_in_use
+ end
+ end
+
+ context 'without a work package that uses the priority' do
+ it 'is false' do
+ expect(priority)
+ .not_to be_in_use
+ end
+ end
+ end
+
+ describe '.default' do
+ it 'returns the default priority' do
+ expect(described_class.default)
+ .to eq default_priority
+ end
+
+ it 'changes if a new default priority is created' do
+ new_default = described_class.create(name: 'New default', is_default: true)
+
+ expect(described_class.default)
+ .to eq new_default
+ end
+
+ it 'does not change if a new non default priority is created' do
+ described_class.create(name: 'New default', is_default: false)
+
+ expect(described_class.default)
+ .to eq default_priority
+ end
+
+ it 'is nil if the default priority looses the default flag' do
+ default_priority.update(is_default: false)
+
+ expect(described_class.default)
+ .to be_nil
+ end
+ end
+
+ describe '#default?' do
+ it 'is true for a default priority' do
+ expect(default_priority)
+ .to be_is_default
+ end
+
+ it 'is false for a non default priority' do
+ expect(priority)
+ .not_to be_is_default
+ end
+
+ it 'changes if a new default priority is created' do
+ described_class.create(name: 'New default', is_default: true)
+
+ expect(default_priority.reload)
+ .not_to be_is_default
+ end
+
+ it 'changes if an existing priority is assigned default' do
+ new_default_priority = create(:priority)
+ new_default_priority.update(is_default: true)
+
+ expect(default_priority.reload)
+ .not_to be_is_default
+ end
+ end
+
+ describe '.destroy' do
+ let!(:work_package) { create(:work_package, priority:) }
+
+ context 'with reassign' do
+ it 'reassigns the work packages' do
+ priority.destroy(default_priority)
+
+ expect(WorkPackage.where(priority: default_priority))
+ .to eq [work_package]
+ end
+ end
+
+ context 'without reassign' do
+ it 'raises an error as it is in use' do
+ expect { priority.destroy }
+ .to raise_error RuntimeError
+ end
+ end
+ end
end
diff --git a/spec/models/mail_handler_spec.rb b/spec/models/mail_handler_spec.rb
index 188bb281df..8d21a60584 100644
--- a/spec/models/mail_handler_spec.rb
+++ b/spec/models/mail_handler_spec.rb
@@ -1233,7 +1233,7 @@ describe MailHandler, type: :model do
assignee = create(:user,
member_in_project: project,
member_with_permissions: %i(view_work_packages),
- notification_settings: [build(:notification_setting, involved: true)])
+ notification_settings: [build(:notification_setting, assignee: true, responsible: true)])
work_package.update_column(:assigned_to_id, assignee.id)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index ff8843b643..895418d77d 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -55,13 +55,13 @@ describe Project, type: :model do
end
describe '#archived?' do
- context 'if active' do
+ context 'if archived' do
it 'is true' do
expect(project).not_to be_archived
end
end
- context 'if not active' do
+ context 'if not archived' do
let(:active) { false }
it 'is false' do
@@ -192,7 +192,184 @@ describe Project, type: :model do
end
end
+ describe '#members' do
+ let(:role) { create(:role) }
+ let(:active_user) { create(:user) }
+ let!(:active_member) { create(:member, project:, user: active_user, roles: [role]) }
+
+ let(:inactive_user) { create(:user, status: Principal.statuses[:locked]) }
+ let!(:inactive_member) { create(:member, project:, user: inactive_user, roles: [role]) }
+
+ it 'only includes active members' do
+ expect(project.members)
+ .to eq [active_member]
+ end
+ end
+
include_examples 'creates an audit trail on destroy' do
subject { create(:attachment) }
end
+
+ describe '#users' do
+ let(:role) { create(:role) }
+ let(:active_user) { create(:user) }
+ let!(:active_member) { create(:member, project:, user: active_user, roles: [role]) }
+
+ let(:inactive_user) { create(:user, status: Principal.statuses[:locked]) }
+ let!(:inactive_member) { create(:member, project:, user: inactive_user, roles: [role]) }
+
+ it 'only includes active users' do
+ expect(project.users)
+ .to eq [active_user]
+ end
+ end
+
+ include_examples 'creates an audit trail on destroy' do
+ subject { create(:attachment) }
+ end
+
+ describe '#close_completed_versions' do
+ let!(:completed_version) do
+ create(:version, project:, effective_date: Date.parse('2000-01-01')).tap do |v|
+ create(:work_package, version: v, status: create(:closed_status))
+ end
+ end
+ let!(:ineffective_version) do
+ create(:version, project:, effective_date: Date.current + 1.day).tap do |v|
+ create(:work_package, version: v, status: create(:closed_status))
+ end
+ end
+ let!(:version_with_open_wps) do
+ create(:version, project:, effective_date: Date.parse('2000-01-01')).tap do |v|
+ create(:work_package, version: v)
+ end
+ end
+
+ before do
+ project.close_completed_versions
+ end
+
+ it 'closes the completed version' do
+ expect(completed_version.reload.status)
+ .to eq 'closed'
+ end
+
+ it 'keeps the version with the not yet reached date open' do
+ expect(ineffective_version.reload.status)
+ .to eq 'open'
+ end
+
+ it 'keeps the version with open work packages open' do
+ expect(version_with_open_wps.reload.status)
+ .to eq 'open'
+ end
+ end
+
+ describe 'hierarchy methods' do
+ shared_let(:root_project) { create(:project) }
+ shared_let(:parent_project) { create(:project, parent: root_project) }
+ shared_let(:child_project1) { create(:project, parent: parent_project) }
+ shared_let(:child_project2) { create(:project, parent: parent_project) }
+
+ describe '#parent' do
+ it 'returns the parent' do
+ expect(parent_project.parent)
+ .to eq root_project
+ end
+ end
+
+ describe '#root' do
+ it 'returns the root of the hierarchy' do
+ expect(child_project1.root)
+ .to eq root_project
+ end
+ end
+
+ describe '#ancestors' do
+ it 'returns the ancestors of the work package' do
+ expect(child_project1.ancestors)
+ .to eq [root_project, parent_project]
+ end
+
+ it 'returns empty array if there are no ancestors' do
+ expect(root_project.ancestors)
+ .to be_empty
+ end
+ end
+
+ describe '#desendants' do
+ it 'returns the descendants of the work package' do
+ expect(root_project.descendants)
+ .to eq [parent_project, child_project1, child_project2]
+ end
+
+ it 'returns empty array if there are no descendants' do
+ expect(child_project2.descendants)
+ .to be_empty
+ end
+ end
+
+ describe '#children' do
+ it 'returns the children of the work package' do
+ expect(parent_project.children)
+ .to eq [child_project1, child_project2]
+ end
+
+ it 'returns empty array if there are no descendants' do
+ expect(child_project2.children)
+ .to be_empty
+ end
+ end
+ end
+
+ describe '#rolled_up_types' do
+ let!(:parent) do
+ create(:project, types: [parent_type]).tap do |p|
+ project.update_attribute(:parent, p)
+ end
+ end
+ let!(:child1) { create(:project, parent: project, types: [child1_type, shared_type]) }
+ let!(:child2) { create(:project, parent: project, types: [child2_type], active: false) }
+
+ let!(:unused_type) { create(:type) }
+ let!(:parent_type) { create(:type) }
+ let!(:child1_type) { create(:type) }
+ let!(:child2_type) { create(:type) }
+ let!(:shared_type) { create(:type) }
+
+ let!(:project_type) do
+ create(:type).tap do |t|
+ project.types = [t, shared_type]
+ end
+ end
+
+ it 'includes all types of active projects starting from receiver down to the leaves' do
+ project.reload
+
+ expect(project.rolled_up_types)
+ .to eq [child1_type, project_type, shared_type].sort_by(&:position)
+ end
+ end
+
+ describe '#enabled_module_names=', with_settings: { default_projects_modules: %w(work_package_tracking repository) } do
+ context 'when assigning a new value' do
+ let(:new_value) { %w(work_package_tracking news) }
+
+ subject do
+ project.enabled_module_names = new_value
+ end
+
+ it 'sets the value' do
+ subject
+
+ expect(project.reload.enabled_module_names.sort)
+ .to eql new_value.sort
+ end
+
+ it 'keeps already assigned modules intact (same id)' do
+ expect { subject }
+ .not_to change { project.reload.enabled_modules.find { |em| em.name == 'work_package_tracking' }.id }
+ end
+ end
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index eeffb45d6a..86c437b817 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -45,44 +45,6 @@ describe User, type: :model do
status:)
end
- describe 'a user with a long login (<= 256 chars)' do
- let(:login) { 'a' * 256 }
-
- it 'is valid' do
- user.login = login
- expect(user).to be_valid
- end
-
- it 'may be loaded from the database' do
- user.login = login
- expect(user.save).to be_truthy
-
- expect(User.find_by_login(login)).to eq(user)
- expect(User.find_by_unique(login)).to eq(user)
- end
- end
-
- describe 'a user with an invalid login' do
- let(:login) { 'me' }
-
- it 'is invalid' do
- user.login = login
- expect(user).not_to be_valid
- end
- end
-
- describe 'a user with and overly long login (> 256 chars)' do
- it 'is invalid' do
- user.login = 'a' * 257
- expect(user).not_to be_valid
- end
-
- it 'may not be stored in the database' do
- user.login = 'a' * 257
- expect(user.save).to be_falsey
- end
- end
-
describe 'with long but allowed attributes' do
it 'is valid' do
user.firstname = 'a' * 256
@@ -110,31 +72,52 @@ describe User, type: :model do
end
describe '#mail' do
- it 'is stripped' do
- user.mail = ' foo@bar.com '
- expect(user.mail)
- .to eql 'foo@bar.com'
+ before do
+ user.mail = mail
end
- it 'validates for local mails' do
- user.mail = 'foobar@abc.def.some-internet'
- expect(user).to be_valid
+ context 'with whitespaces' do
+ let(:mail) { ' foo@bar.com ' }
+
+ it 'is stripped' do
+ expect(user.mail)
+ .to eql 'foo@bar.com'
+ end
end
- it 'invalidates wrong mails' do
- user.mail = 'foobar+abc.def.some-internet'
- expect(user).not_to be_valid
- expect(user.errors[:mail]).to include 'is not a valid email address.'
+ context 'for local mail addresses' do
+ let(:mail) { 'foobar@abc.def.some-internet' }
+
+ it 'is valid' do
+ expect(user).to be_valid
+ end
+ end
+
+ context 'for wrong mail addresses' do
+ let(:mail) { 'foobar+abc.def.some-internet' }
+
+ it 'is invalid' do
+ expect(user).to be_invalid
+ end
+ end
+
+ context 'for an already taken mail addresses (different take)' do
+ let(:mail) { 'foo@bar.com' }
+ let!(:other_user) { create(:user, mail: 'Foo@Bar.com') }
+
+ it 'is invalid' do
+ expect(user).to be_invalid
+ end
end
end
describe '#login' do
- context 'with whitespace' do
- before do
- user.login = login
- end
+ before do
+ user.login = login
+ end
- context 'simple spaces' do
+ context 'with whitespace' do
+ context 'with simple spaces' do
let(:login) { 'a b c' }
it 'is valid' do
@@ -146,7 +129,7 @@ describe User, type: :model do
end
end
- context 'line breaks' do
+ context 'with line breaks' do
let(:login) { 'ab\nc' }
it 'is invalid' do
@@ -158,7 +141,7 @@ describe User, type: :model do
end
end
- context 'tabs' do
+ context 'with tabs' do
let(:login) { 'ab\tc' }
it 'is invalid' do
@@ -172,10 +155,6 @@ describe User, type: :model do
end
context 'with symbols' do
- before do
- user.login = login
- end
-
%w[+ _ . - @].each do |symbol|
context symbol do
let(:login) { "foo#{symbol}bar" }
@@ -190,7 +169,7 @@ describe User, type: :model do
end
end
- context 'combination thereof' do
+ context 'with combination thereof' do
let(:login) { 'the+boss-is@the_house.' }
it 'is valid' do
@@ -214,6 +193,95 @@ describe User, type: :model do
end
end
end
+
+ context 'with more that 255 chars' do
+ let(:login) { 'a' * 256 }
+
+ it 'is valid' do
+ user.login = login
+ expect(user).to be_valid
+ end
+
+ it 'may be loaded from the database' do
+ user.login = login
+ expect(user.save).to be_truthy
+
+ expect(described_class.find_by_login(login)).to eq(user)
+ expect(described_class.find_by_unique(login)).to eq(user)
+ end
+ end
+
+ context 'with an invalid login' do
+ let(:login) { 'me' }
+
+ it 'is invalid' do
+ user.login = login
+ expect(user).not_to be_valid
+ end
+ end
+
+ context 'with an overly long login (> 256 chars)' do
+ let(:login) { 'a' * 257 }
+
+ it 'is invalid' do
+ expect(user).not_to be_valid
+ end
+
+ it 'may not be stored in the database' do
+ expect(user.save).to be_falsey
+ end
+ end
+
+ context 'with another user having the login in a different case' do
+ let!(:other_user) { create(:user, login: 'NewUser') }
+ let(:login) { 'newuser' }
+
+ it 'is invalid' do
+ expect(user).not_to be_valid
+ end
+ end
+
+ context 'when empty' do
+ let(:login) { '' }
+
+ it 'is invalid' do
+ expect(user).not_to be_valid
+ end
+ end
+ end
+
+ describe '#name' do
+ let(:user) do
+ create(:user,
+ firstname: 'John',
+ lastname: 'Smith',
+ login: 'username',
+ mail: 'user@name.org')
+ end
+
+ context 'for firstname_lastname', with_settings: { user_format: :firstname_lastname } do
+ it { expect(user.name).to eq "#{user.firstname} #{user.lastname}" }
+ end
+
+ context 'for firstname', with_settings: { user_format: :firstname } do
+ it { expect(user.name).to eq user.firstname }
+ end
+
+ context 'for lastname_firstname', with_settings: { user_format: :lastname_firstname } do
+ it { expect(user.name).to eq "#{user.lastname} #{user.firstname}" }
+ end
+
+ context 'for lastname_n_firstname', with_settings: { user_format: :lastname_n_firstname } do
+ it { expect(user.name).to eq "#{user.lastname}#{user.firstname}" }
+ end
+
+ context 'for lastname_coma_firstname', with_settings: { user_format: :lastname_coma_firstname } do
+ it { expect(user.name).to eq "#{user.lastname}, #{user.firstname}" }
+ end
+
+ context 'for username', with_settings: { user_format: :username } do
+ it { expect(user.name).to eq user.login }
+ end
end
describe '#authentication_provider' do
@@ -439,6 +507,55 @@ describe User, type: :model do
end
end
+ describe '#wants_comments_in_reverse_order?' do
+ let(:user) { create(:user) }
+
+ it 'is false by default' do
+ expect(user)
+ .not_to be_wants_comments_in_reverse_order
+ end
+
+ it 'is false if set to asc' do
+ user.pref.comments_sorting = 'asc'
+
+ expect(user)
+ .not_to be_wants_comments_in_reverse_order
+ end
+
+ it 'is true if set to asc' do
+ user.pref.comments_sorting = 'desc'
+
+ expect(user)
+ .to be_wants_comments_in_reverse_order
+ end
+ end
+
+ describe '#roles_for_project' do
+ let(:project) { create(:project) }
+ let!(:user) do
+ create(:user,
+ member_in_project: project,
+ member_through_role: roles)
+ end
+ let(:roles) { [create(:role), create(:role)] }
+
+ context 'for a project the user has roles in' do
+ it 'returns the roles' do
+ expect(user.roles_for_project(project))
+ .to match_array roles
+ end
+ end
+
+ context 'for a project the user does not have roles in' do
+ let(:other_project) { create(:project) }
+
+ it 'returns an empty set' do
+ expect(user.roles_for_project(other_project))
+ .to be_empty
+ end
+ end
+ end
+
describe '.system' do
context 'no SystemUser exists' do
before do
@@ -516,16 +633,14 @@ describe User, type: :model do
end
describe '.find_by_rss_key' do
- before do
- @rss_key = user.rss_key
- end
+ let(:rss_key) { user.rss_key }
context 'feeds enabled' do
before do
allow(Setting).to receive(:feeds_enabled?).and_return(true)
end
- it { expect(User.find_by_rss_key(@rss_key)).to eq(user) }
+ it { expect(described_class.find_by_rss_key(rss_key)).to eq(user) }
end
context 'feeds disabled' do
@@ -533,11 +648,34 @@ describe User, type: :model do
allow(Setting).to receive(:feeds_enabled?).and_return(false)
end
- it { expect(User.find_by_rss_key(@rss_key)).to be_nil }
+ it { expect(described_class.find_by_rss_key(rss_key)).to be_nil }
end
end
- describe 'scope.newest' do
+ describe '#rss_key' do
+ let(:user) { create(:user) }
+
+ it 'is created on the fly' do
+ expect { user.rss_key }
+ .to change { user.reload.rss_token.nil? }
+ .from(true)
+ .to(false)
+ end
+
+ it 'is persisted' do
+ key = user.rss_key
+
+ expect(user.reload.rss_key)
+ .to eq key
+ end
+
+ it 'has a length of 64' do
+ expect(user.rss_key.length)
+ .to eq 64
+ end
+ end
+
+ describe '.newest' do
let!(:anonymous) { User.anonymous }
let!(:user1) { create(:user) }
let!(:user2) { create(:user) }
@@ -568,7 +706,7 @@ describe User, type: :model do
expect(Setting.mail_suffix_separators).to eq '+'
# Can match either of the first two
- match2 = User.find_by_mail('foo@example.org')
+ match2 = described_class.find_by_mail('foo@example.org')
expect([user1.id, user2.id]).to include(match2.id)
matches = User.where_mail_with_suffix('foo@example.org')
@@ -583,11 +721,11 @@ describe User, type: :model do
it 'finds users matching the suffix' do
expect(Setting.mail_suffix_separators).to eq '+-'
- match1 = User.find_by_mail('foo-bar@example.org')
+ match1 = described_class.find_by_mail('foo-bar@example.org')
expect(match1).to eq(user3)
# Can match either of the three
- match2 = User.find_by_mail('foo@example.org')
+ match2 = described_class.find_by_mail('foo@example.org')
expect([user1.id, user2.id, user3.id]).to include(match2.id)
matches = User.where_mail_with_suffix('foo@example.org')
@@ -596,6 +734,153 @@ describe User, type: :model do
end
end
+ describe '.try_to_login' do
+ let(:password) { 'pwd123Password!' }
+ let(:login) { 'the_login' }
+ let(:status) { described_class.statuses[:active] }
+
+ let!(:user) do
+ create(:user,
+ password:,
+ password_confirmation: password,
+ login:,
+ status:)
+ end
+
+ context 'with good credentials' do
+ it 'returns the user' do
+ expect(described_class.try_to_login(login, password))
+ .to eq user
+ end
+ end
+
+ context 'with wrong password' do
+ it 'returns the user' do
+ expect(described_class.try_to_login(login, "#{password}!"))
+ .to be_nil
+ end
+ end
+
+ context 'with wrong case in login' do
+ it 'returns the user' do
+ expect(described_class.try_to_login('The_login', password))
+ .to eq user
+ end
+ end
+
+ context 'with wrong characters in login' do
+ it 'returns nil' do
+ expect(described_class.try_to_login(login[0..-2], password))
+ .to be_nil
+ end
+ end
+
+ context 'with the user being locked' do
+ let(:status) { described_class.statuses[:locked] }
+
+ it 'returns nil' do
+ expect(described_class.try_to_login(login, "#{password}!"))
+ .to be_nil
+ end
+ end
+
+ context 'with the user\'s password being changed' do
+ let(:new_password) { 'newPWD12%abc' }
+
+ before do
+ user.password = new_password
+ user.save!
+ end
+
+ it 'returns the user' do
+ expect(described_class.try_to_login(login, new_password))
+ .to eq user
+ end
+ end
+ end
+
+ describe '.find_by_api_key' do
+ let(:status) { described_class.statuses[:active] }
+
+ let!(:user) do
+ create(:user,
+ status:)
+ end
+ let!(:token) do
+ create(:api_token, user:)
+ end
+
+ context 'if the right token is used' do
+ it 'returns the user' do
+ expect(described_class.find_by_api_key(token.plain_value))
+ .to eq user
+ end
+ end
+
+ context 'if it isn\'t the right user' do
+ it 'returns nil' do
+ expect(described_class.find_by_api_key("#{token.value}abc"))
+ .to be_nil
+ end
+ end
+
+ context 'if the right token is used but the user is locked' do
+ let(:status) { described_class.statuses[:locked] }
+
+ it 'returns nil' do
+ expect(described_class.find_by_api_key(token.plain_value))
+ .to be_nil
+ end
+ end
+ end
+
+ describe '.find_by_mail' do
+ let(:mail) { 'the@mail.org' }
+ let!(:user) { create :user, mail: }
+
+ context 'with the exact mail' do
+ it 'finds the user' do
+ expect(described_class.find_by_mail(mail))
+ .to eq user
+ end
+ end
+
+ context 'with the mail address in uppercase' do
+ it 'finds the user' do
+ expect(described_class.find_by_mail(mail.upcase))
+ .to eq user
+ end
+ end
+
+ context 'with a different mail address' do
+ it 'is nil' do
+ expect(described_class.find_by_mail(mail[1..-2]))
+ .to be_nil
+ end
+ end
+
+ context 'with a mail suffix in the address' do
+ let(:mail) { 'the+other@mail.org' }
+
+ it 'finds the user' do
+ expect(described_class.find_by_mail('the@mail.org'))
+ .to eq user
+ end
+ end
+ end
+
+ describe '.anonymous' do
+ it 'creates an anonymous user on the fly' do
+ expect(described_class.anonymous)
+ .to be_a(AnonymousUser)
+ end
+
+ it 'creates a persisted record' do
+ expect(described_class.anonymous)
+ .to be_persisted
+ end
+ end
+
include_examples 'creates an audit trail on destroy' do
subject { create(:attachment) }
end
diff --git a/spec/models/version_spec.rb b/spec/models/version_spec.rb
index da9b3f6aae..12a6be0e3a 100644
--- a/spec/models/version_spec.rb
+++ b/spec/models/version_spec.rb
@@ -371,4 +371,134 @@ describe Version, type: :model do
end
end
end
+
+ describe '#completed_percent and #closed_percent' do
+ create_shared_association_defaults_for_work_package_factory
+
+ let(:project) { create(:project) }
+ let(:version) { create(:version, project:) }
+ let(:closed_status) { create(:status, is_closed: true) }
+
+ context 'without a work package' do
+ it 'is 0 for completed_percent' do
+ expect(version.completed_percent)
+ .to eq 0
+ end
+
+ it 'is 0 for closed_percent' do
+ expect(version.closed_percent)
+ .to eq 0
+ end
+ end
+
+ context 'with assigned work packages that are not begun' do
+ before do
+ create(:work_package, version:)
+ create(:work_package, version:, done_ratio: 0)
+ end
+
+ it 'is 0 for completed_percent' do
+ expect(version.completed_percent)
+ .to eq 0
+ end
+
+ it 'is 0 for closed_percent' do
+ expect(version.closed_percent)
+ .to eq 0
+ end
+ end
+
+ context 'with assigned work packages that are closed' do
+ before do
+ create(:work_package, status: closed_status, version:)
+ create(:work_package, status: closed_status, version:, done_ratio: 20)
+ create(:work_package, status: closed_status, version:, done_ratio: 70, estimated_hours: 25)
+ create(:work_package, status: closed_status, version:, estimated_hours: 15)
+ end
+
+ it 'is 100 for completed_percent' do
+ expect(version.completed_percent)
+ .to eq 100
+ end
+
+ it 'is 100 for closed_percent' do
+ expect(version.closed_percent)
+ .to eq 100
+ end
+ end
+
+ context 'with assigned work packages that have only done ratio' do
+ before do
+ create(:work_package, version:)
+ create(:work_package, version:, done_ratio: 20)
+ create(:work_package, version:, done_ratio: 70)
+ end
+
+ it 'considers the done ratio of open work packages' do
+ expect(version.completed_percent)
+ .to eq (0.0 + 20.0 + 70.0) / 3
+ end
+
+ it 'is 0 for closed_percent' do
+ expect(version.closed_percent)
+ .to eq 0
+ end
+ end
+
+ context 'with assigned work packages that have only done ratio with one being closed' do
+ before do
+ create(:work_package, version:)
+ create(:work_package, version:, done_ratio: 20)
+ create(:work_package, status: closed_status, version:)
+ end
+
+ it 'considers the done ratio of open work packages' do
+ expect(version.completed_percent)
+ .to eq (0.0 + 20.0 + 100.0) / 3
+ end
+
+ it 'is 33 for closed_percent' do
+ expect(version.closed_percent)
+ .to eq 100.0 / 3
+ end
+ end
+
+ context 'with assigned work packages that have weighted done ratio' do
+ before do
+ create(:work_package, version:, estimated_hours: 10)
+ create(:work_package, version:, done_ratio: 30, estimated_hours: 20)
+ create(:work_package, version:, done_ratio: 10, estimated_hours: 40)
+ create(:work_package, status: closed_status, version:, estimated_hours: 25)
+ end
+
+ it 'considers the weighted done ratio of open work packages' do
+ expect(version.completed_percent)
+ .to eq ((10.0 * 0) + (20.0 * 0.3) + (40 * 0.1) + (25.0 * 1)) / 95.0 * 100
+ end
+
+ it 'is considers the weighted closed_percent' do
+ expect(version.closed_percent)
+ .to eq 25.0 / 95.0 * 100
+ end
+ end
+
+ context 'with assigned work packages that have partly weighted done ratio' do
+ before do
+ create(:work_package, version:, done_ratio: 20)
+ create(:work_package, version:, done_ratio: 30, estimated_hours: 10)
+ create(:work_package, version:, done_ratio: 10, estimated_hours: 40)
+ create(:work_package, status: closed_status, version:)
+ end
+
+ it 'considers the weighted done ratio of open work packages and uses default weighting if unset' do
+ expect(version.completed_percent)
+ .to eq ((25.0 * 0.2) + (25.0 * 1) + (10.0 * 0.3) + (40.0 * 0.1)) / 100.0 * 100
+ end
+
+ it 'is considers the weighted closed_percent using average for the estimated hours' do
+ expect(version.closed_percent)
+ .to eq 25.0 / 100.0 * 100
+ end
+ end
+ end
end
diff --git a/spec/models/work_packages/search_spec.rb b/spec/models/work_packages/search_spec.rb
new file mode 100644
index 0000000000..791a7dd2bd
--- /dev/null
+++ b/spec/models/work_packages/search_spec.rb
@@ -0,0 +1,77 @@
+# --copyright
+# OpenProject is an open source project management software.
+# Copyright (C) 2010-2022 the OpenProject GmbH
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License version 3.
+#
+# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
+# Copyright (C) 2006-2013 Jean-Philippe Lang
+# Copyright (C) 2010-2013 the ChiliProject Team
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# See COPYRIGHT and LICENSE files for more details.
+# ++
+
+require 'spec_helper'
+
+describe WorkPackage, 'search', type: :model do
+ shared_let(:description_searchword) { "descKeyword" }
+ shared_let(:project) { create(:project) }
+ shared_let(:work_package) do
+ create(:work_package, project:, description: "The description with the #{description_searchword}.")
+ end
+
+ let(:permissions) { [:view_work_packages] }
+ let(:searchword) { 'keyword' }
+
+ current_user { create(:user, member_in_project: project, member_with_permissions: permissions) }
+
+ subject { described_class.search("%#{searchword}%").first }
+
+ context 'with the keyword being in the description' do
+ let(:searchword) { description_searchword }
+
+ it 'finds the work package' do
+ expect(subject)
+ .to eq [work_package]
+ end
+
+ context 'when lacking the permissions to see the work package' do
+ let(:permissions) { [] }
+
+ it 'does not find the work package' do
+ expect(subject)
+ .to be_empty
+ end
+ end
+ end
+
+ context 'with multiple hits in journals', with_settings: { journal_aggregation_time_minutes: 0 } do
+ before do
+ # Adding two journals with the keyword in it
+ work_package.journals.first.update_column(:notes, "A note with the #{searchword} in it.")
+
+ work_package.journal_notes = "The #{searchword} is in here"
+ work_package.save
+ end
+
+ it 'finds the work package' do
+ expect(subject)
+ .to eq [work_package]
+ end
+ end
+end
diff --git a/spec/models/workflow_spec.rb b/spec/models/workflow_spec.rb
index 04795c2024..565eb87910 100644
--- a/spec/models/workflow_spec.rb
+++ b/spec/models/workflow_spec.rb
@@ -29,69 +29,121 @@
require 'spec_helper'
describe Workflow, type: :model do
- let(:status_0) { create(:status) }
- let(:status_1) { create(:status) }
- let(:role) { create(:role) }
- let(:type) { create(:type) }
-
- describe '#self.copy' do
- let(:role_target) { create(:role) }
- let(:type_target) { create(:type) }
+ describe '.copy' do
+ shared_let(:status0) { create(:status) }
+ shared_let(:status1) { create(:status) }
+ shared_let(:role) { create(:role) }
+ shared_let(:type) { create(:type) }
+ shared_let(:role_target) { create(:role) }
+ shared_let(:type_target) { create(:type) }
+ shared_let(:role_target2) { create(:role) }
+ shared_let(:type_target2) { create(:type) }
shared_examples_for 'copied workflow' do
- before { Workflow.copy(type, role, type_target, role_target) }
-
- subject { Workflow.order(Arel.sql('id DESC')).first }
+ let(:expected_type) { type_target }
+ let(:expected_role) { role_target }
it { expect(subject.old_status).to eq(workflow_src.old_status) }
it { expect(subject.new_status).to eq(workflow_src.new_status) }
- it { expect(subject.type_id).to eq(type_target.id) }
+ it { expect(subject.type).to eq(expected_type) }
- it { expect(subject.role).to eq(role_target) }
+ it { expect(subject.role).to eq(expected_role) }
it { expect(subject.author).to eq(workflow_src.author) }
it { expect(subject.assignee).to eq(workflow_src.assignee) }
end
- describe 'workflow w/o author or assignee' do
+ context 'for a workflow w/o author or assignee' do
let!(:workflow_src) do
create(:workflow,
- old_status: status_0,
- new_status: status_1,
+ old_status: status0,
+ new_status: status1,
type_id: type.id,
role:)
end
- it_behaves_like 'copied workflow'
+ before { described_class.copy(type, role, type_target, role_target) }
+
+ it_behaves_like 'copied workflow' do
+ subject { described_class.order(Arel.sql('id DESC')).first }
+ end
end
- describe 'workflow with author' do
+ context 'for a workflow with author' do
let!(:workflow_src) do
create(:workflow,
- old_status: status_0,
- new_status: status_1,
+ old_status: status0,
+ new_status: status1,
type_id: type.id,
role:,
author: true)
end
- it_behaves_like 'copied workflow'
+ before { described_class.copy(type, role, type_target, role_target) }
+
+ it_behaves_like 'copied workflow' do
+ subject { described_class.order(Arel.sql('id DESC')).first }
+ end
end
- describe 'workflow with assignee' do
+ context 'for a workflow with assignee' do
let!(:workflow_src) do
create(:workflow,
- old_status: status_0,
- new_status: status_1,
+ old_status: status0,
+ new_status: status1,
type_id: type.id,
role:,
assignee: true)
end
- it_behaves_like 'copied workflow'
+ before { described_class.copy(type, role, type_target, role_target) }
+
+ it_behaves_like 'copied workflow' do
+ subject { described_class.order(Arel.sql('id DESC')).first }
+ end
+ end
+
+ context 'when copying to multiple types and roles' do
+ let!(:workflow_src) do
+ create(:workflow,
+ old_status: status0,
+ new_status: status1,
+ type_id: type.id,
+ role:)
+ end
+
+ before { described_class.copy(type, role, [type_target, type_target2], [role_target, role_target2]) }
+
+ it_behaves_like 'copied workflow' do
+ subject { described_class.order(Arel.sql('type_id DESC, role_id DESC')).first }
+
+ let(:expected_role) { role_target2 }
+ let(:expected_type) { type_target2 }
+ end
+
+ it_behaves_like 'copied workflow' do
+ subject { described_class.order(Arel.sql('type_id DESC, role_id DESC')).second }
+
+ let(:expected_role) { role_target }
+ let(:expected_type) { type_target2 }
+ end
+
+ it_behaves_like 'copied workflow' do
+ subject { described_class.order(Arel.sql('type_id DESC, role_id DESC')).third }
+
+ let(:expected_role) { role_target2 }
+ let(:expected_type) { type_target }
+ end
+
+ it_behaves_like 'copied workflow' do
+ subject { described_class.order(Arel.sql('type_id DESC, role_id DESC')).fourth }
+
+ let(:expected_role) { role_target }
+ let(:expected_type) { type_target }
+ end
end
end
end
diff --git a/spec/requests/api/v3/custom_options/custom_options_resource_spec.rb b/spec/requests/api/v3/custom_options/custom_options_resource_spec.rb
index 84fb8ba18b..501a8e50f5 100644
--- a/spec/requests/api/v3/custom_options/custom_options_resource_spec.rb
+++ b/spec/requests/api/v3/custom_options/custom_options_resource_spec.rb
@@ -29,29 +29,19 @@
require 'spec_helper'
require 'rack/test'
-describe 'API v3 Custom Options resource' do
+describe 'API v3 Custom Options resource', :aggregate_failures do
include Rack::Test::Methods
include API::V3::Utilities::PathHelper
+ shared_let(:project) { create(:project) }
let(:user) do
create(:user,
member_in_project: project,
member_through_role: role)
end
- let(:project) { create(:project) }
let(:role) { create(:role, permissions:) }
- let(:permissions) { [:view_work_packages] }
- let(:custom_field) do
- cf = create(:list_wp_custom_field)
- project.work_package_custom_fields << cf
-
- cf
- end
- let(:custom_option) do
- create(:custom_option,
- custom_field:)
- end
+ let(:modification) { nil }
subject(:response) { last_response }
@@ -59,56 +49,178 @@ describe 'API v3 Custom Options resource' do
let(:path) { api_v3_paths.custom_option custom_option.id }
before do
+ modification&.call
allow(User)
.to receive(:current)
- .and_return(user)
+ .and_return(user)
get path
end
- context 'when being allowed' do
- it 'is successful' do
- expect(subject.status)
- .to be(200)
+ describe 'WorkPackageCustomField' do
+ shared_let(:custom_field) do
+ cf = create(:list_wp_custom_field)
+
+ project.work_package_custom_fields << cf
+
+ cf
+ end
+ shared_let(:custom_option) do
+ create(:custom_option,
+ custom_field:)
+ end
+
+ context 'when being allowed' do
+ let(:permissions) { [:view_work_packages] }
+
+ it 'is successful' do
+ expect(subject.status)
+ .to be(200)
+
+ expect(response.body)
+ .to be_json_eql('CustomOption'.to_json)
+ .at_path('_type')
+
+ expect(response.body)
+ .to be_json_eql(custom_option.id.to_json)
+ .at_path('id')
+
+ expect(response.body)
+ .to be_json_eql(custom_option.value.to_json)
+ .at_path('value')
+ end
end
- it 'returns the custom option' do
- expect(response.body)
- .to be_json_eql('CustomOption'.to_json)
- .at_path('_type')
+ context 'when lacking permission' do
+ let(:permissions) { [] }
- expect(response.body)
- .to be_json_eql(custom_option.id.to_json)
- .at_path('id')
+ it 'is 404' do
+ expect(subject.status)
+ .to be(404)
+ end
+ end
- expect(response.body)
- .to be_json_eql(custom_option.value.to_json)
- .at_path('value')
+ context 'when custom option not in project' do
+ let(:permissions) { [:view_work_packages] }
+ let(:modification) do
+ -> do
+ project.work_package_custom_fields = []
+ project.save!
+ end
+ end
+
+ it 'is 404' do
+ expect(subject.status)
+ .to be(404)
+ end
end
end
- context 'when lacking permission' do
+ describe 'ProjectCustomField' do
+ shared_let(:custom_field) { create(:list_project_custom_field) }
+ shared_let(:custom_option) { create(:custom_option, custom_field:) }
+
+ context 'when being allowed' do
+ let(:permissions) { [:view_project] }
+
+ it 'is successful' do
+ expect(subject.status)
+ .to be(200)
+
+ expect(response.body)
+ .to be_json_eql('CustomOption'.to_json)
+ .at_path('_type')
+
+ expect(response.body)
+ .to be_json_eql(custom_option.id.to_json)
+ .at_path('id')
+
+ expect(response.body)
+ .to be_json_eql(custom_option.value.to_json)
+ .at_path('value')
+ end
+ end
+
+ context 'when lacking permission' do
+ let(:user) { User.anonymous }
+ let(:permissions) { [] }
+
+ it 'is 404' do
+ expect(subject.status)
+ .to be(404)
+ end
+ end
+ end
+
+ describe 'TimeEntryCustomField' do
+ shared_let(:custom_field) { create(:list_time_entry_custom_field) }
+ shared_let(:custom_option) { create(:custom_option, custom_field:) }
+
+ context 'when being allowed with log_time' do
+ let(:permissions) { [:log_time] }
+
+ it 'is successful' do
+ expect(subject.status)
+ .to be(200)
+
+ expect(response.body)
+ .to be_json_eql('CustomOption'.to_json)
+ .at_path('_type')
+
+ expect(response.body)
+ .to be_json_eql(custom_option.id.to_json)
+ .at_path('id')
+
+ expect(response.body)
+ .to be_json_eql(custom_option.value.to_json)
+ .at_path('value')
+ end
+ end
+
+ context 'when being allowed with log_own_time' do
+ let(:permissions) { [:log_own_time] }
+
+ it 'is successful' do
+ expect(subject.status)
+ .to be(200)
+ end
+ end
+
+ context 'when lacking permission' do
+ let(:user) { User.anonymous }
+ let(:permissions) { [] }
+
+ it 'is 404' do
+ expect(subject.status)
+ .to be(404)
+ end
+ end
+ end
+
+ describe 'UserCustomField' do
+ shared_let(:custom_field) { create(:list_user_custom_field) }
+ shared_let(:custom_option) { create(:custom_option, custom_field:) }
let(:permissions) { [] }
- it 'is 404' do
+ it 'is successful' do
expect(subject.status)
- .to be(404)
+ .to be(200)
end
end
- context 'when custom option not in project' do
- let(:custom_field) do
- # not added to project
- create(:list_wp_custom_field)
- end
+ describe 'GroupCustomField' do
+ shared_let(:custom_field) { create(:list_group_custom_field) }
+ shared_let(:custom_option) { create(:custom_option, custom_field:) }
+ let(:permissions) { [] }
- it 'is 404' do
+ it 'is successful' do
expect(subject.status)
- .to be(404)
+ .to be(200)
end
end
context 'when not existing' do
let(:path) { api_v3_paths.custom_option 0 }
+ let(:permissions) { [:view_work_packages] }
it 'is 404' do
expect(subject.status)
diff --git a/spec/services/notifications/create_from_model_service_comment_spec.rb b/spec/services/notifications/create_from_model_service_comment_spec.rb
index a65cc25532..2cc0263053 100644
--- a/spec/services/notifications/create_from_model_service_comment_spec.rb
+++ b/spec/services/notifications/create_from_model_service_comment_spec.rb
@@ -73,10 +73,20 @@ describe Notifications::CreateFromModelService, 'comment', with_settings: { jour
end
end
- context 'with the user having registered for involved notifications' do
+ context 'with the user having registered for assignee notifications' do
let(:recipient_notification_settings) do
[
- build(:notification_setting, **notification_settings_all_false.merge(involved: true))
+ build(:notification_setting, **notification_settings_all_false.merge(assignee: true))
+ ]
+ end
+
+ it_behaves_like 'creates no notification'
+ end
+
+ context 'with the user having registered for responsible notifications' do
+ let(:recipient_notification_settings) do
+ [
+ build(:notification_setting, **notification_settings_all_false.merge(responsible: true))
]
end
diff --git a/spec/services/notifications/create_from_model_service_message_spec.rb b/spec/services/notifications/create_from_model_service_message_spec.rb
index 8be43a0c01..576509d0b7 100644
--- a/spec/services/notifications/create_from_model_service_message_spec.rb
+++ b/spec/services/notifications/create_from_model_service_message_spec.rb
@@ -74,10 +74,20 @@ describe Notifications::CreateFromModelService, 'message', with_settings: { jour
end
end
- context 'with the user having registered for involved notifications' do
+ context 'with the user having registered for assignee notifications' do
let(:recipient_notification_settings) do
[
- build(:notification_setting, **notification_settings_all_false.merge(involved: true))
+ build(:notification_setting, **notification_settings_all_false.merge(assignee: true))
+ ]
+ end
+
+ it_behaves_like 'creates no notification'
+ end
+
+ context 'with the user having registered for responsible notifications' do
+ let(:recipient_notification_settings) do
+ [
+ build(:notification_setting, **notification_settings_all_false.merge(responsible: true))
]
end
@@ -206,10 +216,20 @@ describe Notifications::CreateFromModelService, 'message', with_settings: { jour
end
end
- context 'with the user having registered for involved notifications' do
+ context 'with the user having registered for assignee notifications' do
+ let(:recipient_notification_settings) do
+ [
+ build(:notification_setting, **notification_settings_all_false.merge(assignee: true))
+ ]
+ end
+
+ it_behaves_like 'creates no notification'
+ end
+
+ context 'with the user having registered for responsible notifications' do
let(:recipient_notification_settings) do
[
- build(:notification_setting, **notification_settings_all_false.merge(involved: true))
+ build(:notification_setting, **notification_settings_all_false.merge(responsible: true))
]
end
diff --git a/spec/services/notifications/create_from_model_service_news_spec.rb b/spec/services/notifications/create_from_model_service_news_spec.rb
index b8d3fa9c90..20a6e735a3 100644
--- a/spec/services/notifications/create_from_model_service_news_spec.rb
+++ b/spec/services/notifications/create_from_model_service_news_spec.rb
@@ -66,10 +66,20 @@ describe Notifications::CreateFromModelService, 'news', with_settings: { journal
end
end
- context 'with the user having registered for involved notifications' do
+ context 'with the user having registered for assignee notifications' do
let(:recipient_notification_settings) do
[
- build(:notification_setting, **notification_settings_all_false.merge(involved: true))
+ build(:notification_setting, **notification_settings_all_false.merge(assignee: true))
+ ]
+ end
+
+ it_behaves_like 'creates no notification'
+ end
+
+ context 'with the user having registered for responsible notifications' do
+ let(:recipient_notification_settings) do
+ [
+ build(:notification_setting, **notification_settings_all_false.merge(responsible: true))
]
end
diff --git a/spec/services/notifications/create_from_model_service_wiki_spec.rb b/spec/services/notifications/create_from_model_service_wiki_spec.rb
index 7471a0bf2f..49be368284 100644
--- a/spec/services/notifications/create_from_model_service_wiki_spec.rb
+++ b/spec/services/notifications/create_from_model_service_wiki_spec.rb
@@ -72,10 +72,20 @@ describe Notifications::CreateFromModelService, 'wiki', with_settings: { journal
end
end
- context 'with the user having registered for involved notifications' do
+ context 'with the user having registered for assignee notifications' do
let(:recipient_notification_settings) do
[
- build(:notification_setting, **notification_settings_all_false.merge(involved: true))
+ build(:notification_setting, **notification_settings_all_false.merge(assignee: true))
+ ]
+ end
+
+ it_behaves_like 'creates no notification'
+ end
+
+ context 'with the user having registered for responsible notifications' do
+ let(:recipient_notification_settings) do
+ [
+ build(:notification_setting, **notification_settings_all_false.merge(responsible: true))
]
end
@@ -165,10 +175,20 @@ describe Notifications::CreateFromModelService, 'wiki', with_settings: { journal
end
end
- context 'with the user having registered for involved notifications' do
+ context 'with the user having registered for assignee notifications' do
+ let(:recipient_notification_settings) do
+ [
+ build(:notification_setting, **notification_settings_all_false.merge(assignee: true))
+ ]
+ end
+
+ it_behaves_like 'creates no notification'
+ end
+
+ context 'with the user having registered for responsible notifications' do
let(:recipient_notification_settings) do
[
- build(:notification_setting, **notification_settings_all_false.merge(involved: true))
+ build(:notification_setting, **notification_settings_all_false.merge(responsible: true))
]
end
diff --git a/spec/services/notifications/create_from_model_service_work_package_spec.rb b/spec/services/notifications/create_from_model_service_work_package_spec.rb
index 57d8d81510..7c35fb6697 100644
--- a/spec/services/notifications/create_from_model_service_work_package_spec.rb
+++ b/spec/services/notifications/create_from_model_service_work_package_spec.rb
@@ -103,7 +103,7 @@ describe Notifications::CreateFromModelService,
let(:user_property) { :assigned_to }
let(:recipient_notification_settings) do
[
- build(:notification_setting, **notification_settings_all_false.merge(involved: true))
+ build(:notification_setting, **notification_settings_all_false.merge(assignee: true))
]
end
@@ -147,10 +147,10 @@ describe Notifications::CreateFromModelService,
it_behaves_like 'creates no notification'
end
- context 'when assignee has all in app notifications enabled but only involved for mail' do
+ context 'when assignee has all in app notifications enabled but only assignee for mail' do
let(:recipient_notification_settings) do
[
- build(:notification_setting, **notification_settings_all_false.merge(involved: true))
+ build(:notification_setting, **notification_settings_all_false.merge(assignee: true))
]
end
@@ -194,7 +194,7 @@ describe Notifications::CreateFromModelService,
let(:user_property) { :responsible }
let(:recipient_notification_settings) do
[
- build(:notification_setting, **notification_settings_all_false.merge(involved: true))
+ build(:notification_setting, **notification_settings_all_false.merge(responsible: true))
]
end
diff --git a/spec/services/notifications/mail_service_mentioned_integration_spec.rb b/spec/services/notifications/mail_service_mentioned_integration_spec.rb
index 0cba2953ca..cbb9b1be65 100644
--- a/spec/services/notifications/mail_service_mentioned_integration_spec.rb
+++ b/spec/services/notifications/mail_service_mentioned_integration_spec.rb
@@ -42,7 +42,8 @@ describe Notifications::MailService, 'Mentioned integration', type: :model do
notification_settings: [
build(:notification_setting,
mentioned: true,
- involved: true)
+ assignee: true,
+ responsible: true)
],
member_in_project: project,
member_through_role: role
@@ -62,7 +63,12 @@ describe Notifications::MailService, 'Mentioned integration', type: :model do
end
def expect_no_assigned_notification
- expect(Notification.where(recipient:, resource: work_package, reason: :involved))
+ expect(Notification.where(recipient:, resource: work_package, reason: :assignee))
+ .to be_empty
+ end
+
+ def expect_no_responsible_notification
+ expect(Notification.where(recipient:, resource: work_package, reason: :responsible))
.to be_empty
end
@@ -94,9 +100,10 @@ describe Notifications::MailService, 'Mentioned integration', type: :model do
.to have_received(:mentioned)
.once
- # No involved notification since the assignee is also mentioned which trumps
+ # No assignee and responsible notification since the assignee is also mentioned which trumps
# being assignee and a user will only get one notification for a journal.
expect_no_assigned_notification
+ expect_no_responsible_notification
expect_mentioned_notification
update_assignee!(assignee)
diff --git a/spec/services/notifications/mentioned_journals_shared.rb b/spec/services/notifications/mentioned_journals_shared.rb
index 86f19c18a7..9d83de4cfe 100644
--- a/spec/services/notifications/mentioned_journals_shared.rb
+++ b/spec/services/notifications/mentioned_journals_shared.rb
@@ -52,7 +52,8 @@ shared_context 'with a mentioned work package being updated again' do
notification_settings: [
build(:notification_setting,
mentioned: true,
- involved: true)
+ assignee: true,
+ responsible: true)
],
member_in_project: project,
member_through_role: role
diff --git a/spec/services/projects/copy_service_integration_spec.rb b/spec/services/projects/copy_service_integration_spec.rb
index c8744794ce..a59aa968ab 100644
--- a/spec/services/projects/copy_service_integration_spec.rb
+++ b/spec/services/projects/copy_service_integration_spec.rb
@@ -71,6 +71,20 @@ describe Projects::CopyService, 'integration', type: :model do
.and_return(new_project_role.id.to_s)
end
+ describe '.copyable_dependencies' do
+ it 'includes dependencies for work packages as well as for their attachments' do
+ expect(described_class.copyable_dependencies.pluck(:identifier))
+ .to include(::Projects::Copy::WorkPackagesDependentService.identifier,
+ ::Projects::Copy::WorkPackageAttachmentsDependentService.identifier)
+ end
+
+ it 'includes dependencies for wiki as well as for their pages\'s attachments' do
+ expect(described_class.copyable_dependencies.pluck(:identifier))
+ .to include(::Projects::Copy::WikiDependentService.identifier,
+ ::Projects::Copy::WikiPageAttachmentsDependentService.identifier)
+ end
+ end
+
describe 'call' do
subject { instance.call(params) }
@@ -288,6 +302,35 @@ describe Projects::CopyService, 'integration', type: :model do
expect(subject).to be_success
expect(project_copy.wiki.wiki_menu_items.count).to eq 3
end
+
+ context 'with attachments' do
+ let!(:attachment) { create(:attachment, container: source_wiki_page) }
+
+ context 'when requested' do
+ let(:only_args) { %i[wiki wiki_page_attachments] }
+
+ it 'copies them' do
+ expect(subject).to be_success
+ expect(subject.errors).to be_empty
+ expect(project_copy.wiki.pages.count).to eq 2
+
+ page = project_copy.wiki.pages.find_by(title: source_wiki_page.title)
+ expect(page.attachments.count).to eq(1)
+ expect(page.attachments.first.author).to eql(current_user)
+ end
+ end
+
+ context 'when not requested' do
+ it 'ignores them' do
+ expect(subject).to be_success
+ expect(subject.errors).to be_empty
+ expect(project_copy.wiki.pages.count).to eq 2
+
+ page = project_copy.wiki.pages.find_by(title: source_wiki_page.title)
+ expect(page.attachments.count).to eq(0)
+ end
+ end
+ end
end
describe 'valid queries' do
@@ -366,7 +409,7 @@ describe Projects::CopyService, 'integration', type: :model do
let(:only_args) { %w[work_packages] }
- describe '#attachments' do
+ context 'with attachments' do
let!(:attachment) { create(:attachment, container: work_package) }
context 'when requested' do
diff --git a/spec/services/user_preferences/update_service_integration_spec.rb b/spec/services/user_preferences/update_service_integration_spec.rb
index de5c56847e..4519acbd4f 100644
--- a/spec/services/user_preferences/update_service_integration_spec.rb
+++ b/spec/services/user_preferences/update_service_integration_spec.rb
@@ -60,7 +60,8 @@ describe UserPreferences::UpdateService, 'integration', type: :model do
{
project_id: nil,
watched: false,
- involved: true,
+ assignee: true,
+ responsible: true,
work_package_commented: false,
work_package_created: true,
work_package_processed: true,
@@ -76,7 +77,8 @@ describe UserPreferences::UpdateService, 'integration', type: :model do
expect(default_ian.watched).to be true
expect(default_ian.mentioned).to be true
- expect(default_ian.involved).to be true
+ expect(default_ian.assignee).to be true
+ expect(default_ian.responsible).to be true
expect(default_ian.work_package_commented).to be true
expect(default_ian.work_package_created).to be true
expect(default_ian.work_package_processed).to be true
@@ -87,7 +89,8 @@ describe UserPreferences::UpdateService, 'integration', type: :model do
expect(subject.first.project_id).to be_nil
expect(subject.first.mentioned).to be false
expect(subject.first.watched).to be false
- expect(subject.first.involved).to be true
+ expect(default_ian.assignee).to be true
+ expect(default_ian.responsible).to be true
expect(subject.first.work_package_commented).to be false
expect(subject.first.work_package_created).to be true
expect(subject.first.work_package_processed).to be true
diff --git a/spec/services/wiki_pages/copy_service_integration_spec.rb b/spec/services/wiki_pages/copy_service_integration_spec.rb
index 7a76460cdb..d2711ffd2d 100644
--- a/spec/services/wiki_pages/copy_service_integration_spec.rb
+++ b/spec/services/wiki_pages/copy_service_integration_spec.rb
@@ -95,6 +95,35 @@ describe WikiPages::CopyService, 'integration', type: :model do
it 'sets the author to be the current user' do
expect(copy.content.author).to eq(user)
end
+
+ context 'with attachments' do
+ let!(:attachment) do
+ create(:attachment,
+ container: wiki_page)
+ end
+
+ context 'when specifying to copy attachments (default)' do
+ it 'copies the attachment' do
+ expect(copy.attachments.length)
+ .to eq 1
+
+ expect(copy.attachments.first.attributes.slice(:digest, :file, :filesize))
+ .to eq attachment.attributes.slice(:digest, :file, :filesize)
+
+ expect(copy.attachments.first.id)
+ .not_to eq attachment.id
+ end
+ end
+
+ context 'when specifying to not copy attachments' do
+ let(:attributes) { { copy_attachments: false } }
+
+ it 'copies the attachment' do
+ expect(copy.attachments.length)
+ .to eq 0
+ end
+ end
+ end
end
describe 'to a different wiki' do
diff --git a/spec/services/work_packages/copy_service_integration_spec.rb b/spec/services/work_packages/copy_service_integration_spec.rb
index 3b283b576a..cb85cef941 100644
--- a/spec/services/work_packages/copy_service_integration_spec.rb
+++ b/spec/services/work_packages/copy_service_integration_spec.rb
@@ -73,9 +73,7 @@ describe WorkPackages::CopyService, 'integration', type: :model do
.call(**attributes)
end
- before do
- login_as(user)
- end
+ current_user { user }
describe '#call' do
shared_examples_for 'copied work package' do
@@ -301,5 +299,34 @@ describe WorkPackages::CopyService, 'integration', type: :model do
it_behaves_like 'copied work package'
end
+
+ context 'with attachments' do
+ let!(:attachment) do
+ create(:attachment,
+ container: work_package)
+ end
+
+ context 'when specifying to copy attachments (default)' do
+ it 'copies the attachment' do
+ expect(copy.attachments.length)
+ .to eq 1
+
+ expect(copy.attachments.first.attributes.slice(:digest, :file, :filesize))
+ .to eq attachment.attributes.slice(:digest, :file, :filesize)
+
+ expect(copy.attachments.first.id)
+ .not_to eq attachment.id
+ end
+ end
+
+ context 'when specifying to not copy attachments' do
+ let(:attributes) { { copy_attachments: false } }
+
+ it 'copies the attachment' do
+ expect(copy.attachments.length)
+ .to eq 0
+ end
+ end
+ end
end
end
diff --git a/spec/services/work_packages/set_schedule_service_spec.rb b/spec/services/work_packages/set_schedule_service_spec.rb
index 63236ce4ad..48e693c4d6 100644
--- a/spec/services/work_packages/set_schedule_service_spec.rb
+++ b/spec/services/work_packages/set_schedule_service_spec.rb
@@ -73,14 +73,7 @@ describe WorkPackages::SetScheduleService do
let(:parent_follower1_due_date) { follower1_due_date }
let(:parent_following_work_package1) do
- work_package = create_follower(parent_follower1_start_date,
- parent_follower1_due_date,
- {})
-
- following_work_package1.parent = work_package
- following_work_package1.save
-
- work_package
+ create_parent(following_work_package1)
end
let(:follower_sibling_work_package) do
@@ -109,6 +102,16 @@ describe WorkPackages::SetScheduleService do
work_package
end
+ def create_parent(child, start_date: child.start_date, due_date: child.due_date)
+ create(:work_package,
+ subject: "parent of #{child.subject}",
+ start_date:,
+ due_date:).tap do |parent|
+ child.parent = parent
+ child.save
+ end
+ end
+
def create_child(parent, start_date, due_date)
create(:work_package,
subject: "child of #{parent.subject}",
@@ -836,4 +839,34 @@ describe WorkPackages::SetScheduleService do
end
end
end
+
+ context 'with deep hierarchy of work packages' do
+ before do
+ work_package.due_date = Time.zone.today - 5.days
+ end
+
+ def create_hierarchy(parent, nb_children_by_levels)
+ nb_children, *remaining_levels = nb_children_by_levels
+ children = create_list(:work_package, nb_children, parent:)
+ if remaining_levels.any?
+ children.each do |child|
+ create_hierarchy(child, remaining_levels)
+ end
+ end
+ end
+
+ it 'does not fail with a SystemStackError (regression #43894)' do
+ parent = create(:work_package, start_date: Date.current, due_date: Date.current)
+ hierarchy = [1, 1, 1, 1, 2, 4, 4, 4]
+ create_hierarchy(parent, hierarchy)
+
+ # The bug triggers when moving work package is in the middle of the
+ # hierarchy
+ work_package.parent = parent.children.first.children.first.children.first
+ work_package.save
+
+ expect { instance.call(attributes) }
+ .not_to raise_error
+ end
+ end
end
diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb
deleted file mode 100644
index 0c08beeec0..0000000000
--- a/spec/support/database_cleaner.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-RSpec.configure do |config|
- # Since Rails 5.1., we can force the application server and capybara to share the same connection,
- # which results in database_cleaner no longer being necessary.
- # This will only work with a server that works in single mode (e.g., Puma)
- # Using it we can ensure we run with a clean database (which use_transactional_fixtures does not ensure).
- # c.f., spec/support/database_cleaner
- config.use_transactional_fixtures = true
-
- config.before(:suite) do
- DatabaseCleaner.clean_with(:truncation)
- end
-end
diff --git a/spec/support/pages/notifications/settings.rb b/spec/support/pages/notifications/settings.rb
index cb2d988e2d..42ed49164d 100644
--- a/spec/support/pages/notifications/settings.rb
+++ b/spec/support/pages/notifications/settings.rb
@@ -53,7 +53,8 @@ module Pages
def expect_global_represented(setting)
%i[
- involved
+ assignee
+ responsible
work_package_commented
work_package_created
work_package_processed
diff --git a/spec/support/transactional_tests.rb b/spec/support/transactional_tests.rb
new file mode 100644
index 0000000000..be21c10e65
--- /dev/null
+++ b/spec/support/transactional_tests.rb
@@ -0,0 +1,9 @@
+RSpec.configure do |config|
+ # Rails 5.1+ safely shares the database connection between the app and test
+ # threads. So RSpec thread and Puma thread share the same db connection,
+ # meaning running tests in transaction is ok as the transaction will be
+ # visible for both.
+
+ # Run every test method within a transaction
+ config.use_transactional_fixtures = true
+end
diff --git a/spec/workers/backup_job_spec.rb b/spec/workers/backup_job_spec.rb
index ab8f1a1bd9..e2c3b6c1ed 100644
--- a/spec/workers/backup_job_spec.rb
+++ b/spec/workers/backup_job_spec.rb
@@ -69,7 +69,7 @@ describe BackupJob, type: :model do
allow(job).to receive(:arguments).and_return arguments
allow(job).to receive(:job_id).and_return job_id
- expect(Open3).to receive(:capture3).and_return [nil, "Dump failed", db_dump_process_status]
+ allow(Open3).to receive(:capture3).and_return [nil, "Dump failed", db_dump_process_status]
allow_any_instance_of(BackupJob)
.to receive(:tmp_file_name).with("openproject", ".sql").and_return("/tmp/openproject.sql")
@@ -85,6 +85,31 @@ describe BackupJob, type: :model do
job.perform **arguments.first
end
+ describe '#pg_env' do
+ subject { job.pg_env }
+
+ context 'when config has user reference, not username (regression #44251)' do
+ let(:config_double) do
+ {
+ adapter: :postgresql,
+ password: "blabla",
+ database: "test",
+ user: "foobar"
+ }
+ end
+
+ before do
+ allow(job).to receive(:database_config).and_return(config_double)
+ end
+
+ it 'still sets a PGUSER' do
+ expect(subject['PGUSER']).to eq 'foobar'
+ expect(subject['PGPASSWORD']).to eq 'blabla'
+ expect(subject['PGDATABASE']).to eq 'test'
+ end
+ end
+ end
+
context "with a failed database dump" do
let(:db_dump_success) { false }
@@ -175,7 +200,7 @@ describe BackupJob, type: :model do
allow_any_instance_of(LocalFileUploader).to receive(:cached?).and_return(true)
allow_any_instance_of(LocalFileUploader)
.to receive(:local_file)
- .and_return(File.new(dummy_path))
+ .and_return(File.new(dummy_path))
end
after do
diff --git a/spec/workers/copy_project_job_spec.rb b/spec/workers/copy_project_job_spec.rb
index c4bddcd2e7..9686c863b3 100644
--- a/spec/workers/copy_project_job_spec.rb
+++ b/spec/workers/copy_project_job_spec.rb
@@ -45,7 +45,7 @@ describe CopyProjectJob, type: :model do
let(:target_project) { create(:project) }
let(:copy_job) do
- CopyProjectJob.new
+ described_class.new
end
it 'sets locale correctly' do
@@ -126,7 +126,7 @@ describe CopyProjectJob, type: :model do
end
let(:copy_job) do
- CopyProjectJob.new.tap do |job|
+ described_class.new.tap do |job|
job.perform user_id: admin.id,
source_project_id: source_project.id,
target_project_params: params,
@@ -155,7 +155,7 @@ describe CopyProjectJob, type: :model do
let(:admin) { create(:admin) }
let(:source_project) { create(:project) }
let(:copy_job) do
- CopyProjectJob.new.tap do |job|
+ described_class.new.tap do |job|
job.perform user_id: admin.id,
source_project_id: source_project.id,
target_project_params: params,
@@ -188,7 +188,7 @@ describe CopyProjectJob, type: :model do
shared_context 'copy project' do
before do
- CopyProjectJob.new.tap do |job|
+ described_class.new.tap do |job|
job.perform user_id: user.id,
source_project_id: project_to_copy.id,
target_project_params: params,
@@ -204,7 +204,7 @@ describe CopyProjectJob, type: :model do
end
describe 'subproject' do
- let(:params) { { name: 'Copy', identifier: 'copy', parent_id: project.id } }
+ let(:params) { { name: 'Copy', identifier: 'copy' } }
let(:subproject) do
create(:project, parent: project).tap do |p|
create(:member,
@@ -232,7 +232,7 @@ describe CopyProjectJob, type: :model do
perform_enqueued_jobs
mail = ActionMailer::Base.deliveries
- .find { |m| m.message_id.start_with? "op.project-#{subject.id}" }
+ .find { |m| m.message_id.start_with? "op.project-#{subject.id}" }
expect(mail).to be_present
expect(mail.subject).to eq "Created project #{subject.name}"
@@ -240,6 +240,27 @@ describe CopyProjectJob, type: :model do
end
end
+ describe 'user without add_subprojects permission in parent and when explicitly setting that parent' do
+ let(:params) { { name: 'Copy', identifier: 'copy', parent_id: project.id } }
+
+ include_context 'copy project' do
+ let(:project_to_copy) { subproject }
+ end
+
+ it 'does not copy the project' do
+ expect(subject).to be_nil
+ end
+
+ it "notifies the user of that parent not being allowed" do
+ perform_enqueued_jobs
+
+ mail = ActionMailer::Base.deliveries.first
+ expect(mail).to be_present
+ expect(mail.subject).to eq I18n.t('copy_project.failed', source_project_name: subproject.name)
+ expect(mail.to).to eq [user.mail]
+ end
+ end
+
describe 'user with add_subprojects permission in parent' do
let(:role_add_subproject) { create(:role, permissions: [:add_subprojects]) }
let(:member_add_subproject) do
diff --git a/spec/workers/mails/shared/watcher_job.rb b/spec/workers/mails/shared/watcher_job.rb
index 3e025cdcd8..d75809fa5c 100644
--- a/spec/workers/mails/shared/watcher_job.rb
+++ b/spec/workers/mails/shared/watcher_job.rb
@@ -126,25 +126,25 @@ shared_examples "watcher job" do |action|
it_behaves_like 'notifies the watcher' do
let(:notification_settings) do
- [build_stubbed(:notification_setting, mentioned: false, involved: false, watched: true)]
+ [build_stubbed(:notification_setting, mentioned: false, assignee: false, responsible: false, watched: true)]
end
end
it_behaves_like 'notifies the watcher' do
let(:notification_settings) do
- [build_stubbed(:notification_setting, mentioned: false, involved: false, watched: true)]
+ [build_stubbed(:notification_setting, mentioned: false, assignee: false, responsible: false, watched: true)]
end
end
it_behaves_like 'does not notify the watcher' do
let(:notification_settings) do
- [build_stubbed(:notification_setting, mentioned: false, involved: true, watched: false)]
+ [build_stubbed(:notification_setting, mentioned: false, assignee: true, responsible: true, watched: false)]
end
end
it_behaves_like 'does not notify the watcher' do
let(:notification_settings) do
- [build_stubbed(:notification_setting, mentioned: true, involved: false, watched: false)]
+ [build_stubbed(:notification_setting, mentioned: true, assignee: false, responsible: false, watched: false)]
end
end
diff --git a/spec_legacy/fixtures/attachments.yml b/spec_legacy/fixtures/attachments.yml
deleted file mode 100644
index 300ddba898..0000000000
--- a/spec_legacy/fixtures/attachments.yml
+++ /dev/null
@@ -1,139 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-attachments_001:
- created_at: 2006-07-19 21:07:27 +02:00
- downloads: 0
- content_type: text/plain
- disk_filename: 060719210727_error281.txt
- container_id: 3
- digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
- id: 1
- container_type: WorkPackage
- filesize: 28
- filename: error281.txt
- author_id: 2
-attachments_003:
- created_at: 2006-07-19 21:07:27 +02:00
- downloads: 0
- content_type: image/gif
- disk_filename: 060719210727_logo.gif
- container_id: 4
- digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
- id: 3
- container_type: WikiPage
- filesize: 280
- filename: logo.gif
- description: This is a logo
- author_id: 2
-attachments_004:
- created_at: 2006-07-19 21:07:27 +02:00
- container_type: WorkPackage
- container_id: 3
- downloads: 0
- disk_filename: 060719210727_source.rb
- digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
- id: 4
- filesize: 153
- filename: source.rb
- author_id: 2
- description: This is a Ruby source file
- content_type: text/x-ruby
-attachments_005:
- created_at: 2006-07-19 21:07:27 +02:00
- container_type: WorkPackage
- container_id: 3
- downloads: 0
- disk_filename: 060719210727_changeset_iso8859-1.diff
- digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
- id: 5
- filesize: 687
- filename: changeset_iso8859-1.diff
- author_id: 2
- content_type: text/x-diff
-attachments_006:
- created_at: 2006-07-19 21:07:27 +02:00
- container_type: WorkPackage
- container_id: 3
- downloads: 0
- disk_filename: 060719210727_archive.zip
- digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
- id: 6
- filesize: 157
- filename: archive.zip
- author_id: 2
- content_type: application/zip
-attachments_007:
- created_at: 2006-07-19 21:07:27 +02:00
- container_type: WorkPackage
- container_id: 4
- downloads: 0
- disk_filename: 060719210727_archive.zip
- digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
- id: 7
- filesize: 157
- filename: archive.zip
- author_id: 1
- content_type: application/zip
-attachments_010:
- created_at: 2006-07-19 21:07:27 +02:00
- container_type: WorkPackage
- container_id: 2
- downloads: 0
- disk_filename: 060719210727_picture.jpg
- digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
- id: 10
- filesize: 452
- filename: picture.jpg
- author_id: 2
- content_type: image/jpeg
-attachments_013:
- created_at: 2006-07-19 21:07:27 +02:00
- container_type: Message
- container_id: 1
- downloads: 0
- disk_filename: 060719210727_foo.zip
- digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
- id: 13
- filesize: 452
- filename: foo.zip
- author_id: 2
- content_type: application/octet-stream
-attachments_014:
- created_at: 2006-07-19 21:07:27 +02:00
- container_type: WorkPackage
- container_id: 3
- downloads: 0
- disk_filename: 060719210727_changeset_utf8.diff
- digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
- id: 14
- filesize: 687
- filename: changeset_utf8.diff
- author_id: 2
- content_type: text/x-diff
diff --git a/spec_legacy/fixtures/categories.yml b/spec_legacy/fixtures/categories.yml
deleted file mode 100644
index 80f6bfb3bc..0000000000
--- a/spec_legacy/fixtures/categories.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-categories_001:
- name: Printing
- project_id: 1
- assigned_to_id: 2
- id: 1
-categories_002:
- name: Recipes
- project_id: 1
- assigned_to_id:
- id: 2
-categories_003:
- name: Stock management
- project_id: 2
- assigned_to_id:
- id: 3
-categories_004:
- name: Printing
- project_id: 2
- assigned_to_id:
- id: 4
-
diff --git a/spec_legacy/fixtures/changes.yml b/spec_legacy/fixtures/changes.yml
deleted file mode 100644
index 9d997c6c33..0000000000
--- a/spec_legacy/fixtures/changes.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-changes_001:
- id: 1
- changeset_id: 100
- action: A
- path: /test/some/path/in/the/repo
- from_path:
- from_revision:
-changes_002:
- id: 2
- changeset_id: 100
- action: A
- path: /test/some/path/elsewhere/in/the/repo
- from_path:
- from_revision:
-changes_003:
- id: 3
- changeset_id: 101
- action: M
- path: /test/some/path/in/the/repo
- from_path:
- from_revision:
-
diff --git a/spec_legacy/fixtures/changesets.yml b/spec_legacy/fixtures/changesets.yml
deleted file mode 100644
index 2a7c8acae9..0000000000
--- a/spec_legacy/fixtures/changesets.yml
+++ /dev/null
@@ -1,132 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-changesets_001:
- commit_date: 2007-04-11
- committed_on: 2007-04-11 15:14:44 +02:00
- revision: 1
- id: 100
- comments: My very first commit
- repository_id: 10
- committer: dlopper
- user_id: 3
-changesets_002:
- commit_date: 2007-04-12
- committed_on: 2007-04-12 15:14:44 +02:00
- revision: 2
- id: 101
- comments: 'This commit fixes #1, #2 and references #1 & #3'
- repository_id: 10
- committer: dlopper
- user_id: 3
-changesets_003:
- commit_date: 2007-04-12
- committed_on: 2007-04-12 15:14:44 +02:00
- revision: 3
- id: 102
- comments: |-
- A commit with wrong issue ids
- IssueID #666 #3
- repository_id: 10
- committer: dlopper
- user_id: 3
-changesets_004:
- commit_date: 2007-04-12
- committed_on: 2007-04-12 15:14:44 +02:00
- revision: 4
- id: 103
- comments: |-
- A commit with an issue id of an other project
- IssueID 4 2
- repository_id: 10
- committer: dlopper
- user_id: 3
-changesets_005:
- commit_date: "2007-09-10"
- comments: Modified one file in the folder.
- committed_on: 2007-09-10 19:01:08
- revision: "5"
- id: 104
- scmid:
- user_id: 3
- repository_id: 10
- committer: dlopper
-changesets_006:
- commit_date: "2007-09-10"
- comments: Moved helloworld.rb from / to /folder.
- committed_on: 2007-09-10 19:01:47
- revision: "6"
- id: 105
- scmid:
- user_id: 3
- repository_id: 10
- committer: dlopper
-changesets_007:
- commit_date: "2007-09-10"
- comments: Removed one file.
- committed_on: 2007-09-10 19:02:16
- revision: "7"
- id: 106
- scmid:
- user_id: 3
- repository_id: 10
- committer: dlopper
-changesets_008:
- commit_date: "2007-09-10"
- comments: |-
- This commits references an issue.
- Refs #2
- committed_on: 2007-09-10 19:04:35
- revision: "8"
- id: 107
- scmid:
- user_id: 3
- repository_id: 10
- committer: dlopper
-changesets_009:
- commit_date: "2009-09-10"
- comments: One file added.
- committed_on: 2009-09-10 19:04:35
- revision: "9"
- id: 108
- scmid:
- user_id: 3
- repository_id: 10
- committer: dlopper
-changesets_010:
- commit_date: "2009-09-10"
- comments: Same file modified.
- committed_on: 2009-09-10 19:04:35
- revision: "10"
- id: 109
- scmid:
- user_id: 3
- repository_id: 10
- committer: dlopper
-
diff --git a/spec_legacy/fixtures/comments.yml b/spec_legacy/fixtures/comments.yml
deleted file mode 100644
index 74b37405dc..0000000000
--- a/spec_legacy/fixtures/comments.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
-comments_001:
- commented_type: News
- commented_id: 1
- id: 1
- author_id: 1
- comments: my first comment
- created_at: 2006-12-10 18:10:10 +01:00
- updated_at: 2006-12-10 18:10:10 +01:00
-comments_002:
- commented_type: News
- commented_id: 1
- id: 2
- author_id: 2
- comments: This is an other comment
- created_at: 2006-12-10 18:12:10 +01:00
- updated_at: 2006-12-10 18:12:10 +01:00
-
diff --git a/spec_legacy/fixtures/custom_fields.yml b/spec_legacy/fixtures/custom_fields.yml
deleted file mode 100644
index 9e01197289..0000000000
--- a/spec_legacy/fixtures/custom_fields.yml
+++ /dev/null
@@ -1,123 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-custom_fields_001:
- name: Database
- min_length: 0
- regexp: ""
- is_for_all: true
- is_filter: true
- type: WorkPackageCustomField
- max_length: 0
- id: 1
- is_required: false
- field_format: list
- editable: true
-custom_fields_002:
- name: "Searchable field"
- min_length: 1
- regexp: ""
- is_for_all: true
- type: WorkPackageCustomField
- max_length: 100
- id: 2
- is_required: false
- field_format: string
- searchable: true
- editable: true
- default_value: "Default string"
-custom_fields_003:
- name: "Development status"
- min_length: 0
- regexp: ""
- is_for_all: false
- is_filter: true
- type: ProjectCustomField
- max_length: 0
- id: 3
- is_required: false
- field_format: list
- editable: true
-custom_fields_004:
- name: "Phone number"
- min_length: 0
- regexp: ""
- is_for_all: false
- type: UserCustomField
- max_length: 0
- id: 4
- is_required: false
- field_format: string
- editable: true
-custom_fields_005:
- name: Money
- min_length: 0
- regexp: ""
- is_for_all: false
- type: UserCustomField
- max_length: 0
- id: 5
- is_required: false
- field_format: float
- editable: true
-custom_fields_006:
- name: "Float field"
- min_length: 0
- regexp: ""
- is_for_all: true
- type: WorkPackageCustomField
- max_length: 0
- id: 6
- is_required: false
- field_format: float
- editable: true
-custom_fields_008:
- name: "Custom date"
- min_length: 0
- regexp: ""
- is_for_all: true
- is_filter: false
- type: WorkPackageCustomField
- max_length: 0
- id: 8
- is_required: false
- field_format: date
- editable: true
-custom_fields_009:
- name: "Project 1 cf"
- min_length: 0
- regexp: ""
- is_for_all: false
- is_filter: true
- type: WorkPackageCustomField
- max_length: 0
- id: 9
- is_required: false
- field_format: date
- editable: true
diff --git a/spec_legacy/fixtures/custom_fields_projects.yml b/spec_legacy/fixtures/custom_fields_projects.yml
deleted file mode 100644
index 6d0f23b27a..0000000000
--- a/spec_legacy/fixtures/custom_fields_projects.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-custom_fields_projects_001:
- custom_field_id: 9
- project_id: 1
diff --git a/spec_legacy/fixtures/custom_fields_types.yml b/spec_legacy/fixtures/custom_fields_types.yml
deleted file mode 100644
index 3d78da811c..0000000000
--- a/spec_legacy/fixtures/custom_fields_types.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-custom_fields_types_001:
- custom_field_id: 1
- type_id: 1
-custom_fields_types_002:
- custom_field_id: 2
- type_id: 1
-custom_fields_types_003:
- custom_field_id: 2
- type_id: 3
-custom_fields_types_004:
- custom_field_id: 6
- type_id: 1
-custom_fields_types_005:
- custom_field_id: 6
- type_id: 2
-custom_fields_types_006:
- custom_field_id: 6
- type_id: 3
-custom_fields_types_007:
- custom_field_id: 8
- type_id: 1
diff --git a/spec_legacy/fixtures/custom_options.yml b/spec_legacy/fixtures/custom_options.yml
deleted file mode 100644
index 5815a3e0de..0000000000
--- a/spec_legacy/fixtures/custom_options.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-custom_option_001:
- id: 1
- custom_field_id: 1
- position: 1
- value: MySQL
- default_value: false
-custom_option_002:
- id: 2
- custom_field_id: 1
- position: 2
- value: PostgreSQL
- default_value: false
-custom_option_003:
- id: 3
- custom_field_id: 1
- position: 3
- value: Oracle
- default_value: false
-custom_option_004:
- id: 4
- custom_field_id: 3
- position: 1
- value: Stable
- default_value: false
-custom_option_005:
- id: 5
- custom_field_id: 3
- position: 2
- value: Beta
- default_value: false
-custom_option_006:
- id: 6
- custom_field_id: 3
- position: 3
- value: Alpha
- default_value: false
-custom_option_007:
- id: 7
- custom_field_id: 3
- position: 4
- value: Planning
- default_value: false
diff --git a/spec_legacy/fixtures/custom_values.yml b/spec_legacy/fixtures/custom_values.yml
deleted file mode 100644
index 1dab703ebe..0000000000
--- a/spec_legacy/fixtures/custom_values.yml
+++ /dev/null
@@ -1,143 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-custom_values_006:
- customized_type: WorkPackage
- custom_field_id: 2
- customized_id: 3
- id: 6
- value: "125"
-custom_values_007:
- customized_type: Project
- custom_field_id: 3
- customized_id: 1
- id: 7
- value: "4"
-custom_values_001:
- customized_type: Principal
- custom_field_id: 4
- customized_id: 3
- id: 1
- value: ""
-custom_values_002:
- customized_type: Principal
- custom_field_id: 4
- customized_id: 4
- id: 2
- value: 01 23 45 67 89
-custom_values_003:
- customized_type: Principal
- custom_field_id: 4
- customized_id: 2
- id: 3
- value: "01 42 50 00 00"
-custom_values_004:
- customized_type: WorkPackage
- custom_field_id: 2
- customized_id: 1
- id: 4
- value: "125"
-custom_values_005:
- customized_type: WorkPackage
- custom_field_id: 2
- customized_id: 2
- id: 5
- value: ""
-custom_values_008:
- customized_type: WorkPackage
- custom_field_id: 1
- customized_id: 3
- id: 8
- value: "1"
-custom_values_009:
- customized_type: WorkPackage
- custom_field_id: 2
- customized_id: 7
- id: 9
- value: "this is a stringforcustomfield search"
-custom_values_010:
- customized_type: WorkPackage
- custom_field_id: 6
- customized_id: 1
- id: 10
- value: "2.1"
-custom_values_011:
- customized_type: WorkPackage
- custom_field_id: 6
- customized_id: 2
- id: 11
- value: "2.05"
-custom_values_012:
- customized_type: WorkPackage
- custom_field_id: 6
- customized_id: 3
- id: 12
- value: "11.65"
-custom_values_013:
- customized_type: WorkPackage
- custom_field_id: 6
- customized_id: 7
- id: 13
- value: ""
-custom_values_014:
- customized_type: WorkPackage
- custom_field_id: 6
- customized_id: 5
- id: 14
- value: "-7.6"
-custom_values_015:
- customized_type: Enumeration
- custom_field_id: 7
- customized_id: 10
- id: 15
- value: true
-custom_values_016:
- customized_type: Enumeration
- custom_field_id: 7
- customized_id: 11
- id: 16
- value: '1'
-custom_values_017:
- customized_type: WorkPackage
- custom_field_id: 8
- customized_id: 1
- id: 17
- value: '2009-12-01'
-custom_values_018:
- customized_type: WorkPackage
- custom_field_id: 1
- customized_id: 1
- id: 18
- value: "3"
-custom_values_019:
- customized_type: WorkPackage
- custom_field_id: 8
- customized_id: 3
- id: 19
- value: '2009-12-01'
diff --git a/spec_legacy/fixtures/files/060719210727_archive.zip b/spec_legacy/fixtures/files/060719210727_archive.zip
deleted file mode 100644
index 5467885d4b..0000000000
Binary files a/spec_legacy/fixtures/files/060719210727_archive.zip and /dev/null differ
diff --git a/spec_legacy/fixtures/files/060719210727_changeset_iso8859-1.diff b/spec_legacy/fixtures/files/060719210727_changeset_iso8859-1.diff
deleted file mode 100644
index 9bade6ab99..0000000000
--- a/spec_legacy/fixtures/files/060719210727_changeset_iso8859-1.diff
+++ /dev/null
@@ -1,13 +0,0 @@
-Index: trunk/app/controllers/issues_controller.rb
-===================================================================
---- trunk/app/controllers/issues_controller.rb (rvision 1483)
-+++ trunk/app/controllers/issues_controller.rb (rvision 1484)
-@@ -149,7 +149,7 @@
- attach_files(@issue, params[:attachments])
- flash[:notice] = 'Demande cre avec succs'
- Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added')
-- redirect_to :controller => 'issues', :action => 'show', :id => @issue, :project_id => @project
-+ redirect_to :controller => 'issues', :action => 'show', :id => @issue
- return
- end
- end
diff --git a/spec_legacy/fixtures/files/060719210727_changeset_utf8.diff b/spec_legacy/fixtures/files/060719210727_changeset_utf8.diff
deleted file mode 100644
index 031336c8ab..0000000000
--- a/spec_legacy/fixtures/files/060719210727_changeset_utf8.diff
+++ /dev/null
@@ -1,13 +0,0 @@
-Index: trunk/app/controllers/issues_controller.rb
-===================================================================
---- trunk/app/controllers/issues_controller.rb (révision 1483)
-+++ trunk/app/controllers/issues_controller.rb (révision 1484)
-@@ -149,7 +149,7 @@
- attach_files(@issue, params[:attachments])
- flash[:notice] = 'Demande créée avec succès'
- Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added')
-- redirect_to :controller => 'issues', :action => 'show', :id => @issue, :project_id => @project
-+ redirect_to :controller => 'issues', :action => 'show', :id => @issue
- return
- end
- end
diff --git a/spec_legacy/fixtures/files/060719210727_source.rb b/spec_legacy/fixtures/files/060719210727_source.rb
deleted file mode 100644
index 9087a3b845..0000000000
--- a/spec_legacy/fixtures/files/060719210727_source.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-# The Greeter class
-class Greeter
- def initialize(name)
- @name = name.capitalize
- end
-
- def salute
- puts "Hello #{@name}!"
- end
-end
diff --git a/spec_legacy/fixtures/files/testfile.txt b/spec_legacy/fixtures/files/testfile.txt
deleted file mode 100644
index 66c507f9c9..0000000000
--- a/spec_legacy/fixtures/files/testfile.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-this is a text file for upload tests
-with multiple lines
diff --git a/spec_legacy/fixtures/files/textfile.txt b/spec_legacy/fixtures/files/textfile.txt
deleted file mode 100644
index 12e882a22d..0000000000
--- a/spec_legacy/fixtures/files/textfile.txt
+++ /dev/null
@@ -1 +0,0 @@
-some silly content
diff --git a/spec_legacy/fixtures/forums.yml b/spec_legacy/fixtures/forums.yml
deleted file mode 100644
index 21eaf31e8a..0000000000
--- a/spec_legacy/fixtures/forums.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-forums_001:
- name: Help
- project_id: 1
- topics_count: 2
- id: 1
- description: Help board
- position: 1
- last_message_id: 6
- messages_count: 6
-forums_002:
- name: Discussion
- project_id: 1
- topics_count: 0
- id: 2
- description: Discussion board
- position: 2
- last_message_id:
- messages_count: 0
-forums_003:
- name: Discussion
- project_id: 2
- topics_count: 0
- id: 3
- description: Discussion board
- position: 1
- last_message_id:
- messages_count: 0
diff --git a/spec_legacy/fixtures/group_users.yml b/spec_legacy/fixtures/group_users.yml
deleted file mode 100644
index 2d35784f1c..0000000000
--- a/spec_legacy/fixtures/group_users.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-group_users_001:
- group_id: 10
- user_id: 8
-group_users_002:
- group_id: 11
- user_id: 8
-
diff --git a/spec_legacy/fixtures/menu_items.yml b/spec_legacy/fixtures/menu_items.yml
deleted file mode 100644
index 42f965afe5..0000000000
--- a/spec_legacy/fixtures/menu_items.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-menu_items_001:
- id: 1
- name: wiki
- title: Wiki
- type: MenuItems::WikiMenuItem
- navigatable_id: 1
-menu_items_002:
- id: 2
- name: wiki
- title: Wiki
- type: MenuItems::WikiMenuItem
- navigatable_id: 2
-
diff --git a/spec_legacy/fixtures/messages.yml b/spec_legacy/fixtures/messages.yml
deleted file mode 100644
index b7e1d7ebb9..0000000000
--- a/spec_legacy/fixtures/messages.yml
+++ /dev/null
@@ -1,106 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-messages_001:
- created_at: 2007-05-12 17:15:32 +02:00
- updated_at: 2007-05-12 17:15:32 +02:00
- subject: First post
- id: 1
- replies_count: 2
- last_reply_id: 3
- content: "This is the very first post\n\nin the forum"
- author_id: 1
- parent_id:
- forum_id: 1
-messages_002:
- created_at: 2007-05-12 17:18:00 +02:00
- updated_at: 2007-05-12 17:18:00 +02:00
- subject: First reply
- id: 2
- replies_count: 0
- last_reply_id:
- content: "Reply to the first post"
- author_id: 1
- parent_id: 1
- forum_id: 1
-messages_003:
- created_at: 2007-05-12 17:18:02 +02:00
- updated_at: 2007-05-12 17:18:02 +02:00
- subject: "RE: First post"
- id: 3
- replies_count: 0
- last_reply_id:
- content: "An other reply"
- author_id: 2
- parent_id: 1
- forum_id: 1
-messages_004:
- created_at: 2007-08-12 17:15:32 +02:00
- updated_at: 2007-08-12 17:15:32 +02:00
- subject: Post 2
- id: 4
- replies_count: 2
- last_reply_id: 6
- content: "This is an other post"
- author_id: 1
- parent_id:
- forum_id: 1
-messages_005:
- created_at: <%= 3.days.ago %>
- updated_at: <%= 3.days.ago %>
- subject: 'RE: post 2'
- id: 5
- replies_count: 0
- last_reply_id:
- content: "Reply to the second post"
- author_id: 1
- parent_id: 4
- forum_id: 1
-messages_006:
- created_at: <%= 2.days.ago %>
- updated_at: <%= 2.days.ago %>
- subject: 'RE: post 2'
- id: 6
- replies_count: 0
- last_reply_id:
- content: "Another reply to the second post"
- author_id: 3
- parent_id: 4
- forum_id: 1
-messages_007:
- created_at: <%= 2.days.ago %>
- updated_at: <%= 2.days.ago %>
- subject: 'Message on a private project'
- id: 7
- replies_count: 0
- last_reply_id:
- content: "This is a private message"
- author_id: 1
- parent_id:
- forum_id: 3
diff --git a/spec_legacy/fixtures/news.yml b/spec_legacy/fixtures/news.yml
deleted file mode 100644
index c17961dd80..0000000000
--- a/spec_legacy/fixtures/news.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-news_001:
- created_at: 2006-07-19 22:40:26 +02:00
- updated_at: 2006-07-19 22:40:26 +02:00
- project_id: 1
- title: eCookbook first release !
- id: 1
- description: |-
- eCookbook 1.0 has been released.
-
- Visit http://ecookbook.somenet.foo/
- summary: First version was released...
- author_id: 2
- comments_count: 1
-news_002:
- created_at: 2006-07-19 22:42:58 +02:00
- updated_at: 2006-07-19 22:42:58 +02:00
- project_id: 1
- title: 100,000 downloads for eCookbook
- id: 2
- description: eCookbook 1.0 have downloaded 100,000 times
- summary: eCookbook 1.0 have downloaded 100,000 times
- author_id: 2
- comments_count: 0
-news_003:
- created_at: 2006-07-19 22:42:58 +02:00
- updated_at: 2006-07-19 22:42:58 +02:00
- project_id: 2
- title: News on a private project
- id: 3
- description: This is a private news
- summary:
- author_id: 2
- comments_count: 0
diff --git a/spec_legacy/fixtures/queries.yml b/spec_legacy/fixtures/queries.yml
deleted file mode 100644
index 8abf181191..0000000000
--- a/spec_legacy/fixtures/queries.yml
+++ /dev/null
@@ -1,193 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-queries_001:
- id: 1
- project_id: 1
- public: true
- include_subprojects: true
- name: Multiple custom fields query
- filters: |
- ---
- cf_1:
- :values:
- - "1"
- :operator: "="
- status_id:
- :values:
- - "1"
- :operator: o
- cf_2:
- :values:
- - "125"
- :operator: "="
-
- user_id: 1
- column_names:
-queries_002:
- id: 2
- project_id: 1
- public: false
- include_subprojects: true
- name: Private query for cookbook
- filters: |
- ---
- type_id:
- :values:
- - "3"
- :operator: "="
- status_id:
- :values:
- - "1"
- :operator: o
-
- user_id: 3
- column_names:
-queries_003:
- id: 3
- project_id:
- public: false
- include_subprojects: true
- name: Private query for all projects
- filters: |
- ---
- type_id:
- :values:
- - "3"
- :operator: "="
-
- user_id: 3
- column_names:
-queries_004:
- id: 4
- project_id:
- public: true
- include_subprojects: true
- name: Public query for all projects
- filters: |
- ---
- type_id:
- :values:
- - "3"
- :operator: "="
-
- user_id: 2
- column_names:
-queries_005:
- id: 5
- project_id:
- public: true
- include_subprojects: true
- name: Open issues by priority and type
- filters: |
- ---
- status_id:
- :values:
- - "1"
- :operator: o
-
- user_id: 1
- column_names:
- sort_criteria: |
- ---
- - - priority
- - desc
- - - type
- - asc
-queries_006:
- id: 6
- project_id:
- public: true
- include_subprojects: true
- name: Open issues grouped by type
- filters: |
- ---
- status_id:
- :values:
- - "1"
- :operator: o
-
- user_id: 1
- column_names:
- group_by: type
- sort_criteria: |
- ---
- - - priority
- - desc
-queries_007:
- id: 7
- project_id: 2
- public: true
- include_subprojects: true
- name: Public query for project 2
- filters: |
- ---
- type_id:
- :values:
- - "3"
- :operator: "="
-
- user_id: 2
- column_names:
-queries_008:
- id: 8
- project_id: 2
- public: false
- include_subprojects: true
- name: Private query for project 2
- filters: |
- ---
- type_id:
- :values:
- - "3"
- :operator: "="
-
- user_id: 2
- column_names:
-queries_009:
- id: 9
- project_id:
- public: true
- include_subprojects: true
- name: Open issues grouped by list custom field
- filters: |
- ---
- status_id:
- :values:
- - "1"
- :operator: o
-
- user_id: 1
- column_names:
- group_by: cf_1
- sort_criteria: |
- ---
- - - priority
- - desc
-
diff --git a/spec_legacy/fixtures/repositories.yml b/spec_legacy/fixtures/repositories.yml
deleted file mode 100644
index 9f0a803754..0000000000
--- a/spec_legacy/fixtures/repositories.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-repositories_001:
- project_id: 1
- url: file:///<%= Rails.root.to_s.gsub(%r{config\/\.\.}, '') %>/tmp/test/subversion_repository
- id: 10
- root_url: file:///<%= Rails.root.to_s.gsub(%r{config\/\.\.}, '') %>/tmp/test/subversion_repository
- password: ""
- login: ""
- type: Repository::Subversion
- scm_type: existing
-repositories_002:
- project_id: 2
- url: svn://localhost/test
- id: 11
- root_url: svn://localhost
- password: ""
- login: ""
- type: Repository::Subversion
- scm_type: existing
diff --git a/spec_legacy/fixtures/time_entries.yml b/spec_legacy/fixtures/time_entries.yml
deleted file mode 100644
index 6ddc4379a2..0000000000
--- a/spec_legacy/fixtures/time_entries.yml
+++ /dev/null
@@ -1,90 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-time_entries_001:
- created_at: 2007-03-23 12:54:18 +01:00
- tweek: 12
- tmonth: 3
- project_id: 1
- comments: My hours
- updated_at: 2007-03-23 12:54:18 +01:00
- activity_id: 9
- spent_on: 2007-03-23
- work_package_id: 1
- id: 1
- hours: 4.25
- user_id: 2
- logged_by_id: 2
- tyear: 2007
-time_entries_002:
- created_at: 2007-03-23 14:11:04 +01:00
- tweek: 11
- tmonth: 3
- project_id: 1
- comments: ""
- updated_at: 2007-03-23 14:11:04 +01:00
- activity_id: 9
- spent_on: 2007-03-12
- work_package_id: 1
- id: 2
- hours: 150.0
- user_id: 1
- logged_by_id: 1
- tyear: 2007
-time_entries_003:
- created_at: 2007-04-21 12:20:48 +02:00
- tweek: 16
- tmonth: 4
- project_id: 1
- comments: ""
- updated_at: 2007-04-21 12:20:48 +02:00
- activity_id: 9
- spent_on: 2007-04-21
- work_package_id: 3
- id: 3
- hours: 1.0
- user_id: 1
- logged_by_id: 1
- tyear: 2007
-time_entries_004:
- created_at: 2007-04-22 12:20:48 +02:00
- tweek: 16
- tmonth: 4
- project_id: 3
- comments: Time spent on a subproject
- updated_at: 2007-04-22 12:20:48 +02:00
- activity_id: 10
- spent_on: 2007-04-22
- work_package_id:
- id: 4
- hours: 7.65
- user_id: 1
- logged_by_id: 1
- tyear: 2007
-
diff --git a/spec_legacy/fixtures/versions.yml b/spec_legacy/fixtures/versions.yml
deleted file mode 100644
index 69b5e30860..0000000000
--- a/spec_legacy/fixtures/versions.yml
+++ /dev/null
@@ -1,99 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-versions_001:
- created_at: 2006-07-19 21:00:07 +02:00
- name: "0.1"
- project_id: 1
- updated_at: 2006-07-19 21:00:07 +02:00
- id: 1
- description: Beta
- effective_date: 2006-07-01
- status: closed
- sharing: 'none'
-versions_002:
- created_at: 2006-07-19 21:00:33 +02:00
- name: "1.0"
- project_id: 1
- updated_at: 2006-07-19 21:00:33 +02:00
- id: 2
- description: Stable release
- effective_date: <%= 20.day.from_now.to_date.to_fs(:db) %>
- status: locked
- sharing: 'none'
-versions_003:
- created_at: 2006-07-19 21:00:33 +02:00
- name: "2.0"
- project_id: 1
- updated_at: 2006-07-19 21:00:33 +02:00
- id: 3
- description: Future version
- effective_date:
- status: open
- sharing: 'none'
-versions_004:
- created_at: 2006-07-19 21:00:33 +02:00
- name: "2.0"
- project_id: 3
- updated_at: 2006-07-19 21:00:33 +02:00
- id: 4
- description: Future version on subproject
- effective_date:
- status: open
- sharing: 'tree'
-versions_005:
- created_at: 2006-07-19 21:00:07 +02:00
- name: "Alpha"
- project_id: 2
- updated_at: 2006-07-19 21:00:07 +02:00
- id: 5
- description: Private Alpha
- effective_date: 2006-07-01
- status: open
- sharing: 'none'
-versions_006:
- created_at: 2006-07-19 21:00:07 +02:00
- name: "Private Version of public subproject"
- project_id: 5
- updated_at: 2006-07-19 21:00:07 +02:00
- id: 6
- description: "Should be done any day now..."
- effective_date:
- status: open
- sharing: 'tree'
-versions_007:
- created_at: 2006-07-19 21:00:07 +02:00
- name: "Systemwide visible version"
- project_id: 2
- updated_at: 2006-07-19 21:00:07 +02:00
- id: 7
- description:
- effective_date:
- status: open
- sharing: 'system'
diff --git a/spec_legacy/fixtures/watchers.yml b/spec_legacy/fixtures/watchers.yml
deleted file mode 100644
index 97ecfb50a3..0000000000
--- a/spec_legacy/fixtures/watchers.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-watchers_001:
- watchable_type: WorkPackage
- watchable_id: 2
- user_id: 3
-watchers_002:
- watchable_type: Message
- watchable_id: 1
- user_id: 1
-watchers_003:
- watchable_type: WorkPackage
- watchable_id: 2
- user_id: 1
-
diff --git a/spec_legacy/fixtures/wiki_contents.yml b/spec_legacy/fixtures/wiki_contents.yml
deleted file mode 100644
index 7ed34b4628..0000000000
--- a/spec_legacy/fixtures/wiki_contents.yml
+++ /dev/null
@@ -1,122 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-wiki_contents_001:
- text: |-
- h1. CookBook documentation
-
- Some updated [[documentation]] here with gzipped history
- updated_at: 2007-03-07 00:10:51 +01:00
- page_id: 1
- id: 1
- lock_version: 3
- author_id: 1
-wiki_contents_002:
- text: |-
- h1. Another page
-
- This is a link to a ticket: #2
- And this is an included page:
- {{include(Page with an inline image)}}
- updated_at: 2007-03-08 00:18:07 +01:00
- page_id: 2
- id: 2
- lock_version: 1
- author_id: 1
-wiki_contents_003:
- text: |-
- h1. Start page
-
- E-commerce web site start page
- updated_at: 2007-03-08 00:18:07 +01:00
- page_id: 3
- id: 3
- lock_version: 1
- author_id: 1
-wiki_contents_004:
- text: |-
- h1. Page with an inline image
-
- This is an inline image:
-
- !logo.gif!
- updated_at: 2007-03-08 00:18:07 +01:00
- page_id: 4
- id: 4
- lock_version: 1
- author_id: 1
-wiki_contents_005:
- text: |-
- h1. Child page 1
-
- This is a child page
- updated_at: 2007-03-08 00:18:07 +01:00
- page_id: 5
- id: 5
- lock_version: 1
- author_id: 1
-wiki_contents_006:
- text: |-
- h1. Child page 2
-
- This is a child page
- updated_at: 2007-03-08 00:18:07 +01:00
- page_id: 6
- id: 6
- lock_version: 1
- author_id: 1
-wiki_contents_007:
- text: This is a child page
- updated_at: 2007-03-08 00:18:07 +01:00
- page_id: 7
- id: 7
- lock_version: 1
- author_id: 1
-wiki_contents_008:
- text: This is a parent page
- updated_at: 2007-03-08 00:18:07 +01:00
- page_id: 8
- id: 8
- lock_version: 1
- author_id: 1
-wiki_contents_009:
- text: This is a child page
- updated_at: 2007-03-08 00:18:07 +01:00
- page_id: 9
- id: 9
- lock_version: 1
- author_id: 1
-wiki_contents_010:
- text: Page with cyrillic title
- updated_at: 2007-03-08 00:18:07 +01:00
- page_id: 10
- id: 10
- lock_version: 1
- author_id: 1
-
diff --git a/spec_legacy/fixtures/wiki_pages.yml b/spec_legacy/fixtures/wiki_pages.yml
deleted file mode 100644
index bbc0806e15..0000000000
--- a/spec_legacy/fixtures/wiki_pages.yml
+++ /dev/null
@@ -1,109 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-wiki_pages_001:
- created_at: 2007-03-07 00:08:07 +01:00
- title: CookBook documentation
- slug: cookbook-documentation
- id: 1
- wiki_id: 1
- protected: true
- parent_id:
-wiki_pages_002:
- created_at: 2007-03-08 00:18:07 +01:00
- title: Another page
- slug: another-page
- id: 2
- wiki_id: 1
- protected: false
- parent_id:
-wiki_pages_003:
- created_at: 2007-03-08 00:18:07 +01:00
- title: Start page
- slug: start-page
- id: 3
- wiki_id: 2
- protected: false
- parent_id:
-wiki_pages_004:
- created_at: 2007-03-08 00:18:07 +01:00
- title: Page with an inline image
- slug: page-with-an-inline-image
- id: 4
- wiki_id: 1
- protected: false
- parent_id: 1
-wiki_pages_005:
- created_at: 2007-03-08 00:18:07 +01:00
- title: Child 1
- slug: child-1
- id: 5
- wiki_id: 1
- protected: false
- parent_id: 2
-wiki_pages_006:
- created_at: 2007-03-08 00:18:07 +01:00
- title: Child 2
- slug: child-2
- id: 6
- wiki_id: 1
- protected: false
- parent_id: 2
-wiki_pages_007:
- created_at: 2007-03-08 00:18:07 +01:00
- title: Child page 1
- slug: child-page-1
- id: 7
- wiki_id: 2
- protected: false
- parent_id: 8
-wiki_pages_008:
- created_at: 2007-03-08 00:18:07 +01:00
- title: Parent page
- slug: parent-page
- id: 8
- wiki_id: 2
- protected: false
- parent_id:
-wiki_pages_009:
- created_at: 2007-03-08 00:18:07 +01:00
- title: Child page 2
- slug: child-page-2
- id: 9
- wiki_id: 2
- protected: false
- parent_id: 8
-wiki_pages_010:
- created_at: 2007-03-08 00:18:07 +01:00
- title: Этика менеджмента
- slug: etika-mieniedzhmienta
- id: 10
- wiki_id: 1
- protected: false
- parent_id:
diff --git a/spec_legacy/fixtures/wikis.yml b/spec_legacy/fixtures/wikis.yml
deleted file mode 100644
index 216ef63afc..0000000000
--- a/spec_legacy/fixtures/wikis.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-wiki_menu_item_001:
- status: 1
- start_page: CookBook documentation
- project_id: 1
- id: 1
-wiki_menu_item_002:
- status: 1
- start_page: Start page
- project_id: 2
- id: 2
-
diff --git a/spec_legacy/fixtures/work_packages.yml b/spec_legacy/fixtures/work_packages.yml
deleted file mode 100644
index 8e9ea1865d..0000000000
--- a/spec_legacy/fixtures/work_packages.yml
+++ /dev/null
@@ -1,234 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-issues_001:
- created_at: <%= 3.days.ago %>
- project_id: 1
- updated_at: <%= 1.day.ago %>
- priority_id: 4
- subject: Can't print recipes
- id: 1
- version_id:
- category_id: 1
- description: Unable to print recipes
- type_id: 1
- assigned_to_id:
- author_id: 2
- status_id: 1
- start_date: <%= 1.day.ago.to_date.to_fs(:db) %>
- due_date: <%= 10.day.from_now.to_date.to_fs(:db) %>
- lock_version: 3
-issues_002:
- created_at: 2006-07-19 21:04:21 +02:00
- project_id: 1
- updated_at: 2006-07-19 21:09:50 +02:00
- priority_id: 5
- subject: Add ingredients categories
- id: 2
- version_id: 2
- category_id:
- description: Ingredients of the recipe should be classified by categories
- type_id: 2
- assigned_to_id: 3
- author_id: 2
- status_id: 2
- start_date: <%= 2.day.ago.to_date.to_fs(:db) %>
- due_date:
- lock_version: 3
- done_ratio: 30
-issues_003:
- created_at: 2006-07-19 21:07:27 +02:00
- project_id: 1
- updated_at: 2006-07-19 21:07:27 +02:00
- priority_id: 4
- subject: Error 281 when updating a recipe
- id: 3
- version_id:
- category_id:
- description: Error 281 is encountered when saving a recipe
- type_id: 1
- assigned_to_id: 3
- author_id: 2
- status_id: 1
- start_date: <%= 15.day.ago.to_date.to_fs(:db) %>
- due_date: <%= 5.day.ago.to_date.to_fs(:db) %>
-issues_004:
- created_at: <%= 5.days.ago %>
- project_id: 2
- updated_at: <%= 2.days.ago %>
- priority_id: 4
- subject: Issue on project 2
- id: 4
- version_id:
- category_id:
- description: Issue on project 2
- type_id: 1
- assigned_to_id: 2
- author_id: 2
- status_id: 1
-issues_005:
- created_at: <%= 5.days.ago %>
- project_id: 3
- updated_at: <%= 2.days.ago %>
- priority_id: 4
- subject: Subproject issue
- id: 5
- version_id:
- category_id:
- description: This is an issue on a cookbook subproject
- type_id: 1
- assigned_to_id:
- author_id: 2
- status_id: 1
-issues_006:
- created_at: <%= 1.minute.ago %>
- project_id: 5
- updated_at: <%= 1.minute.ago %>
- priority_id: 4
- subject: Issue of a private subproject
- id: 6
- version_id:
- category_id:
- description: This is an issue of a private subproject of cookbook
- type_id: 1
- assigned_to_id:
- author_id: 2
- status_id: 1
- start_date: <%= Date.today.to_fs(:db) %>
- due_date: <%= 1.days.from_now.to_date.to_fs(:db) %>
-issues_007:
- created_at: <%= 10.days.ago %>
- project_id: 1
- updated_at: <%= 10.days.ago %>
- priority_id: 5
- subject: Issue due today
- id: 7
- version_id:
- category_id:
- description: This is an issue that is due today
- type_id: 1
- assigned_to_id:
- author_id: 2
- status_id: 1
- start_date: <%= 10.days.ago.to_fs(:db) %>
- due_date: <%= Date.today.to_fs(:db) %>
-issues_008:
- created_at: <%= 10.days.ago %>
- project_id: 1
- updated_at: <%= 10.days.ago %>
- priority_id: 5
- subject: Closed issue
- id: 8
- version_id:
- category_id:
- description: This is a closed issue.
- type_id: 1
- assigned_to_id:
- author_id: 2
- status_id: 5
- start_date:
- due_date:
-issues_009:
- created_at: <%= 1.minute.ago %>
- project_id: 5
- updated_at: <%= 1.minute.ago %>
- priority_id: 5
- subject: Blocked Issue
- id: 9
- version_id:
- category_id:
- description: This is an issue that is blocked by issue #10
- type_id: 1
- assigned_to_id:
- author_id: 2
- status_id: 1
- start_date: <%= Date.today.to_fs(:db) %>
- due_date: <%= 1.days.from_now.to_date.to_fs(:db) %>
-issues_010:
- created_at: <%= 1.minute.ago %>
- project_id: 5
- updated_at: <%= 1.minute.ago %>
- priority_id: 5
- subject: Issue Doing the Blocking
- id: 10
- version_id:
- category_id:
- description: This is an issue that blocks issue #9
- type_id: 1
- assigned_to_id:
- author_id: 2
- status_id: 1
- start_date: <%= Date.today.to_fs(:db) %>
- due_date: <%= 1.days.from_now.to_date.to_fs(:db) %>
-issues_011:
- created_at: <%= 3.days.ago %>
- project_id: 1
- updated_at: <%= 1.day.ago %>
- priority_id: 5
- subject: Closed issue on a closed version
- id: 11
- version_id: 1
- category_id: 1
- description:
- type_id: 1
- assigned_to_id:
- author_id: 2
- status_id: 5
- start_date: <%= 1.day.ago.to_date.to_fs(:db) %>
- due_date:
-issues_012:
- created_at: <%= 3.days.ago %>
- project_id: 1
- updated_at: <%= 1.day.ago %>
- priority_id: 5
- subject: Closed issue on a locked version
- id: 12
- version_id: 2
- category_id: 1
- description:
- type_id: 1
- assigned_to_id:
- author_id: 3
- status_id: 5
- start_date: <%= 1.day.ago.to_date.to_fs(:db) %>
- due_date:
-issues_013:
- created_at: <%= 5.days.ago %>
- project_id: 3
- updated_at: <%= 2.days.ago %>
- priority_id: 4
- subject: Subproject issue two
- id: 13
- version_id:
- category_id:
- description: This is a second issue on a cookbook subproject
- type_id: 1
- assigned_to_id:
- author_id: 2
- status_id: 1
diff --git a/spec_legacy/fixtures/workflows.yml b/spec_legacy/fixtures/workflows.yml
deleted file mode 100644
index b94712651c..0000000000
--- a/spec_legacy/fixtures/workflows.yml
+++ /dev/null
@@ -1,1643 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
----
-workflows_189:
- new_status_id: 5
- role_id: 1
- old_status_id: 2
- id: 189
- type_id: 3
-workflows_001:
- new_status_id: 2
- role_id: 1
- old_status_id: 1
- id: 1
- type_id: 1
-workflows_002:
- new_status_id: 3
- role_id: 1
- old_status_id: 1
- id: 2
- type_id: 1
-workflows_003:
- new_status_id: 4
- role_id: 1
- old_status_id: 1
- id: 3
- type_id: 1
-workflows_110:
- new_status_id: 6
- role_id: 1
- old_status_id: 4
- id: 110
- type_id: 2
-workflows_004:
- new_status_id: 5
- role_id: 1
- old_status_id: 1
- id: 4
- type_id: 1
-workflows_030:
- new_status_id: 5
- role_id: 1
- old_status_id: 6
- id: 30
- type_id: 1
-workflows_111:
- new_status_id: 1
- role_id: 1
- old_status_id: 5
- id: 111
- type_id: 2
-workflows_005:
- new_status_id: 6
- role_id: 1
- old_status_id: 1
- id: 5
- type_id: 1
-workflows_031:
- new_status_id: 2
- role_id: 2
- old_status_id: 1
- id: 31
- type_id: 1
-workflows_112:
- new_status_id: 2
- role_id: 1
- old_status_id: 5
- id: 112
- type_id: 2
-workflows_006:
- new_status_id: 1
- role_id: 1
- old_status_id: 2
- id: 6
- type_id: 1
-workflows_032:
- new_status_id: 3
- role_id: 2
- old_status_id: 1
- id: 32
- type_id: 1
-workflows_113:
- new_status_id: 3
- role_id: 1
- old_status_id: 5
- id: 113
- type_id: 2
-workflows_220:
- new_status_id: 6
- role_id: 2
- old_status_id: 2
- id: 220
- type_id: 3
-workflows_007:
- new_status_id: 3
- role_id: 1
- old_status_id: 2
- id: 7
- type_id: 1
-workflows_033:
- new_status_id: 4
- role_id: 2
- old_status_id: 1
- id: 33
- type_id: 1
-workflows_060:
- new_status_id: 5
- role_id: 2
- old_status_id: 6
- id: 60
- type_id: 1
-workflows_114:
- new_status_id: 4
- role_id: 1
- old_status_id: 5
- id: 114
- type_id: 2
-workflows_140:
- new_status_id: 6
- role_id: 2
- old_status_id: 4
- id: 140
- type_id: 2
-workflows_221:
- new_status_id: 1
- role_id: 2
- old_status_id: 3
- id: 221
- type_id: 3
-workflows_008:
- new_status_id: 4
- role_id: 1
- old_status_id: 2
- id: 8
- type_id: 1
-workflows_034:
- new_status_id: 5
- role_id: 2
- old_status_id: 1
- id: 34
- type_id: 1
-workflows_115:
- new_status_id: 6
- role_id: 1
- old_status_id: 5
- id: 115
- type_id: 2
-workflows_141:
- new_status_id: 1
- role_id: 2
- old_status_id: 5
- id: 141
- type_id: 2
-workflows_222:
- new_status_id: 2
- role_id: 2
- old_status_id: 3
- id: 222
- type_id: 3
-workflows_223:
- new_status_id: 4
- role_id: 2
- old_status_id: 3
- id: 223
- type_id: 3
-workflows_009:
- new_status_id: 5
- role_id: 1
- old_status_id: 2
- id: 9
- type_id: 1
-workflows_035:
- new_status_id: 6
- role_id: 2
- old_status_id: 1
- id: 35
- type_id: 1
-workflows_061:
- new_status_id: 2
- role_id: 3
- old_status_id: 1
- id: 61
- type_id: 1
-workflows_116:
- new_status_id: 1
- role_id: 1
- old_status_id: 6
- id: 116
- type_id: 2
-workflows_142:
- new_status_id: 2
- role_id: 2
- old_status_id: 5
- id: 142
- type_id: 2
-workflows_250:
- new_status_id: 6
- role_id: 3
- old_status_id: 2
- id: 250
- type_id: 3
-workflows_224:
- new_status_id: 5
- role_id: 2
- old_status_id: 3
- id: 224
- type_id: 3
-workflows_036:
- new_status_id: 1
- role_id: 2
- old_status_id: 2
- id: 36
- type_id: 1
-workflows_062:
- new_status_id: 3
- role_id: 3
- old_status_id: 1
- id: 62
- type_id: 1
-workflows_117:
- new_status_id: 2
- role_id: 1
- old_status_id: 6
- id: 117
- type_id: 2
-workflows_143:
- new_status_id: 3
- role_id: 2
- old_status_id: 5
- id: 143
- type_id: 2
-workflows_170:
- new_status_id: 6
- role_id: 3
- old_status_id: 4
- id: 170
- type_id: 2
-workflows_251:
- new_status_id: 1
- role_id: 3
- old_status_id: 3
- id: 251
- type_id: 3
-workflows_225:
- new_status_id: 6
- role_id: 2
- old_status_id: 3
- id: 225
- type_id: 3
-workflows_063:
- new_status_id: 4
- role_id: 3
- old_status_id: 1
- id: 63
- type_id: 1
-workflows_090:
- new_status_id: 5
- role_id: 3
- old_status_id: 6
- id: 90
- type_id: 1
-workflows_118:
- new_status_id: 3
- role_id: 1
- old_status_id: 6
- id: 118
- type_id: 2
-workflows_144:
- new_status_id: 4
- role_id: 2
- old_status_id: 5
- id: 144
- type_id: 2
-workflows_252:
- new_status_id: 2
- role_id: 3
- old_status_id: 3
- id: 252
- type_id: 3
-workflows_226:
- new_status_id: 1
- role_id: 2
- old_status_id: 4
- id: 226
- type_id: 3
-workflows_038:
- new_status_id: 4
- role_id: 2
- old_status_id: 2
- id: 38
- type_id: 1
-workflows_064:
- new_status_id: 5
- role_id: 3
- old_status_id: 1
- id: 64
- type_id: 1
-workflows_091:
- new_status_id: 2
- role_id: 1
- old_status_id: 1
- id: 91
- type_id: 2
-workflows_119:
- new_status_id: 4
- role_id: 1
- old_status_id: 6
- id: 119
- type_id: 2
-workflows_145:
- new_status_id: 6
- role_id: 2
- old_status_id: 5
- id: 145
- type_id: 2
-workflows_171:
- new_status_id: 1
- role_id: 3
- old_status_id: 5
- id: 171
- type_id: 2
-workflows_253:
- new_status_id: 4
- role_id: 3
- old_status_id: 3
- id: 253
- type_id: 3
-workflows_227:
- new_status_id: 2
- role_id: 2
- old_status_id: 4
- id: 227
- type_id: 3
-workflows_039:
- new_status_id: 5
- role_id: 2
- old_status_id: 2
- id: 39
- type_id: 1
-workflows_065:
- new_status_id: 6
- role_id: 3
- old_status_id: 1
- id: 65
- type_id: 1
-workflows_092:
- new_status_id: 3
- role_id: 1
- old_status_id: 1
- id: 92
- type_id: 2
-workflows_146:
- new_status_id: 1
- role_id: 2
- old_status_id: 6
- id: 146
- type_id: 2
-workflows_172:
- new_status_id: 2
- role_id: 3
- old_status_id: 5
- id: 172
- type_id: 2
-workflows_254:
- new_status_id: 5
- role_id: 3
- old_status_id: 3
- id: 254
- type_id: 3
-workflows_228:
- new_status_id: 3
- role_id: 2
- old_status_id: 4
- id: 228
- type_id: 3
-workflows_066:
- new_status_id: 1
- role_id: 3
- old_status_id: 2
- id: 66
- type_id: 1
-workflows_093:
- new_status_id: 4
- role_id: 1
- old_status_id: 1
- id: 93
- type_id: 2
-workflows_147:
- new_status_id: 2
- role_id: 2
- old_status_id: 6
- id: 147
- type_id: 2
-workflows_173:
- new_status_id: 3
- role_id: 3
- old_status_id: 5
- id: 173
- type_id: 2
-workflows_255:
- new_status_id: 6
- role_id: 3
- old_status_id: 3
- id: 255
- type_id: 3
-workflows_229:
- new_status_id: 5
- role_id: 2
- old_status_id: 4
- id: 229
- type_id: 3
-workflows_067:
- new_status_id: 3
- role_id: 3
- old_status_id: 2
- id: 67
- type_id: 1
-workflows_148:
- new_status_id: 3
- role_id: 2
- old_status_id: 6
- id: 148
- type_id: 2
-workflows_174:
- new_status_id: 4
- role_id: 3
- old_status_id: 5
- id: 174
- type_id: 2
-workflows_256:
- new_status_id: 1
- role_id: 3
- old_status_id: 4
- id: 256
- type_id: 3
-workflows_068:
- new_status_id: 4
- role_id: 3
- old_status_id: 2
- id: 68
- type_id: 1
-workflows_094:
- new_status_id: 5
- role_id: 1
- old_status_id: 1
- id: 94
- type_id: 2
-workflows_149:
- new_status_id: 4
- role_id: 2
- old_status_id: 6
- id: 149
- type_id: 2
-workflows_175:
- new_status_id: 6
- role_id: 3
- old_status_id: 5
- id: 175
- type_id: 2
-workflows_257:
- new_status_id: 2
- role_id: 3
- old_status_id: 4
- id: 257
- type_id: 3
-workflows_069:
- new_status_id: 5
- role_id: 3
- old_status_id: 2
- id: 69
- type_id: 1
-workflows_095:
- new_status_id: 6
- role_id: 1
- old_status_id: 1
- id: 95
- type_id: 2
-workflows_176:
- new_status_id: 1
- role_id: 3
- old_status_id: 6
- id: 176
- type_id: 2
-workflows_258:
- new_status_id: 3
- role_id: 3
- old_status_id: 4
- id: 258
- type_id: 3
-workflows_096:
- new_status_id: 1
- role_id: 1
- old_status_id: 2
- id: 96
- type_id: 2
-workflows_177:
- new_status_id: 2
- role_id: 3
- old_status_id: 6
- id: 177
- type_id: 2
-workflows_259:
- new_status_id: 5
- role_id: 3
- old_status_id: 4
- id: 259
- type_id: 3
-workflows_097:
- new_status_id: 3
- role_id: 1
- old_status_id: 2
- id: 97
- type_id: 2
-workflows_178:
- new_status_id: 3
- role_id: 3
- old_status_id: 6
- id: 178
- type_id: 2
-workflows_098:
- new_status_id: 4
- role_id: 1
- old_status_id: 2
- id: 98
- type_id: 2
-workflows_179:
- new_status_id: 4
- role_id: 3
- old_status_id: 6
- id: 179
- type_id: 2
-workflows_099:
- new_status_id: 5
- role_id: 1
- old_status_id: 2
- id: 99
- type_id: 2
-workflows_100:
- new_status_id: 6
- role_id: 1
- old_status_id: 2
- id: 100
- type_id: 2
-workflows_020:
- new_status_id: 6
- role_id: 1
- old_status_id: 4
- id: 20
- type_id: 1
-workflows_101:
- new_status_id: 1
- role_id: 1
- old_status_id: 3
- id: 101
- type_id: 2
-workflows_021:
- new_status_id: 1
- role_id: 1
- old_status_id: 5
- id: 21
- type_id: 1
-workflows_102:
- new_status_id: 2
- role_id: 1
- old_status_id: 3
- id: 102
- type_id: 2
-workflows_210:
- new_status_id: 5
- role_id: 1
- old_status_id: 6
- id: 210
- type_id: 3
-workflows_022:
- new_status_id: 2
- role_id: 1
- old_status_id: 5
- id: 22
- type_id: 1
-workflows_103:
- new_status_id: 4
- role_id: 1
- old_status_id: 3
- id: 103
- type_id: 2
-workflows_023:
- new_status_id: 3
- role_id: 1
- old_status_id: 5
- id: 23
- type_id: 1
-workflows_104:
- new_status_id: 5
- role_id: 1
- old_status_id: 3
- id: 104
- type_id: 2
-workflows_130:
- new_status_id: 6
- role_id: 2
- old_status_id: 2
- id: 130
- type_id: 2
-workflows_211:
- new_status_id: 2
- role_id: 2
- old_status_id: 1
- id: 211
- type_id: 3
-workflows_024:
- new_status_id: 4
- role_id: 1
- old_status_id: 5
- id: 24
- type_id: 1
-workflows_050:
- new_status_id: 6
- role_id: 2
- old_status_id: 4
- id: 50
- type_id: 1
-workflows_105:
- new_status_id: 6
- role_id: 1
- old_status_id: 3
- id: 105
- type_id: 2
-workflows_131:
- new_status_id: 1
- role_id: 2
- old_status_id: 3
- id: 131
- type_id: 2
-workflows_212:
- new_status_id: 3
- role_id: 2
- old_status_id: 1
- id: 212
- type_id: 3
-workflows_025:
- new_status_id: 6
- role_id: 1
- old_status_id: 5
- id: 25
- type_id: 1
-workflows_051:
- new_status_id: 1
- role_id: 2
- old_status_id: 5
- id: 51
- type_id: 1
-workflows_106:
- new_status_id: 1
- role_id: 1
- old_status_id: 4
- id: 106
- type_id: 2
-workflows_132:
- new_status_id: 2
- role_id: 2
- old_status_id: 3
- id: 132
- type_id: 2
-workflows_213:
- new_status_id: 4
- role_id: 2
- old_status_id: 1
- id: 213
- type_id: 3
-workflows_240:
- new_status_id: 5
- role_id: 2
- old_status_id: 6
- id: 240
- type_id: 3
-workflows_026:
- new_status_id: 1
- role_id: 1
- old_status_id: 6
- id: 26
- type_id: 1
-workflows_052:
- new_status_id: 2
- role_id: 2
- old_status_id: 5
- id: 52
- type_id: 1
-workflows_107:
- new_status_id: 2
- role_id: 1
- old_status_id: 4
- id: 107
- type_id: 2
-workflows_133:
- new_status_id: 4
- role_id: 2
- old_status_id: 3
- id: 133
- type_id: 2
-workflows_214:
- new_status_id: 5
- role_id: 2
- old_status_id: 1
- id: 214
- type_id: 3
-workflows_241:
- new_status_id: 2
- role_id: 3
- old_status_id: 1
- id: 241
- type_id: 3
-workflows_027:
- new_status_id: 2
- role_id: 1
- old_status_id: 6
- id: 27
- type_id: 1
-workflows_053:
- new_status_id: 3
- role_id: 2
- old_status_id: 5
- id: 53
- type_id: 1
-workflows_080:
- new_status_id: 6
- role_id: 3
- old_status_id: 4
- id: 80
- type_id: 1
-workflows_108:
- new_status_id: 3
- role_id: 1
- old_status_id: 4
- id: 108
- type_id: 2
-workflows_134:
- new_status_id: 5
- role_id: 2
- old_status_id: 3
- id: 134
- type_id: 2
-workflows_160:
- new_status_id: 6
- role_id: 3
- old_status_id: 2
- id: 160
- type_id: 2
-workflows_215:
- new_status_id: 6
- role_id: 2
- old_status_id: 1
- id: 215
- type_id: 3
-workflows_242:
- new_status_id: 3
- role_id: 3
- old_status_id: 1
- id: 242
- type_id: 3
-workflows_028:
- new_status_id: 3
- role_id: 1
- old_status_id: 6
- id: 28
- type_id: 1
-workflows_054:
- new_status_id: 4
- role_id: 2
- old_status_id: 5
- id: 54
- type_id: 1
-workflows_081:
- new_status_id: 1
- role_id: 3
- old_status_id: 5
- id: 81
- type_id: 1
-workflows_109:
- new_status_id: 5
- role_id: 1
- old_status_id: 4
- id: 109
- type_id: 2
-workflows_135:
- new_status_id: 6
- role_id: 2
- old_status_id: 3
- id: 135
- type_id: 2
-workflows_161:
- new_status_id: 1
- role_id: 3
- old_status_id: 3
- id: 161
- type_id: 2
-workflows_216:
- new_status_id: 1
- role_id: 2
- old_status_id: 2
- id: 216
- type_id: 3
-workflows_243:
- new_status_id: 4
- role_id: 3
- old_status_id: 1
- id: 243
- type_id: 3
-workflows_029:
- new_status_id: 4
- role_id: 1
- old_status_id: 6
- id: 29
- type_id: 1
-workflows_055:
- new_status_id: 6
- role_id: 2
- old_status_id: 5
- id: 55
- type_id: 1
-workflows_082:
- new_status_id: 2
- role_id: 3
- old_status_id: 5
- id: 82
- type_id: 1
-workflows_136:
- new_status_id: 1
- role_id: 2
- old_status_id: 4
- id: 136
- type_id: 2
-workflows_162:
- new_status_id: 2
- role_id: 3
- old_status_id: 3
- id: 162
- type_id: 2
-workflows_217:
- new_status_id: 3
- role_id: 2
- old_status_id: 2
- id: 217
- type_id: 3
-workflows_270:
- new_status_id: 5
- role_id: 3
- old_status_id: 6
- id: 270
- type_id: 3
-workflows_244:
- new_status_id: 5
- role_id: 3
- old_status_id: 1
- id: 244
- type_id: 3
-workflows_056:
- new_status_id: 1
- role_id: 2
- old_status_id: 6
- id: 56
- type_id: 1
-workflows_137:
- new_status_id: 2
- role_id: 2
- old_status_id: 4
- id: 137
- type_id: 2
-workflows_163:
- new_status_id: 4
- role_id: 3
- old_status_id: 3
- id: 163
- type_id: 2
-workflows_190:
- new_status_id: 6
- role_id: 1
- old_status_id: 2
- id: 190
- type_id: 3
-workflows_218:
- new_status_id: 4
- role_id: 2
- old_status_id: 2
- id: 218
- type_id: 3
-workflows_245:
- new_status_id: 6
- role_id: 3
- old_status_id: 1
- id: 245
- type_id: 3
-workflows_057:
- new_status_id: 2
- role_id: 2
- old_status_id: 6
- id: 57
- type_id: 1
-workflows_083:
- new_status_id: 3
- role_id: 3
- old_status_id: 5
- id: 83
- type_id: 1
-workflows_138:
- new_status_id: 3
- role_id: 2
- old_status_id: 4
- id: 138
- type_id: 2
-workflows_164:
- new_status_id: 5
- role_id: 3
- old_status_id: 3
- id: 164
- type_id: 2
-workflows_191:
- new_status_id: 1
- role_id: 1
- old_status_id: 3
- id: 191
- type_id: 3
-workflows_219:
- new_status_id: 5
- role_id: 2
- old_status_id: 2
- id: 219
- type_id: 3
-workflows_246:
- new_status_id: 1
- role_id: 3
- old_status_id: 2
- id: 246
- type_id: 3
-workflows_058:
- new_status_id: 3
- role_id: 2
- old_status_id: 6
- id: 58
- type_id: 1
-workflows_084:
- new_status_id: 4
- role_id: 3
- old_status_id: 5
- id: 84
- type_id: 1
-workflows_139:
- new_status_id: 5
- role_id: 2
- old_status_id: 4
- id: 139
- type_id: 2
-workflows_165:
- new_status_id: 6
- role_id: 3
- old_status_id: 3
- id: 165
- type_id: 2
-workflows_192:
- new_status_id: 2
- role_id: 1
- old_status_id: 3
- id: 192
- type_id: 3
-workflows_247:
- new_status_id: 3
- role_id: 3
- old_status_id: 2
- id: 247
- type_id: 3
-workflows_059:
- new_status_id: 4
- role_id: 2
- old_status_id: 6
- id: 59
- type_id: 1
-workflows_085:
- new_status_id: 6
- role_id: 3
- old_status_id: 5
- id: 85
- type_id: 1
-workflows_166:
- new_status_id: 1
- role_id: 3
- old_status_id: 4
- id: 166
- type_id: 2
-workflows_248:
- new_status_id: 4
- role_id: 3
- old_status_id: 2
- id: 248
- type_id: 3
-workflows_086:
- new_status_id: 1
- role_id: 3
- old_status_id: 6
- id: 86
- type_id: 1
-workflows_167:
- new_status_id: 2
- role_id: 3
- old_status_id: 4
- id: 167
- type_id: 2
-workflows_193:
- new_status_id: 4
- role_id: 1
- old_status_id: 3
- id: 193
- type_id: 3
-workflows_249:
- new_status_id: 5
- role_id: 3
- old_status_id: 2
- id: 249
- type_id: 3
-workflows_087:
- new_status_id: 2
- role_id: 3
- old_status_id: 6
- id: 87
- type_id: 1
-workflows_168:
- new_status_id: 3
- role_id: 3
- old_status_id: 4
- id: 168
- type_id: 2
-workflows_194:
- new_status_id: 5
- role_id: 1
- old_status_id: 3
- id: 194
- type_id: 3
-workflows_088:
- new_status_id: 3
- role_id: 3
- old_status_id: 6
- id: 88
- type_id: 1
-workflows_169:
- new_status_id: 5
- role_id: 3
- old_status_id: 4
- id: 169
- type_id: 2
-workflows_195:
- new_status_id: 6
- role_id: 1
- old_status_id: 3
- id: 195
- type_id: 3
-workflows_089:
- new_status_id: 4
- role_id: 3
- old_status_id: 6
- id: 89
- type_id: 1
-workflows_196:
- new_status_id: 1
- role_id: 1
- old_status_id: 4
- id: 196
- type_id: 3
-workflows_197:
- new_status_id: 2
- role_id: 1
- old_status_id: 4
- id: 197
- type_id: 3
-workflows_198:
- new_status_id: 3
- role_id: 1
- old_status_id: 4
- id: 198
- type_id: 3
-workflows_199:
- new_status_id: 5
- role_id: 1
- old_status_id: 4
- id: 199
- type_id: 3
-workflows_010:
- new_status_id: 6
- role_id: 1
- old_status_id: 2
- id: 10
- type_id: 1
-workflows_011:
- new_status_id: 1
- role_id: 1
- old_status_id: 3
- id: 11
- type_id: 1
-workflows_012:
- new_status_id: 2
- role_id: 1
- old_status_id: 3
- id: 12
- type_id: 1
-workflows_200:
- new_status_id: 6
- role_id: 1
- old_status_id: 4
- id: 200
- type_id: 3
-workflows_013:
- new_status_id: 4
- role_id: 1
- old_status_id: 3
- id: 13
- type_id: 1
-workflows_120:
- new_status_id: 5
- role_id: 1
- old_status_id: 6
- id: 120
- type_id: 2
-workflows_201:
- new_status_id: 1
- role_id: 1
- old_status_id: 5
- id: 201
- type_id: 3
-workflows_040:
- new_status_id: 6
- role_id: 2
- old_status_id: 2
- id: 40
- type_id: 1
-workflows_121:
- new_status_id: 2
- role_id: 2
- old_status_id: 1
- id: 121
- type_id: 2
-workflows_202:
- new_status_id: 2
- role_id: 1
- old_status_id: 5
- id: 202
- type_id: 3
-workflows_014:
- new_status_id: 5
- role_id: 1
- old_status_id: 3
- id: 14
- type_id: 1
-workflows_041:
- new_status_id: 1
- role_id: 2
- old_status_id: 3
- id: 41
- type_id: 1
-workflows_122:
- new_status_id: 3
- role_id: 2
- old_status_id: 1
- id: 122
- type_id: 2
-workflows_203:
- new_status_id: 3
- role_id: 1
- old_status_id: 5
- id: 203
- type_id: 3
-workflows_015:
- new_status_id: 6
- role_id: 1
- old_status_id: 3
- id: 15
- type_id: 1
-workflows_230:
- new_status_id: 6
- role_id: 2
- old_status_id: 4
- id: 230
- type_id: 3
-workflows_123:
- new_status_id: 4
- role_id: 2
- old_status_id: 1
- id: 123
- type_id: 2
-workflows_204:
- new_status_id: 4
- role_id: 1
- old_status_id: 5
- id: 204
- type_id: 3
-workflows_016:
- new_status_id: 1
- role_id: 1
- old_status_id: 4
- id: 16
- type_id: 1
-workflows_042:
- new_status_id: 2
- role_id: 2
- old_status_id: 3
- id: 42
- type_id: 1
-workflows_231:
- new_status_id: 1
- role_id: 2
- old_status_id: 5
- id: 231
- type_id: 3
-workflows_070:
- new_status_id: 6
- role_id: 3
- old_status_id: 2
- id: 70
- type_id: 1
-workflows_124:
- new_status_id: 5
- role_id: 2
- old_status_id: 1
- id: 124
- type_id: 2
-workflows_150:
- new_status_id: 5
- role_id: 2
- old_status_id: 6
- id: 150
- type_id: 2
-workflows_205:
- new_status_id: 6
- role_id: 1
- old_status_id: 5
- id: 205
- type_id: 3
-workflows_017:
- new_status_id: 2
- role_id: 1
- old_status_id: 4
- id: 17
- type_id: 1
-workflows_043:
- new_status_id: 4
- role_id: 2
- old_status_id: 3
- id: 43
- type_id: 1
-workflows_232:
- new_status_id: 2
- role_id: 2
- old_status_id: 5
- id: 232
- type_id: 3
-workflows_125:
- new_status_id: 6
- role_id: 2
- old_status_id: 1
- id: 125
- type_id: 2
-workflows_151:
- new_status_id: 2
- role_id: 3
- old_status_id: 1
- id: 151
- type_id: 2
-workflows_206:
- new_status_id: 1
- role_id: 1
- old_status_id: 6
- id: 206
- type_id: 3
-workflows_018:
- new_status_id: 3
- role_id: 1
- old_status_id: 4
- id: 18
- type_id: 1
-workflows_044:
- new_status_id: 5
- role_id: 2
- old_status_id: 3
- id: 44
- type_id: 1
-workflows_071:
- new_status_id: 1
- role_id: 3
- old_status_id: 3
- id: 71
- type_id: 1
-workflows_233:
- new_status_id: 3
- role_id: 2
- old_status_id: 5
- id: 233
- type_id: 3
-workflows_126:
- new_status_id: 1
- role_id: 2
- old_status_id: 2
- id: 126
- type_id: 2
-workflows_152:
- new_status_id: 3
- role_id: 3
- old_status_id: 1
- id: 152
- type_id: 2
-workflows_207:
- new_status_id: 2
- role_id: 1
- old_status_id: 6
- id: 207
- type_id: 3
-workflows_019:
- new_status_id: 5
- role_id: 1
- old_status_id: 4
- id: 19
- type_id: 1
-workflows_045:
- new_status_id: 6
- role_id: 2
- old_status_id: 3
- id: 45
- type_id: 1
-workflows_260:
- new_status_id: 6
- role_id: 3
- old_status_id: 4
- id: 260
- type_id: 3
-workflows_234:
- new_status_id: 4
- role_id: 2
- old_status_id: 5
- id: 234
- type_id: 3
-workflows_127:
- new_status_id: 3
- role_id: 2
- old_status_id: 2
- id: 127
- type_id: 2
-workflows_153:
- new_status_id: 4
- role_id: 3
- old_status_id: 1
- id: 153
- type_id: 2
-workflows_180:
- new_status_id: 5
- role_id: 3
- old_status_id: 6
- id: 180
- type_id: 2
-workflows_208:
- new_status_id: 3
- role_id: 1
- old_status_id: 6
- id: 208
- type_id: 3
-workflows_046:
- new_status_id: 1
- role_id: 2
- old_status_id: 4
- id: 46
- type_id: 1
-workflows_072:
- new_status_id: 2
- role_id: 3
- old_status_id: 3
- id: 72
- type_id: 1
-workflows_261:
- new_status_id: 1
- role_id: 3
- old_status_id: 5
- id: 261
- type_id: 3
-workflows_235:
- new_status_id: 6
- role_id: 2
- old_status_id: 5
- id: 235
- type_id: 3
-workflows_154:
- new_status_id: 5
- role_id: 3
- old_status_id: 1
- id: 154
- type_id: 2
-workflows_181:
- new_status_id: 2
- role_id: 1
- old_status_id: 1
- id: 181
- type_id: 3
-workflows_209:
- new_status_id: 4
- role_id: 1
- old_status_id: 6
- id: 209
- type_id: 3
-workflows_047:
- new_status_id: 2
- role_id: 2
- old_status_id: 4
- id: 47
- type_id: 1
-workflows_073:
- new_status_id: 4
- role_id: 3
- old_status_id: 3
- id: 73
- type_id: 1
-workflows_128:
- new_status_id: 4
- role_id: 2
- old_status_id: 2
- id: 128
- type_id: 2
-workflows_262:
- new_status_id: 2
- role_id: 3
- old_status_id: 5
- id: 262
- type_id: 3
-workflows_236:
- new_status_id: 1
- role_id: 2
- old_status_id: 6
- id: 236
- type_id: 3
-workflows_155:
- new_status_id: 6
- role_id: 3
- old_status_id: 1
- id: 155
- type_id: 2
-workflows_048:
- new_status_id: 3
- role_id: 2
- old_status_id: 4
- id: 48
- type_id: 1
-workflows_074:
- new_status_id: 5
- role_id: 3
- old_status_id: 3
- id: 74
- type_id: 1
-workflows_129:
- new_status_id: 5
- role_id: 2
- old_status_id: 2
- id: 129
- type_id: 2
-workflows_263:
- new_status_id: 3
- role_id: 3
- old_status_id: 5
- id: 263
- type_id: 3
-workflows_237:
- new_status_id: 2
- role_id: 2
- old_status_id: 6
- id: 237
- type_id: 3
-workflows_182:
- new_status_id: 3
- role_id: 1
- old_status_id: 1
- id: 182
- type_id: 3
-workflows_049:
- new_status_id: 5
- role_id: 2
- old_status_id: 4
- id: 49
- type_id: 1
-workflows_075:
- new_status_id: 6
- role_id: 3
- old_status_id: 3
- id: 75
- type_id: 1
-workflows_156:
- new_status_id: 1
- role_id: 3
- old_status_id: 2
- id: 156
- type_id: 2
-workflows_264:
- new_status_id: 4
- role_id: 3
- old_status_id: 5
- id: 264
- type_id: 3
-workflows_238:
- new_status_id: 3
- role_id: 2
- old_status_id: 6
- id: 238
- type_id: 3
-workflows_183:
- new_status_id: 4
- role_id: 1
- old_status_id: 1
- id: 183
- type_id: 3
-workflows_076:
- new_status_id: 1
- role_id: 3
- old_status_id: 4
- id: 76
- type_id: 1
-workflows_157:
- new_status_id: 3
- role_id: 3
- old_status_id: 2
- id: 157
- type_id: 2
-workflows_265:
- new_status_id: 6
- role_id: 3
- old_status_id: 5
- id: 265
- type_id: 3
-workflows_239:
- new_status_id: 4
- role_id: 2
- old_status_id: 6
- id: 239
- type_id: 3
-workflows_077:
- new_status_id: 2
- role_id: 3
- old_status_id: 4
- id: 77
- type_id: 1
-workflows_158:
- new_status_id: 4
- role_id: 3
- old_status_id: 2
- id: 158
- type_id: 2
-workflows_184:
- new_status_id: 5
- role_id: 1
- old_status_id: 1
- id: 184
- type_id: 3
-workflows_266:
- new_status_id: 1
- role_id: 3
- old_status_id: 6
- id: 266
- type_id: 3
-workflows_078:
- new_status_id: 3
- role_id: 3
- old_status_id: 4
- id: 78
- type_id: 1
-workflows_159:
- new_status_id: 5
- role_id: 3
- old_status_id: 2
- id: 159
- type_id: 2
-workflows_185:
- new_status_id: 6
- role_id: 1
- old_status_id: 1
- id: 185
- type_id: 3
-workflows_267:
- new_status_id: 2
- role_id: 3
- old_status_id: 6
- id: 267
- type_id: 3
-workflows_079:
- new_status_id: 5
- role_id: 3
- old_status_id: 4
- id: 79
- type_id: 1
-workflows_186:
- new_status_id: 1
- role_id: 1
- old_status_id: 2
- id: 186
- type_id: 3
-workflows_268:
- new_status_id: 3
- role_id: 3
- old_status_id: 6
- id: 268
- type_id: 3
-workflows_187:
- new_status_id: 3
- role_id: 1
- old_status_id: 2
- id: 187
- type_id: 3
-workflows_269:
- new_status_id: 4
- role_id: 3
- old_status_id: 6
- id: 269
- type_id: 3
-workflows_188:
- new_status_id: 4
- role_id: 1
- old_status_id: 2
- id: 188
- type_id: 3
diff --git a/spec_legacy/functional/wiki_controller_spec.rb b/spec_legacy/functional/wiki_controller_spec.rb
deleted file mode 100644
index b7d76f0bb6..0000000000
--- a/spec_legacy/functional/wiki_controller_spec.rb
+++ /dev/null
@@ -1,338 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-require_relative '../legacy_spec_helper'
-require 'wiki_controller'
-
-describe WikiController, type: :controller do
- render_views
-
- fixtures :all
-
- before do
- User.current = nil
- end
-
- def wiki
- Project.first.wiki
- end
-
- def redirect_page
- wiki.find_page(wiki.start_page) || wiki.pages.first
- end
-
- it 'shows start page' do
- get :show, params: { project_id: 'ecookbook' }
- assert_response :success
- assert_template 'show'
- assert_select 'h1', content: /CookBook documentation/
-
- # child_pages macro
- assert_select 'ul',
- attributes: { class: 'pages-hierarchy' },
- child: {
- tag: 'li',
- child: {
- tag: 'a',
- attributes: { href: '/projects/ecookbook/wiki/Page_with_an_inline_image' },
- content: 'Page with an inline image'
- }
- }
- end
-
- it 'shows page with name' do
- get :show, params: { project_id: 1, id: 'Another page' }
- assert_response :success
- assert_template 'show'
- assert_select 'h1', content: /Another page/
- end
-
- it 'shows unexistent page without edit right' do
- get :show, params: { project_id: 1, id: 'Unexistent page' }
- assert_response 404
- end
-
- it 'shows unexistent page with edit right' do
- session[:user_id] = 2
- get :show, params: { project_id: 1, id: 'Unexistent page' }
- assert_response :success
- assert_template 'new'
- end
-
- it 'histories with one version' do
- create :wiki_content_journal,
- journable_id: 2,
- data: build(:journal_wiki_content_journal,
- text: "h1. Another page\n\n\nthis is a link to ticket: #2")
- get :history, params: { project_id: 1, id: 'Another page' }
- assert_response :success
- assert_template 'history'
- refute_nil assigns(:versions)
- assert_equal 1, assigns(:versions).size
- assert_select 'input[type=submit][name=commit]', false
- end
-
- it 'diffs' do
- journal_from = create :wiki_content_journal,
- journable_id: 1,
- data: build(:journal_wiki_content_journal,
- text: 'h1. CookBook documentation')
- journal_to = create :wiki_content_journal,
- journable_id: 1,
- data: build(:journal_wiki_content_journal,
- text: "h1. CookBook documentation\n\n\nSome updated [[documentation]] here...")
-
- get :diff,
- params: { project_id: 1, id: 'CookBook documentation', version: journal_to.version, version_from: journal_from.version }
- assert_response :success
- assert_template 'diff'
- assert_select 'ins', attributes: { class: 'diffins' },
- content: /updated/
- end
-
- it 'annotates' do
- create :wiki_content_journal,
- journable_id: 1,
- data: build(:journal_wiki_content_journal,
- text: 'h1. CookBook documentation')
- journal_to = create :wiki_content_journal,
- journable_id: 1,
- data: build(:journal_wiki_content_journal,
- text: "h1. CookBook documentation\n\n\nSome [[documentation]] here...")
-
- get :annotate, params: { project_id: 1, id: 'CookBook documentation', version: journal_to.version }
- assert_response :success
- assert_template 'annotate'
- # Line 1
- assert_select 'tr',
- child: { tag: 'th', attributes: { class: 'line-num' }, content: '1' },
- child: { tag: 'td', attributes: { class: 'author' }, content: /John Smith/ },
- child: { tag: 'td', content: /h1\. CookBook documentation/ }
- # Line 2
- assert_select 'tr',
- child: { tag: 'th', attributes: { class: 'line-num' }, content: '2' },
- child: { tag: 'td', attributes: { class: 'author' }, content: /redMine Admin/ },
- child: { tag: 'td', content: /Some updated \[\[documentation\]\] here/ }
- end
-
- it 'gets rename' do
- session[:user_id] = 2
- get :rename, params: { project_id: 1, id: 'Another page' }
- assert_response :success
- assert_template 'rename'
- end
-
- it 'gets rename child page' do
- session[:user_id] = 2
- get :rename, params: { project_id: 1, id: 'Child 1' }
- assert_response :success
- assert_template 'rename'
- end
-
- it 'renames with redirect' do
- session[:user_id] = 2
- patch :rename, params: { project_id: 1, id: 'Another page',
- page: { title: 'Another renamed page',
- redirect_existing_links: 1 } }
- assert_redirected_to action: 'show', project_id: 'ecookbook', id: 'another-renamed-page'
- # Check redirects
- refute_nil wiki.find_page('Another page')
- assert_nil wiki.find_page('Another page', with_redirect: false)
- end
-
- it 'renames without redirect' do
- session[:user_id] = 2
- patch :rename, params: { project_id: 1, id: 'another-page',
- page: { title: 'Another renamed page',
- redirect_existing_links: '0' } }
- assert_redirected_to action: 'show', project_id: 'ecookbook', id: 'another-renamed-page'
- # Check that there's no redirects
- assert_nil wiki.find_page('Another page')
- end
-
- it 'destroys child' do
- session[:user_id] = 2
- delete :destroy, params: { project_id: 1, id: 'Child 1' }
- assert_redirected_to action: 'index', project_id: 'ecookbook', id: redirect_page
- end
-
- it 'destroys parent' do
- session[:user_id] = 2
- assert_no_difference('WikiPage.count') do
- delete :destroy, params: { project_id: 1, id: 'Another page' }
- end
- assert_response :success
- assert_template 'destroy'
- end
-
- it 'destroys parent with nullify' do
- session[:user_id] = 2
- assert_difference('WikiPage.count', -1) do
- delete :destroy, params: { project_id: 1, id: 'Another page', todo: 'nullify' }
- end
- assert_redirected_to action: 'index', project_id: 'ecookbook', id: redirect_page
- assert_nil WikiPage.find_by(id: 2)
- end
-
- it 'destroys parent with cascade' do
- session[:user_id] = 2
- assert_difference('WikiPage.count', -3) do
- delete :destroy, params: { project_id: 1, id: 'Another page', todo: 'destroy' }
- end
- assert_redirected_to action: 'index', project_id: 'ecookbook', id: redirect_page
- assert_nil WikiPage.find_by(id: 2)
- assert_nil WikiPage.find_by(id: 5)
- end
-
- it 'destroys parent with reassign' do
- session[:user_id] = 2
- assert_difference('WikiPage.count', -1) do
- delete :destroy, params: { project_id: 1, id: 'Another page', todo: 'reassign', reassign_to_id: 1 }
- end
- assert_redirected_to action: 'index', project_id: 'ecookbook', id: redirect_page
- assert_nil WikiPage.find_by(id: 2)
- assert_equal WikiPage.find(1), WikiPage.find_by(id: 5).parent
- end
-
- it 'indexes' do
- get :index, params: { project_id: 'ecookbook' }
- assert_response :success
- assert_template 'index'
- pages = assigns(:pages)
- refute_nil pages
- assert_equal wiki.pages.size, pages.size
-
- assert_select 'ul', attributes: { class: 'pages-hierarchy' },
- child: { tag: 'li', child: { tag: 'a', attributes: { href: '/projects/ecookbook/wiki/CookBook%20documentation' },
- content: 'CookBook documentation' },
- child: { tag: 'ul',
- child: { tag: 'li',
- child: { tag: 'a', attributes: { href: '/projects/ecookbook/wiki/Page%20with%20an%20inline%20image' },
- content: 'Page with an inline image' } } } },
- child: { tag: 'li', child: { tag: 'a', attributes: { href: '/projects/ecookbook/wiki/Another%20page' },
- content: 'Another page' } }
- end
-
- it 'indexes should include atom link' do
- get :index, params: { project_id: 'ecookbook' }
- assert_select 'a', attributes: { href: '/projects/ecookbook/activity.atom?show_wiki_edits=1' }
- end
-
- context 'GET :export' do
- context 'with an authorized user to export the wiki' do
- before do
- session[:user_id] = 2
- get :export, params: { project_id: 'ecookbook' }
- end
-
- it { is_expected.to respond_with :success }
- it { should_assign_to :pages }
- it { should_respond_with_content_type 'text/html' }
-
- it 'exports all of the wiki pages to a single html file' do
- assert_select 'a[name=?]', 'cookbook-documentation'
- assert_select 'a[name=?]', 'another-page'
- assert_select 'a[name=?]', 'page-with-an-inline-image'
- end
- end
-
- context 'with an unauthorized user' do
- before do
- get :export, params: { project_id: 'ecookbook' }
-
- it { is_expected.to respond_with :redirect }
- it { is_expected.to redirect_to('wiki index') { { action: 'show', project_id: @project, id: nil } } }
- end
- end
- end
-
- it 'does not found' do
- get :show, params: { project_id: 999 }
- assert_response 404
- end
-
- it 'protects page' do
- page = WikiPage.find_by(wiki_id: 1, title: 'Another page')
- assert !page.protected?
- session[:user_id] = 2
- post :protect, params: { project_id: 1, id: page.title, protected: '1' }
- assert_redirected_to action: 'show', project_id: 'ecookbook', id: 'another-page'
- assert page.reload.protected?
- end
-
- it 'unprotects page' do
- page = WikiPage.find_by(wiki_id: 1, title: 'CookBook documentation')
- assert page.protected?
- session[:user_id] = 2
- post :protect, params: { project_id: 1, id: page.title, protected: '0' }
- assert_redirected_to action: 'show', project_id: 'ecookbook', id: 'cookbook-documentation'
- assert !page.reload.protected?
- end
-
- it 'shows page with edit link' do
- session[:user_id] = 2
- get :show, params: { project_id: 1 }
- assert_response :success
- assert_template 'show'
- assert_select 'a', attributes: { href: '/projects/1/wiki/CookBook+documentation/edit' }
- end
-
- it 'shows page without edit link' do
- session[:user_id] = 4
- get :show, params: { project_id: 1 }
- assert_response :success
- assert_template 'show'
- assert_select('a', { attributes: { href: '/projects/1/wiki/CookBook+documentation/edit' } }, false)
- end
-
- it 'edits unprotected page' do
- # Non members can edit unprotected wiki pages
- session[:user_id] = 4
- get :edit, params: { project_id: 1, id: 'Another page' }
- assert_response :success
- assert_template 'edit'
- end
-
- it 'edits protected page by nonmember' do
- # Non members can't edit protected wiki pages
- session[:user_id] = 4
- get :edit, params: { project_id: 1, id: 'CookBook documentation' }
- assert_response 403
- end
-
- it 'edits protected page by member' do
- session[:user_id] = 2
- get :edit, params: { project_id: 1, id: 'CookBook documentation' }
- assert_response :success
- assert_template 'edit'
- end
-
- it 'histories of non existing page should return 404' do
- get :history, params: { project_id: 1, id: 'Unknown page' }
- assert_response 404
- end
-end
diff --git a/spec_legacy/functional/workflows_controller_spec.rb b/spec_legacy/functional/workflows_controller_spec.rb
deleted file mode 100644
index 45107145c4..0000000000
--- a/spec_legacy/functional/workflows_controller_spec.rb
+++ /dev/null
@@ -1,140 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-require_relative '../legacy_spec_helper'
-require 'workflows_controller'
-
-describe WorkflowsController, type: :controller do
- render_views
-
- fixtures :all
-
- before do
- User.current = nil
- session[:user_id] = 1 # admin
- end
-
- it 'gets edit' do
- get :edit
- assert_response :success
- assert_template 'edit'
- refute_nil assigns(:roles)
- refute_nil assigns(:types)
- end
-
- it 'gets edit with role and type' do
- Workflow.delete_all
- Workflow.create!(role_id: 1, type_id: 1, old_status_id: 2, new_status_id: 3)
- Workflow.create!(role_id: 2, type_id: 1, old_status_id: 3, new_status_id: 5)
-
- get :edit, params: { role_id: 2, type_id: 1 }
- assert_response :success
- assert_template 'edit'
-
- # used status only
- refute_nil assigns(:statuses)
- assert_equal [2, 3, 5], assigns(:statuses).map(&:id)
-
- # allowed transitions
- assert_select 'input', attributes: { type: 'checkbox',
- name: 'status[3][5][]',
- value: 'always',
- checked: 'checked' }
- # not allowed
- assert_select 'input', attributes: { type: 'checkbox',
- name: 'status[3][2][]',
- value: 'always',
- checked: nil }
- # unused
- assert_select('input', { attributes: { type: 'checkbox',
- name: 'status[1][1][]' } }, false)
- end
-
- it 'gets edit with role and type and all statuses' do
- Workflow.delete_all
-
- get :edit, params: { role_id: 2, type_id: 1, used_statuses_only: '0' }
- assert_response :success
- assert_template 'edit'
-
- refute_nil assigns(:statuses)
- assert_equal Status.count, assigns(:statuses).size
-
- assert_select 'input', attributes: { type: 'checkbox',
- name: 'status[1][1][]',
- value: 'always',
- checked: nil }
- end
-
- it 'gets copy' do
- get :copy
- assert_response :success
- assert_template 'copy'
- end
-
- it 'posts copy one to one' do
- source_transitions = status_transitions(type_id: 1, role_id: 2)
-
- post :copy, params: { source_type_id: '1', source_role_id: '2',
- target_type_ids: ['3'], target_role_ids: ['1'] }
- assert_response 302
- assert_equal source_transitions, status_transitions(type_id: 3, role_id: 1)
- end
-
- it 'posts copy one to many' do
- source_transitions = status_transitions(type_id: 1, role_id: 2)
-
- post :copy, params: { source_type_id: '1', source_role_id: '2',
- target_type_ids: ['2', '3'], target_role_ids: ['1', '3'] }
- assert_response 302
- assert_equal source_transitions, status_transitions(type_id: 2, role_id: 1)
- assert_equal source_transitions, status_transitions(type_id: 3, role_id: 1)
- assert_equal source_transitions, status_transitions(type_id: 2, role_id: 3)
- assert_equal source_transitions, status_transitions(type_id: 3, role_id: 3)
- end
-
- it 'posts copy many to many' do
- source_t2 = status_transitions(type_id: 2, role_id: 2)
- source_t3 = status_transitions(type_id: 3, role_id: 2)
-
- post :copy, params: { source_type_id: 'any', source_role_id: '2',
- target_type_ids: ['2', '3'], target_role_ids: ['1', '3'] }
- assert_response 302
- assert_equal source_t2, status_transitions(type_id: 2, role_id: 1)
- assert_equal source_t3, status_transitions(type_id: 3, role_id: 1)
- assert_equal source_t2, status_transitions(type_id: 2, role_id: 3)
- assert_equal source_t3, status_transitions(type_id: 3, role_id: 3)
- end
-
- # Returns an array of status transitions that can be compared
- def status_transitions(conditions)
- Workflow
- .where(conditions)
- .order(Arel.sql('type_id, role_id, old_status_id, new_status_id'))
- .map { |w| [w.old_status, w.new_status_id] }
- end
-end
diff --git a/spec_legacy/legacy_spec_helper.rb b/spec_legacy/legacy_spec_helper.rb
index 6eb00033bf..4bc6b40d7c 100644
--- a/spec_legacy/legacy_spec_helper.rb
+++ b/spec_legacy/legacy_spec_helper.rb
@@ -34,7 +34,6 @@ require 'fileutils'
require 'rspec/mocks'
require 'factory_bot_rails'
-require_relative './support/legacy_file_helpers'
require_relative './support/legacy_assertions'
require 'rspec/rails'
@@ -55,6 +54,11 @@ RSpec.configure do |config|
DatabaseCleaner.clean_with(:truncation)
end
+ # Clear fixtures so that normal specs can run without needing truncation
+ config.after(:suite) do
+ DatabaseCleaner.clean_with(:truncation)
+ end
+
config.include LegacyAssertionsAndHelpers
config.include ActiveSupport::Testing::Assertions
config.include Shoulda::Context::Assertions
diff --git a/spec_legacy/support/legacy_file_helpers.rb b/spec_legacy/support/legacy_file_helpers.rb
deleted file mode 100644
index a656fe70d2..0000000000
--- a/spec_legacy/support/legacy_file_helpers.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-
-module LegacyFileHelpers
- module_function
-
- def mock_uploaded_file(name: 'test.txt',
- content_type: 'text/plain',
- content: 'test content',
- binary: false)
-
- tmp = ::OpenProject::Files.create_temp_file name: name, content: content, binary: binary
- Rack::Test::UploadedFile.new tmp.path, content_type, binary
- end
-end
diff --git a/spec_legacy/unit/enumeration_spec.rb b/spec_legacy/unit/enumeration_spec.rb
deleted file mode 100644
index 110b2b539c..0000000000
--- a/spec_legacy/unit/enumeration_spec.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-require_relative './../legacy_spec_helper'
-
-describe Enumeration, type: :model do
- before do
- WorkPackage.delete_all
- @low_priority = create :priority_low
- @issues = create_list :work_package, 6, priority: @low_priority
- @default_enumeration = create :default_enumeration
- end
-
- it 'ins use' do
- assert @low_priority.in_use?
- assert !create(:priority).in_use?
- end
-
- it 'defaults' do
- e = Enumeration.default
- assert e.is_a?(Enumeration)
- assert e.is_default?
- assert_equal 'Default Enumeration', e.name
- end
-
- it 'creates' do
- e = Enumeration.new(name: 'Not default', is_default: false)
- e.type = 'Enumeration'
- assert e.save
- assert_equal @default_enumeration.name, Enumeration.default.name
- end
-
- it 'creates as default' do
- e = Enumeration.new(name: 'Very urgent', is_default: true)
- e.type = 'Enumeration'
- assert e.save
- assert_equal e, Enumeration.default
- end
-
- it 'updates default' do
- @default_enumeration.update(name: 'Changed', is_default: true)
- assert_equal @default_enumeration, Enumeration.default
- end
-
- it 'updates default to non default' do
- @default_enumeration.update(name: 'Changed', is_default: false)
- assert_nil Enumeration.default
- end
-
- it 'changes default' do
- e = Enumeration.find_by(name: @default_enumeration.name)
- e.update(name: 'Changed Enumeration', is_default: true)
- assert_equal e, Enumeration.default
- end
-
- it 'destroys with reassign' do
- new_priority = create :priority
- Enumeration.find(@low_priority.id).destroy(new_priority)
- assert_nil WorkPackage.find_by(priority_id: @low_priority.id)
- assert_equal @issues.size, new_priority.objects_count
- end
-
- it 'belongs to a project' do
- association = Enumeration.reflect_on_association(:project)
- assert association, 'No Project association found'
- assert_equal :belongs_to, association.macro
- end
-
- it 'acts as tree' do
- assert @low_priority.respond_to?(:parent)
- assert @low_priority.respond_to?(:children)
- end
-end
diff --git a/spec_legacy/unit/lib/redmine/i18n_spec.rb b/spec_legacy/unit/lib/redmine/i18n_spec.rb
index e291d5aa59..59b48d72e4 100644
--- a/spec_legacy/unit/lib/redmine/i18n_spec.rb
+++ b/spec_legacy/unit/lib/redmine/i18n_spec.rb
@@ -102,18 +102,4 @@ describe Redmine::I18n do
end.not_to raise_error
end
end
-
- it 'fallbacks' do
- ::I18n.backend.store_translations(:en, untranslated: 'Untranslated string')
- ::I18n.locale = 'en'
- assert_equal 'Untranslated string', I18n.t(:untranslated)
- ::I18n.locale = 'de'
- assert_equal 'Untranslated string', I18n.t(:untranslated)
-
- ::I18n.backend.store_translations(:de, untranslated: 'Keine Übersetzung')
- ::I18n.locale = 'en'
- assert_equal 'Untranslated string', I18n.t(:untranslated)
- ::I18n.locale = 'de'
- assert_equal 'Keine Übersetzung', I18n.t(:untranslated)
- end
end
diff --git a/spec_legacy/unit/lib/redmine/menu_manager/menu_item_spec.rb b/spec_legacy/unit/lib/redmine/menu_manager/menu_item_spec.rb
deleted file mode 100644
index ebddff5b60..0000000000
--- a/spec_legacy/unit/lib/redmine/menu_manager/menu_item_spec.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-require_relative '../../../../legacy_spec_helper'
-
-module RedmineMenuTestHelper
- # Helpers
- def get_menu_item(menu_name, item_name)
- Redmine::MenuManager.items(menu_name).find { |item| item.name == item_name.to_sym }
- end
-end
-
-describe Redmine::MenuManager::MenuItem do
- include RedmineMenuTestHelper
-
- Redmine::MenuManager.map :test_menu do |menu|
- menu.push(:parent, '/test', {})
- menu.push(:child_menu, '/test', parent: :parent)
- menu.push(:child2_menu, '/test', parent: :parent)
- end
-
- # context new menu item
- it 'news menu item should require a name' do
- assert_raises ArgumentError do
- Redmine::MenuManager::MenuItem.new
- end
- end
-
- it 'news menu item should require an url' do
- assert_raises ArgumentError do
- Redmine::MenuManager::MenuItem.new(:test_missing_url)
- end
- end
-
- it 'news menu item should require the options' do
- assert_raises ArgumentError do
- Redmine::MenuManager::MenuItem.new(:test_missing_options, '/test')
- end
- end
-
- it 'news menu item with all required parameters' do
- assert Redmine::MenuManager::MenuItem.new(:test_good_menu, '/test', {})
- end
-
- it 'news menu item should require a proc to use for the if condition' do
- assert_raises ArgumentError do
- Redmine::MenuManager::MenuItem.new(:test_error, '/test',
- if: ['not_a_proc'])
- end
-
- assert Redmine::MenuManager::MenuItem.new(:test_good_if, '/test',
- if: Proc.new {})
- end
-
- it 'news menu item should allow a hash for extra html options' do
- assert_raises ArgumentError do
- Redmine::MenuManager::MenuItem.new(:test_error, '/test',
- html: ['not_a_hash'])
- end
-
- assert Redmine::MenuManager::MenuItem.new(:test_good_html, '/test',
- html: { data: 'foo' })
- end
-
- it 'news menu item should require a proc to use the children option' do
- assert_raises ArgumentError do
- Redmine::MenuManager::MenuItem.new(:test_error, '/test',
- children: ['not_a_proc'])
- end
-
- assert Redmine::MenuManager::MenuItem.new(:test_good_children, '/test',
- children: Proc.new {})
- end
-
- it 'news should not allow setting the parent item to the current item' do
- assert_raises ArgumentError do
- Redmine::MenuManager::MenuItem.new(:test_error, '/test', parent: :test_error)
- end
- end
-
- it 'hases children' do
- parent_item = get_menu_item(:test_menu, :parent)
- assert parent_item.has_children?
- assert_equal 2, parent_item.children.size
- assert_equal get_menu_item(:test_menu, :child_menu).name, parent_item.children[0].name
- assert_equal get_menu_item(:test_menu, :child2_menu).name, parent_item.children[1].name
- end
-end
diff --git a/spec_legacy/unit/project_spec.rb b/spec_legacy/unit/project_spec.rb
deleted file mode 100644
index c6f8d991ce..0000000000
--- a/spec_legacy/unit/project_spec.rb
+++ /dev/null
@@ -1,175 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-require_relative '../legacy_spec_helper'
-
-describe Project, type: :model do
- fixtures :all
-
- before do
- User.current = nil
- end
-
- it { is_expected.to validate_presence_of :name }
-
- context 'associations' do
- it { is_expected.to have_many :members }
- it { is_expected.to have_many(:users).through(:members) }
- it { is_expected.to have_many :member_principals }
- it { is_expected.to have_many(:principals).through(:member_principals) }
- it { is_expected.to have_many :enabled_modules }
- it { is_expected.to have_many :work_packages }
- it { is_expected.to have_many(:work_package_changes).through(:work_packages) }
- it { is_expected.to have_many :versions }
- it { is_expected.to have_many :time_entries }
- it { is_expected.to have_many :queries }
- it { is_expected.to have_many :news }
- it { is_expected.to have_many :categories }
- it { is_expected.to have_many :forums }
- it { is_expected.to have_many(:changesets).through(:repository) }
-
- it { is_expected.to have_one :repository }
- it { is_expected.to have_one :wiki }
-
- it { is_expected.to have_and_belong_to_many :types }
- it { is_expected.to have_and_belong_to_many :work_package_custom_fields }
- end
-
- it 'memberses should be active users' do
- Project.all.each do |project|
- assert_nil project.members.detect { |m| !(m.principal.is_a?(User) && m.principal.active?) }
- end
- end
-
- it 'userses should be active users' do
- Project.all.each do |project|
- assert_nil project.users.detect { |u| !(u.is_a?(User) && u.active?) }
- end
- end
-
- it 'parents' do
- p = Project.find(6).parent
- assert p.is_a?(Project)
- assert_equal 5, p.id
- end
-
- it 'ancestorses' do
- a = Project.find(6).ancestors
- assert a.first.is_a?(Project)
- assert_equal [1, 5], a.map(&:id).sort
- end
-
- it 'roots' do
- r = Project.find(6).root
- assert r.is_a?(Project)
- assert_equal 1, r.id
- end
-
- it 'childrens' do
- c = Project.find(1).children
- assert c.first.is_a?(Project)
- # ignore ordering, since it depends on database collation configuration
- # and may order lowercase/uppercase chars in a different order
- assert_equal [3, 4, 5], c.map(&:id).sort!
- end
-
- it 'descendantses' do
- d = Project.find(1).descendants.pluck(:id)
- assert_equal [3, 4, 5, 6], d.sort
- end
-
- it 'userses by role' do
- users_by_role = Project.find(1).users_by_role
- assert_kind_of Hash, users_by_role
- role = Role.find(1)
- assert_kind_of Array, users_by_role[role]
- assert users_by_role[role].include?(User.find(2))
- end
-
- it 'rolleds up types' do
- parent = Project.find(1)
- parent.types = ::Type.find([1, 2])
- child = parent.children.find(3)
-
- assert_equal [1, 2], parent.type_ids
- assert_equal [2, 3], child.types.map(&:id)
-
- assert_kind_of ::Type, parent.rolled_up_types.first
-
- assert_equal [999, 1, 2, 3], parent.rolled_up_types.map(&:id)
- assert_equal [2, 3], child.rolled_up_types.map(&:id)
- end
-
- it 'rolleds up types should ignore archived subprojects' do
- parent = Project.find(1)
- parent.types = ::Type.find([1, 2])
- child = parent.children.find(3)
- child.types = ::Type.find([1, 3])
- parent.children.each do |child|
- child.update(active: false)
- child.children.each do |grand_child|
- grand_child.update(active: false)
- end
- end
-
- assert_equal [1, 2], parent.rolled_up_types.map(&:id)
- end
-
- context 'with modules',
- with_legacy_settings: { default_projects_modules: ['work_package_tracking', 'repository'] } do
- it 'enableds module names' do
- project = Project.new
-
- project.enabled_module_names = %w(work_package_tracking news)
- assert_equal %w(news work_package_tracking), project.enabled_module_names.sort
- end
- end
-
- it 'enableds module names should not recreate enabled modules' do
- project = Project.find(1)
- # Remove one module
- modules = project.enabled_modules.to_a.slice(0..-2)
- assert modules.any?
- assert_difference 'EnabledModule.count', -1 do
- project.enabled_module_names = modules.map(&:name)
- end
- project.reload
- # Ids should be preserved
- assert_equal project.enabled_module_ids.sort, modules.map(&:id).sort
- end
-
- it 'closes completed versions' do
- Version.update_all("status = 'open'")
- project = Project.find(1)
- refute_nil project.versions.detect { |v| v.completed? && v.status == 'open' }
- refute_nil project.versions.detect { |v| !v.completed? && v.status == 'open' }
- project.close_completed_versions
- project.reload
- assert_nil project.versions.detect { |v| v.completed? && v.status != 'closed' }
- refute_nil project.versions.detect { |v| !v.completed? && v.status == 'open' }
- end
-end
diff --git a/spec_legacy/unit/search_spec.rb b/spec_legacy/unit/search_spec.rb
deleted file mode 100644
index 6ca1d1f60d..0000000000
--- a/spec_legacy/unit/search_spec.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-require_relative '../legacy_spec_helper'
-
-describe 'Search' do # FIXME: naming (RSpec-port)
- fixtures :all
-
- before do
- @project = Project.find(1)
- @issue_keyword = '%unable to print recipes%'
- @issue = WorkPackage.find(1)
- @changeset_keyword = '%very first commit%'
- @changeset = Changeset.find(100)
- end
-
- it 'search_by_anonymouses' do
- User.current = nil
-
- r = WorkPackage.search(@issue_keyword).first
- assert r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert r.include?(@changeset)
-
- # Removes the :view_changesets permission from Anonymous role
- remove_permission Role.anonymous, :view_changesets
-
- r = WorkPackage.search(@issue_keyword).first
- assert r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert !r.include?(@changeset)
-
- # Make the project private
- @project.update_attribute :public, false
- r = WorkPackage.search(@issue_keyword).first
- assert !r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert !r.include?(@changeset)
- end
-
- it 'search_by_users' do
- User.current = User.find_by_login('rhill')
- assert User.current.memberships.empty?
-
- r = WorkPackage.search(@issue_keyword).first
- assert r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert r.include?(@changeset)
-
- # Removes the :view_changesets permission from Non member role
- remove_permission Role.non_member, :view_changesets
-
- r = WorkPackage.search(@issue_keyword).first
- assert r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert !r.include?(@changeset)
-
- # Make the project private
- @project.update_attribute :public, false
- r = WorkPackage.search(@issue_keyword).first
- assert !r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert !r.include?(@changeset)
- end
-
- it 'search_by_allowed_members' do
- User.current = User.find_by_login('jsmith')
- assert User.current.projects.include?(@project)
-
- r = WorkPackage.search(@issue_keyword).first
- assert r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert r.include?(@changeset)
-
- # Make the project private
- @project.update_attribute :public, false
- r = WorkPackage.search(@issue_keyword).first
- assert r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert r.include?(@changeset)
- end
-
- it 'search_by_unallowed_members' do
- # Removes the :view_changesets permission from user's and non member role
- remove_permission Role.find(1), :view_changesets
- remove_permission Role.non_member, :view_changesets
-
- User.current = User.find_by_login('jsmith')
- assert User.current.projects.include?(@project)
-
- r = WorkPackage.search(@issue_keyword).first
- assert r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert !r.include?(@changeset)
-
- # Make the project private
- @project.update_attribute :public, false
- r = WorkPackage.search(@issue_keyword).first
- assert r.include?(@issue)
- r = Changeset.search(@changeset_keyword).first
- assert !r.include?(@changeset)
- end
-
- it 'search_issue_with_multiple_hits_in_journalses' do
- i = WorkPackage.find(1)
- Journal.where(journable_id: i.id).delete_all
- i.add_journal User.current, 'Journal notes'
- i.save!
- i.add_journal User.current, 'Some notes with Redmine links: #2, r2.'
- i.save!
-
- assert_equal 2, i.journals.where("notes LIKE '%notes%'").count
-
- r = WorkPackage.search('%notes%').first
- assert_equal 1, r.size
- assert_equal i, r.first
- end
-
- private
-
- def remove_permission(role, permission)
- role.permissions = role.permissions - [permission]
- role.save
- end
-end
diff --git a/spec_legacy/unit/user_spec.rb b/spec_legacy/unit/user_spec.rb
deleted file mode 100644
index 1bba4058b7..0000000000
--- a/spec_legacy/unit/user_spec.rb
+++ /dev/null
@@ -1,298 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-require_relative '../legacy_spec_helper'
-
-describe User, type: :model do
- include MiniTest::Assertions # refute
-
- fixtures :all
-
- before do
- @admin = User.find(1)
- @jsmith = User.find(2)
- @dlopper = User.find(3)
- end
-
- it 'creates' do
- user = User.new(firstname: 'new', lastname: 'user', mail: 'newuser@somenet.foo')
-
- user.login = 'jsmith'
- user.password = 'adminADMIN!'
- user.password_confirmation = 'adminADMIN!'
- # login uniqueness
- assert !user.save
- assert_equal 1, user.errors.count
-
- user.login = 'newuser'
- user.password = 'adminADMIN!'
- user.password_confirmation = 'NOTadminADMIN!'
- # password confirmation
- assert !user.save
- assert_equal 1, user.errors.count
-
- user.password = 'adminADMIN!'
- user.password_confirmation = 'adminADMIN!'
- assert user.save
- end
-
- context 'User.login' do
- it 'is case-insensitive.' do
- u = User.new(firstname: 'new', lastname: 'user', mail: 'newuser@somenet.foo')
- u.login = 'newuser'
- u.password = 'adminADMIN!'
- u.password_confirmation = 'adminADMIN!'
- assert u.save
-
- u = User.new(firstname: 'Similar', lastname: 'User', mail: 'similaruser@somenet.foo')
- u.login = 'NewUser'
- u.password = 'adminADMIN!'
- u.password_confirmation = 'adminADMIN!'
- assert !u.save
- assert_includes u.errors[:login], I18n.t('activerecord.errors.messages.taken')
- end
- end
-
- it 'mails uniqueness should not be case sensitive' do
- u = User.new(firstname: 'new', lastname: 'user', mail: 'newuser@somenet.foo')
- u.login = 'newuser1'
- u.password = 'adminADMIN!'
- u.password_confirmation = 'adminADMIN!'
- assert u.save
-
- u = User.new(firstname: 'new', lastname: 'user', mail: 'newUser@Somenet.foo')
- u.login = 'newuser2'
- u.password = 'adminADMIN!'
- u.password_confirmation = 'adminADMIN!'
- assert !u.save
- assert_includes u.errors[:mail], I18n.t('activerecord.errors.messages.taken')
- end
-
- it 'validates login presence' do
- @admin.login = ''
- assert !@admin.save
- assert_equal 1, @admin.errors.count
- end
-
- context 'User#try_to_login' do
- it 'fall-backs to case-insensitive if user login is not found as-typed.' do
- user = User.try_to_login('AdMin', 'adminADMIN!')
- assert_kind_of User, user
- assert_equal 'admin', user.login
- end
-
- it 'selects the exact matching user first' do
- case_sensitive_user = create(:user, login: 'changed', password: 'adminADMIN!',
- password_confirmation: 'adminADMIN!')
- # bypass validations to make it appear like existing data
- case_sensitive_user.update_attribute(:login, 'ADMIN')
-
- user = User.try_to_login('ADMIN', 'adminADMIN!')
- assert_kind_of User, user
- assert_equal 'ADMIN', user.login
- end
- end
-
- it 'passwords' do
- user = User.try_to_login('admin', 'adminADMIN!')
- assert_kind_of User, user
- assert_equal 'admin', user.login
- user.password = 'newpassPASS!'
- assert user.save
-
- user = User.try_to_login('admin', 'newpassPASS!')
- assert_kind_of User, user
- assert_equal 'admin', user.login
- end
-
- it 'names format' do
- assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
- Setting.user_format = :firstname_lastname
- assert_equal 'John Smith', @jsmith.reload.name
- Setting.user_format = :username
- assert_equal 'jsmith', @jsmith.reload.name
- end
-
- it 'locks' do
- user = User.try_to_login('jsmith', 'jsmith')
- assert_equal @jsmith, user
-
- @jsmith.status = User.statuses[:locked]
- assert @jsmith.save
-
- user = User.try_to_login('jsmith', 'jsmith')
- assert_equal nil, user
- end
-
- describe '.try_to_login' do
- context 'with good credentials' do
- it 'returns the user' do
- user = User.try_to_login('admin', 'adminADMIN!')
- assert_kind_of User, user
- assert_equal 'admin', user.login
- end
- end
-
- context 'with wrong credentials' do
- it 'returns nil' do
- assert_nil User.try_to_login('admin', 'foo')
- end
- end
- end
-
- if ldap_configured?
- describe '#try_to_login using LDAP' do
- context 'with failed connection to the LDAP server' do
- it 'returns nil' do
- @auth_source = LdapAuthSource.find(1)
- allow_any_instance_of(AuthSource).to receive(:initialize_ldap_con).and_raise(Net::LDAP::Error, 'Cannot connect')
-
- assert_equal nil, User.try_to_login('edavis', 'wrong')
- end
- end
-
- context 'with an unsuccessful authentication' do
- it 'returns nil' do
- assert_equal nil, User.try_to_login('edavis', 'wrong')
- end
- end
-
- context 'on the fly registration' do
- before do
- @auth_source = LdapAuthSource.find(1)
- end
-
- context 'with a successful authentication' do
- it "creates a new user account if it doesn't exist" do
- assert_difference('User.count') do
- user = User.try_to_login('edavis', '123456')
- assert !user.admin?
- end
- end
-
- it 'retrieves existing user' do
- user = User.try_to_login('edavis', '123456')
- user.admin = true
- user.save!
-
- assert_no_difference('User.count') do
- user = User.try_to_login('edavis', '123456')
- assert user.admin?
- end
- end
- end
- end
- end
-
- else
- puts 'Skipping LDAP tests.'
- end
-
- it 'returns existing or new anonymous' do
- anon = User.anonymous
- assert !anon.new_record?
- assert_kind_of AnonymousUser, anon
- end
-
- it { is_expected.to have_one :rss_token }
-
- it 'rsses key' do
- assert_nil @jsmith.rss_token
- key = @jsmith.rss_key
- assert_equal 64, key.length
-
- @jsmith.reload
- assert_equal key, @jsmith.rss_key
- end
-
- it { is_expected.to have_one :api_token }
-
- context 'User#find_by_api_key' do
- it 'returns nil if no matching key is found' do
- assert_nil User.find_by_api_key('zzzzzzzzz')
- end
-
- it 'returns nil if the key is found for an inactive user' do
- user = create(:user, status: User.statuses[:locked])
- token = build(:api_token, user:)
- user.api_token = token
- user.save
-
- assert_nil User.find_by_api_key(token.value)
- end
-
- it 'returns the user if the key is found for an active user' do
- user = create(:user, status: User.statuses[:active])
- token = build(:api_token, user:)
- user.api_token = token
- user.save
-
- assert_equal user, User.find_by_api_key(token.plain_value)
- end
- end
-
- it 'roleses for project' do
- # user with a role
- roles = @jsmith.roles_for_project(Project.find(1))
- assert_kind_of Role, roles.first
- assert_equal 'Manager', roles.first.name
-
- # user with no role
- assert_nil @dlopper.roles_for_project(Project.find(2)).detect(&:member?)
- end
-
- it 'projectses by role for user with role' do
- user = User.find(2)
- assert_kind_of Hash, user.projects_by_role
- assert_equal 2, user.projects_by_role.size
- assert_equal [1, 5], user.projects_by_role[Role.find(1)].map(&:id).sort
- assert_equal [2], user.projects_by_role[Role.find(2)].map(&:id).sort
- end
-
- it 'projectses by role for user with no role' do
- user = create(:user)
- assert_equal({}, user.projects_by_role)
- end
-
- it 'projectses by role for anonymous' do
- assert_equal({}, User.anonymous.projects_by_role)
- end
-
- it 'commentses sorting preference' do
- assert !@jsmith.wants_comments_in_reverse_order?
- @jsmith.pref.comments_sorting = 'asc'
- assert !@jsmith.wants_comments_in_reverse_order?
- @jsmith.pref.comments_sorting = 'desc'
- assert @jsmith.wants_comments_in_reverse_order?
- end
-
- it 'finds by mail should be case insensitive' do
- u = User.find_by_mail('JSmith@somenet.foo')
- refute_nil u
- assert_equal 'jsmith@somenet.foo', u.mail
- end
-end
diff --git a/spec_legacy/unit/version_spec.rb b/spec_legacy/unit/version_spec.rb
deleted file mode 100644
index 8f1ab58c6b..0000000000
--- a/spec_legacy/unit/version_spec.rb
+++ /dev/null
@@ -1,132 +0,0 @@
-#-- copyright
-# OpenProject is an open source project management software.
-# Copyright (C) 2012-2022 the OpenProject GmbH
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License version 3.
-#
-# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-# Copyright (C) 2010-2013 the ChiliProject Team
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# See COPYRIGHT and LICENSE files for more details.
-#++
-require_relative '../legacy_spec_helper'
-
-describe Version, type: :model do
- fixtures :all
-
- it 'progresses should be 0 with no assigned issues' do
- project = Project.find(1)
- (v = Version.new.tap do |v|
- v.attributes = { project:, name: 'Progress' }
- end).save!
- assert_equal 0, v.completed_percent
- assert_equal 0, v.closed_percent
- end
-
- it 'progresses should be 0 with unbegun assigned issues' do
- project = Project.find(1)
- (v = Version.new.tap do |v|
- v.attributes = { project:, name: 'Progress' }
- end).save!
- add_work_package(v)
- add_work_package(v, done_ratio: 0)
- assert_progress_equal 0, v.completed_percent
- assert_progress_equal 0, v.closed_percent
- end
-
- it 'progresses should be 100 with closed assigned issues' do
- project = Project.find(1)
- status = Status.where(is_closed: true).first
- (v = Version.new.tap do |v|
- v.attributes = { project:, name: 'Progress' }
- end).save!
- add_work_package(v, status:)
- add_work_package(v, status:, done_ratio: 20)
- add_work_package(v, status:, done_ratio: 70, estimated_hours: 25)
- add_work_package(v, status:, estimated_hours: 15)
- assert_progress_equal 100.0, v.completed_percent
- assert_progress_equal 100.0, v.closed_percent
- end
-
- it 'progresses should consider done ratio of open assigned issues' do
- project = Project.find(1)
- (v = Version.new.tap do |v|
- v.attributes = { project:, name: 'Progress' }
- end).save!
- add_work_package(v)
- add_work_package(v, done_ratio: 20)
- add_work_package(v, done_ratio: 70)
- assert_progress_equal (0.0 + 20.0 + 70.0) / 3, v.completed_percent
- assert_progress_equal 0, v.closed_percent
- end
-
- it 'progresses should consider closed issues as completed' do
- project = Project.find(1)
- (v = Version.new.tap do |v|
- v.attributes = { project:, name: 'Progress' }
- end).save!
- add_work_package(v)
- add_work_package(v, done_ratio: 20)
- add_work_package(v, status: Status.where(is_closed: true).first)
- assert_progress_equal (0.0 + 20.0 + 100.0) / 3, v.completed_percent
- assert_progress_equal 100.0 / 3, v.closed_percent
- end
-
- it 'progresses should consider estimated hours to weight issues' do
- project = Project.find(1)
- (v = Version.new.tap do |v|
- v.attributes = { project:, name: 'Progress' }
- end).save!
- add_work_package(v, estimated_hours: 10)
- add_work_package(v, estimated_hours: 20, done_ratio: 30)
- add_work_package(v, estimated_hours: 40, done_ratio: 10)
- add_work_package(v, estimated_hours: 25, status: Status.where(is_closed: true).first)
- assert_progress_equal ((10.0 * 0) + (20.0 * 0.3) + (40 * 0.1) + (25.0 * 1)) / 95.0 * 100, v.completed_percent
- assert_progress_equal 25.0 / 95.0 * 100, v.closed_percent
- end
-
- it 'progresses should consider average estimated hours to weight unestimated issues' do
- project = Project.find(1)
- (v = Version.new.tap do |v|
- v.attributes = { project:, name: 'Progress' }
- end).save!
- add_work_package(v, done_ratio: 20)
- add_work_package(v, status: Status.where(is_closed: true).first)
- add_work_package(v, estimated_hours: 10, done_ratio: 30)
- add_work_package(v, estimated_hours: 40, done_ratio: 10)
- assert_progress_equal ((25.0 * 0.2) + (25.0 * 1) + (10.0 * 0.3) + (40.0 * 0.1)) / 100.0 * 100, v.completed_percent
- assert_progress_equal 25.0 / 100.0 * 100, v.closed_percent
- end
-
- private
-
- def add_work_package(version, attributes = {})
- WorkPackage.create!({ project: version.project,
- priority_id: 5,
- status_id: 1,
- version:,
- subject: 'Test',
- author: User.first,
- type: version.project.types.first }.merge(attributes))
- end
-
- def assert_progress_equal(expected_float, actual_float, _message = '')
- assert_in_delta(expected_float, actual_float, 0.000001, '')
- end
-end