Merge branch 'rc/improve-projects-factory' into 'master'

Improve the Project factory to make `creator` defaults to `namespace.owner`

See merge request !13412
This commit is contained in:
Robert Speicher 2017-08-10 21:48:47 +00:00
commit 130c369aa7
6 changed files with 130 additions and 196 deletions

View file

@ -1,8 +1,8 @@
require 'spec_helper'
describe AutocompleteController do
let!(:project) { create(:project) }
let!(:user) { create(:user) }
let(:project) { create(:project) }
let(:user) { project.owner }
context 'GET users' do
let!(:user2) { create(:user) }
@ -11,7 +11,6 @@ describe AutocompleteController do
context 'project members' do
before do
sign_in(user)
project.add_master(user)
end
describe 'GET #users with project ID' do
@ -19,11 +18,11 @@ describe AutocompleteController do
get(:users, project_id: project.id)
end
let(:body) { JSON.parse(response.body) }
it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq 2 }
it { expect(body.map { |u| u["username"] }).to include(user.username) }
it 'returns the project members' do
expect(json_response).to be_kind_of(Array)
expect(json_response.size).to eq(1)
expect(json_response.map { |u| u["username"] }).to include(user.username)
end
end
describe 'GET #users with unknown project' do
@ -39,20 +38,20 @@ describe AutocompleteController do
let(:group) { create(:group) }
before do
sign_in(user)
group.add_owner(user)
sign_in(user)
end
let(:body) { JSON.parse(response.body) }
describe 'GET #users with group ID' do
before do
get(:users, group_id: group.id)
end
it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq 1 }
it { expect(body.first["username"]).to eq user.username }
it 'returns the group members' do
expect(json_response).to be_kind_of(Array)
expect(json_response.size).to eq(1)
expect(json_response.first["username"]).to eq user.username
end
end
describe 'GET #users with unknown group ID' do
@ -65,23 +64,22 @@ describe AutocompleteController do
end
context 'non-member login for public project' do
let!(:project) { create(:project, :public) }
let(:project) { create(:project, :public) }
before do
sign_in(non_member)
project.add_master(user)
end
let(:body) { JSON.parse(response.body) }
describe 'GET #users with project ID' do
before do
get(:users, project_id: project.id, current_user: true)
end
it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq 3 }
it { expect(body.map { |u| u['username'] }).to include(user.username, non_member.username) }
it 'returns the project members and non-members' do
expect(json_response).to be_kind_of(Array)
expect(json_response.size).to eq(2)
expect(json_response.map { |u| u['username'] }).to include(user.username, non_member.username)
end
end
end
@ -91,10 +89,8 @@ describe AutocompleteController do
get(:users)
end
let(:body) { JSON.parse(response.body) }
it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq User.count }
it { expect(json_response).to be_kind_of(Array) }
it { expect(json_response.size).to eq User.count }
end
context 'user order' do
@ -106,7 +102,7 @@ describe AutocompleteController do
sign_in(user)
get(:users, search: 'user')
response_usernames = JSON.parse(response.body).map { |user| user['username'] }
response_usernames = json_response.map { |user| user['username'] }
expect(response_usernames.take(3)).to match_array([user.username, reported_user.username, user1.username])
end
@ -120,15 +116,12 @@ describe AutocompleteController do
get(:users, per_page: per_page)
end
let(:body) { JSON.parse(response.body) }
it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq per_page }
it { expect(json_response).to be_kind_of(Array) }
it { expect(json_response.size).to eq(per_page) }
end
context 'unauthenticated user' do
let(:public_project) { create(:project, :public) }
let(:body) { JSON.parse(response.body) }
describe 'GET #users with public project' do
before do
@ -136,8 +129,8 @@ describe AutocompleteController do
get(:users, project_id: public_project.id)
end
it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq 2 }
it { expect(json_response).to be_kind_of(Array) }
it { expect(json_response.size).to eq 2 }
end
describe 'GET #users with project' do
@ -170,8 +163,8 @@ describe AutocompleteController do
get(:users)
end
it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq 0 }
it { expect(json_response).to be_kind_of(Array) }
it { expect(json_response).to be_empty }
end
describe 'GET #users with todo filter' do
@ -179,14 +172,12 @@ describe AutocompleteController do
get :users, todo_filter: true
expect(response.status).to eq 200
expect(body).to be_kind_of(Array)
expect(json_response).to be_kind_of(Array)
end
end
end
context 'author of issuable included' do
let(:body) { JSON.parse(response.body) }
context 'authenticated' do
before do
sign_in(user)
@ -195,13 +186,13 @@ describe AutocompleteController do
it 'includes the author' do
get(:users, author_id: non_member.id)
expect(body.first["username"]).to eq non_member.username
expect(json_response.first["username"]).to eq non_member.username
end
it 'rejects non existent user ids' do
get(:users, author_id: 99999)
expect(body.collect { |u| u['id'] }).not_to include(99999)
expect(json_response.collect { |u| u['id'] }).not_to include(99999)
end
end
@ -209,7 +200,7 @@ describe AutocompleteController do
it 'returns empty result' do
get(:users, author_id: non_member.id)
expect(body).to be_empty
expect(json_response).to be_empty
end
end
end
@ -222,10 +213,9 @@ describe AutocompleteController do
it 'skips the user IDs passed' do
get(:users, skip_users: [user, user2].map(&:id))
other_user_ids = [non_member, project.owner, project.creator].map(&:id)
response_user_ids = JSON.parse(response.body).map { |user| user['id'] }
response_user_ids = json_response.map { |user| user['id'] }
expect(response_user_ids).to contain_exactly(*other_user_ids)
expect(response_user_ids).to contain_exactly(non_member.id)
end
end
end
@ -249,17 +239,15 @@ describe AutocompleteController do
get(:projects, project_id: project.id)
end
let(:body) { JSON.parse(response.body) }
it 'returns projects' do
expect(json_response).to be_kind_of(Array)
expect(json_response.size).to eq(2)
it do
expect(body).to be_kind_of(Array)
expect(body.size).to eq 2
expect(json_response.first['id']).to eq(0)
expect(json_response.first['name_with_namespace']).to eq 'No project'
expect(body.first['id']).to eq 0
expect(body.first['name_with_namespace']).to eq 'No project'
expect(body.last['id']).to eq authorized_project.id
expect(body.last['name_with_namespace']).to eq authorized_project.name_with_namespace
expect(json_response.last['id']).to eq authorized_project.id
expect(json_response.last['name_with_namespace']).to eq authorized_project.name_with_namespace
end
end
end
@ -275,14 +263,12 @@ describe AutocompleteController do
get(:projects, project_id: project.id, search: 'rugged')
end
let(:body) { JSON.parse(response.body) }
it 'returns projects' do
expect(json_response).to be_kind_of(Array)
expect(json_response.size).to eq(2)
it do
expect(body).to be_kind_of(Array)
expect(body.size).to eq 2
expect(body.last['id']).to eq authorized_search_project.id
expect(body.last['name_with_namespace']).to eq authorized_search_project.name_with_namespace
expect(json_response.last['id']).to eq authorized_search_project.id
expect(json_response.last['name_with_namespace']).to eq authorized_search_project.name_with_namespace
end
end
end
@ -304,11 +290,9 @@ describe AutocompleteController do
get(:projects, project_id: project.id)
end
let(:body) { JSON.parse(response.body) }
it do
expect(body).to be_kind_of(Array)
expect(body.size).to eq 3 # Of a total of 4
it 'returns projects' do
expect(json_response).to be_kind_of(Array)
expect(json_response.size).to eq 3 # Of a total of 4
end
end
end
@ -328,11 +312,9 @@ describe AutocompleteController do
get(:projects, project_id: project.id, offset_id: authorized_project.id)
end
let(:body) { JSON.parse(response.body) }
it do
expect(body.detect { |item| item['id'] == 0 }).to be_nil # 'No project' is not there
expect(body.detect { |item| item['id'] == authorized_project.id }).to be_nil # Offset project is not there either
it 'returns "No project"' do
expect(json_response.detect { |item| item['id'] == 0 }).to be_nil # 'No project' is not there
expect(json_response.detect { |item| item['id'] == authorized_project.id }).to be_nil # Offset project is not there either
end
end
end
@ -349,13 +331,10 @@ describe AutocompleteController do
get(:projects, project_id: project.id)
end
let(:body) { JSON.parse(response.body) }
it do
expect(body).to be_kind_of(Array)
expect(body.size).to eq 1 # 'No project'
expect(body.first['id']).to eq 0
it 'returns a single "No project"' do
expect(json_response).to be_kind_of(Array)
expect(json_response.size).to eq(1) # 'No project'
expect(json_response.first['id']).to eq 0
end
end
end

View file

@ -8,12 +8,47 @@ FactoryGirl.define do
factory :project, class: 'Project' do
sequence(:name) { |n| "project#{n}" }
path { name.downcase.gsub(/\s/, '_') }
namespace
creator
# Behaves differently to nil due to cache_has_external_issue_tracker
has_external_issue_tracker false
# Associations
namespace
creator { group ? create(:user) : namespace&.owner }
# Nest Project Feature attributes
transient do
wiki_access_level ProjectFeature::ENABLED
builds_access_level ProjectFeature::ENABLED
snippets_access_level ProjectFeature::ENABLED
issues_access_level ProjectFeature::ENABLED
merge_requests_access_level ProjectFeature::ENABLED
repository_access_level ProjectFeature::ENABLED
end
after(:create) do |project, evaluator|
# Builds and MRs can't have higher visibility level than repository access level.
builds_access_level = [evaluator.builds_access_level, evaluator.repository_access_level].min
merge_requests_access_level = [evaluator.merge_requests_access_level, evaluator.repository_access_level].min
project.project_feature.update_columns(
wiki_access_level: evaluator.wiki_access_level,
builds_access_level: builds_access_level,
snippets_access_level: evaluator.snippets_access_level,
issues_access_level: evaluator.issues_access_level,
merge_requests_access_level: merge_requests_access_level,
repository_access_level: evaluator.repository_access_level)
# Normally the class Projects::CreateService is used for creating
# projects, and this class takes care of making sure the owner and current
# user have access to the project. Our specs don't use said service class,
# thus we must manually refresh things here.
unless project.group || project.pending_delete
project.add_master(project.owner)
end
project.group&.refresh_members_authorized_projects
end
trait :public do
visibility_level Gitlab::VisibilityLevel::PUBLIC
end
@ -67,30 +102,28 @@ FactoryGirl.define do
test_repo
transient do
create_template nil
create_templates nil
end
after :create do |project, evaluator|
if evaluator.create_template
args = evaluator.create_template
project.add_user(args[:user], args[:access])
if evaluator.create_templates
templates_path = "#{evaluator.create_templates}_templates"
project.repository.create_file(
args[:user],
".gitlab/#{args[:path]}/bug.md",
project.creator,
".gitlab/#{templates_path}/bug.md",
'something valid',
message: 'test 3',
branch_name: 'master')
project.repository.create_file(
args[:user],
".gitlab/#{args[:path]}/template_test.md",
project.creator,
".gitlab/#{templates_path}/template_test.md",
'template_test',
message: 'test 1',
branch_name: 'master')
project.repository.create_file(
args[:user],
".gitlab/#{args[:path]}/feature_proposal.md",
project.creator,
".gitlab/#{templates_path}/feature_proposal.md",
'feature_proposal',
message: 'test 2',
branch_name: 'master')
@ -142,44 +175,6 @@ FactoryGirl.define do
trait(:repository_enabled) { repository_access_level ProjectFeature::ENABLED }
trait(:repository_disabled) { repository_access_level ProjectFeature::DISABLED }
trait(:repository_private) { repository_access_level ProjectFeature::PRIVATE }
# Nest Project Feature attributes
transient do
wiki_access_level ProjectFeature::ENABLED
builds_access_level ProjectFeature::ENABLED
snippets_access_level ProjectFeature::ENABLED
issues_access_level ProjectFeature::ENABLED
merge_requests_access_level ProjectFeature::ENABLED
repository_access_level ProjectFeature::ENABLED
end
after(:create) do |project, evaluator|
# Builds and MRs can't have higher visibility level than repository access level.
builds_access_level = [evaluator.builds_access_level, evaluator.repository_access_level].min
merge_requests_access_level = [evaluator.merge_requests_access_level, evaluator.repository_access_level].min
project.project_feature
.update_attributes!(
wiki_access_level: evaluator.wiki_access_level,
builds_access_level: builds_access_level,
snippets_access_level: evaluator.snippets_access_level,
issues_access_level: evaluator.issues_access_level,
merge_requests_access_level: merge_requests_access_level,
repository_access_level: evaluator.repository_access_level
)
# Normally the class Projects::CreateService is used for creating
# projects, and this class takes care of making sure the owner and current
# user have access to the project. Our specs don't use said service class,
# thus we must manually refresh things here.
owner = project.owner
if owner && owner.is_a?(User) && !project.pending_delete
project.members.create!(user: owner, access_level: Gitlab::Access::MASTER)
end
project.group&.refresh_members_authorized_projects
end
end
# Project with empty repository

View file

@ -1,5 +1,5 @@
FactoryGirl.define do
factory :user, aliases: [:author, :assignee, :recipient, :owner, :creator, :resource_owner] do
factory :user, aliases: [:author, :assignee, :recipient, :owner, :resource_owner] do
email { generate(:email) }
name { generate(:name) }
username { generate(:username) }

View file

@ -1,41 +1,28 @@
require 'spec_helper'
describe Gitlab::Template::IssueTemplate do
subject { described_class }
let(:user) { create(:user) }
let(:project) do
create(:project,
:repository,
create_template: {
user: user,
access: Gitlab::Access::MASTER,
path: 'issue_templates'
})
end
let(:project) { create(:project, :repository, create_templates: :issue) }
describe '.all' do
it 'strips the md suffix' do
expect(subject.all(project).first.name).not_to end_with('.issue_template')
expect(described_class.all(project).first.name).not_to end_with('.issue_template')
end
it 'combines the globals and rest' do
all = subject.all(project).map(&:name)
all = described_class.all(project).map(&:name)
expect(all).to include('bug')
expect(all).to include('feature_proposal')
expect(all).to include('template_test')
end
end
describe '.find' do
it 'returns nil if the file does not exist' do
expect { subject.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
expect { described_class.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
it 'returns the issue object of a valid file' do
ruby = subject.find('bug', project)
ruby = described_class.find('bug', project)
expect(ruby).to be_a described_class
expect(ruby.name).to eq('bug')
@ -44,21 +31,17 @@ describe Gitlab::Template::IssueTemplate do
describe '.by_category' do
it 'return array of templates' do
all = subject.by_category('', project).map(&:name)
all = described_class.by_category('', project).map(&:name)
expect(all).to include('bug')
expect(all).to include('feature_proposal')
expect(all).to include('template_test')
end
context 'when repo is bare or empty' do
let(:empty_project) { create(:project) }
before do
empty_project.add_user(user, Gitlab::Access::MASTER)
end
it "returns empty array" do
templates = subject.by_category('', empty_project)
templates = described_class.by_category('', empty_project)
expect(templates).to be_empty
end
end
@ -66,26 +49,23 @@ describe Gitlab::Template::IssueTemplate do
describe '#content' do
it 'loads the full file' do
issue_template = subject.new('.gitlab/issue_templates/bug.md', project)
issue_template = described_class.new('.gitlab/issue_templates/bug.md', project)
expect(issue_template.name).to eq 'bug'
expect(issue_template.content).to eq('something valid')
end
it 'raises error when file is not found' do
issue_template = subject.new('.gitlab/issue_templates/bugnot.md', project)
issue_template = described_class.new('.gitlab/issue_templates/bugnot.md', project)
expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
context "when repo is empty" do
let(:empty_project) { create(:project) }
before do
empty_project.add_user(user, Gitlab::Access::MASTER)
end
it "raises file not found" do
issue_template = subject.new('.gitlab/issue_templates/not_existent.md', empty_project)
issue_template = described_class.new('.gitlab/issue_templates/not_existent.md', empty_project)
expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
end

View file

@ -1,41 +1,28 @@
require 'spec_helper'
describe Gitlab::Template::MergeRequestTemplate do
subject { described_class }
let(:user) { create(:user) }
let(:project) do
create(:project,
:repository,
create_template: {
user: user,
access: Gitlab::Access::MASTER,
path: 'merge_request_templates'
})
end
let(:project) { create(:project, :repository, create_templates: :merge_request) }
describe '.all' do
it 'strips the md suffix' do
expect(subject.all(project).first.name).not_to end_with('.issue_template')
expect(described_class.all(project).first.name).not_to end_with('.issue_template')
end
it 'combines the globals and rest' do
all = subject.all(project).map(&:name)
all = described_class.all(project).map(&:name)
expect(all).to include('bug')
expect(all).to include('feature_proposal')
expect(all).to include('template_test')
end
end
describe '.find' do
it 'returns nil if the file does not exist' do
expect { subject.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
expect { described_class.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
it 'returns the merge request object of a valid file' do
ruby = subject.find('bug', project)
ruby = described_class.find('bug', project)
expect(ruby).to be_a described_class
expect(ruby.name).to eq('bug')
@ -44,21 +31,17 @@ describe Gitlab::Template::MergeRequestTemplate do
describe '.by_category' do
it 'return array of templates' do
all = subject.by_category('', project).map(&:name)
all = described_class.by_category('', project).map(&:name)
expect(all).to include('bug')
expect(all).to include('feature_proposal')
expect(all).to include('template_test')
end
context 'when repo is bare or empty' do
let(:empty_project) { create(:project) }
before do
empty_project.add_user(user, Gitlab::Access::MASTER)
end
it "returns empty array" do
templates = subject.by_category('', empty_project)
templates = described_class.by_category('', empty_project)
expect(templates).to be_empty
end
end
@ -66,26 +49,23 @@ describe Gitlab::Template::MergeRequestTemplate do
describe '#content' do
it 'loads the full file' do
issue_template = subject.new('.gitlab/merge_request_templates/bug.md', project)
issue_template = described_class.new('.gitlab/merge_request_templates/bug.md', project)
expect(issue_template.name).to eq 'bug'
expect(issue_template.content).to eq('something valid')
end
it 'raises error when file is not found' do
issue_template = subject.new('.gitlab/merge_request_templates/bugnot.md', project)
issue_template = described_class.new('.gitlab/merge_request_templates/bugnot.md', project)
expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
context "when repo is empty" do
let(:empty_project) { create(:project) }
before do
empty_project.add_user(user, Gitlab::Access::MASTER)
end
it "raises file not found" do
issue_template = subject.new('.gitlab/merge_request_templates/not_existent.md', empty_project)
issue_template = described_class.new('.gitlab/merge_request_templates/not_existent.md', empty_project)
expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
end

View file

@ -8,8 +8,8 @@ describe API::Projects do
let(:user2) { create(:user) }
let(:user3) { create(:user) }
let(:admin) { create(:admin) }
let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
let(:project2) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace) }
let(:project) { create(:project, namespace: user.namespace) }
let(:project2) { create(:project, path: 'project2', namespace: user.namespace) }
let(:snippet) { create(:project_snippet, :public, author: user, project: project, title: 'example') }
let(:project_member) { create(:project_member, :developer, user: user3, project: project) }
let(:user4) { create(:user) }