PageRenderTime 25ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/controllers/import/bitbucket_controller_spec.rb

https://gitlab.com/abuhazim/gitlab-foss
Ruby | 367 lines | 297 code | 69 blank | 1 comment | 0 complexity | 098c26e857755d3e58b18176d2c86a01 MD5 | raw file
  1. # frozen_string_literal: true
  2. require 'spec_helper'
  3. RSpec.describe Import::BitbucketController do
  4. include ImportSpecHelper
  5. let(:user) { create(:user) }
  6. let(:token) { "asdasd12345" }
  7. let(:secret) { "sekrettt" }
  8. let(:refresh_token) { SecureRandom.hex(15) }
  9. let(:access_params) { { token: token, expires_at: nil, expires_in: nil, refresh_token: nil } }
  10. let(:code) { SecureRandom.hex(8) }
  11. def assign_session_tokens
  12. session[:bitbucket_token] = token
  13. end
  14. before do
  15. sign_in(user)
  16. allow(controller).to receive(:bitbucket_import_enabled?).and_return(true)
  17. end
  18. describe "GET callback" do
  19. before do
  20. session[:oauth_request_token] = {}
  21. end
  22. it "updates access token" do
  23. expires_at = Time.current + 1.day
  24. expires_in = 1.day
  25. access_token = double(token: token,
  26. secret: secret,
  27. expires_at: expires_at,
  28. expires_in: expires_in,
  29. refresh_token: refresh_token)
  30. allow_any_instance_of(OAuth2::Client)
  31. .to receive(:get_token)
  32. .with(hash_including(
  33. 'grant_type' => 'authorization_code',
  34. 'code' => code,
  35. redirect_uri: users_import_bitbucket_callback_url),
  36. {})
  37. .and_return(access_token)
  38. stub_omniauth_provider('bitbucket')
  39. get :callback, params: { code: code }
  40. expect(session[:bitbucket_token]).to eq(token)
  41. expect(session[:bitbucket_refresh_token]).to eq(refresh_token)
  42. expect(session[:bitbucket_expires_at]).to eq(expires_at)
  43. expect(session[:bitbucket_expires_in]).to eq(expires_in)
  44. expect(controller).to redirect_to(status_import_bitbucket_url)
  45. end
  46. end
  47. describe "GET status" do
  48. before do
  49. @repo = double(name: 'vim', slug: 'vim', owner: 'asd', full_name: 'asd/vim', clone_url: 'http://test.host/demo/url.git', 'valid?' => true)
  50. @invalid_repo = double(name: 'mercurialrepo', slug: 'mercurialrepo', owner: 'asd', full_name: 'asd/mercurialrepo', clone_url: 'http://test.host/demo/mercurialrepo.git', 'valid?' => false)
  51. allow(controller).to receive(:provider_url).and_return('http://demobitbucket.org')
  52. assign_session_tokens
  53. end
  54. it_behaves_like 'import controller status' do
  55. before do
  56. allow(controller).to receive(:provider_url).and_return('http://demobitbucket.org')
  57. end
  58. let(:repo) { @repo }
  59. let(:repo_id) { @repo.full_name }
  60. let(:import_source) { @repo.full_name }
  61. let(:provider_name) { 'bitbucket' }
  62. let(:client_repos_field) { :repos }
  63. end
  64. it 'returns invalid repos' do
  65. allow_any_instance_of(Bitbucket::Client).to receive(:repos).and_return([@repo, @invalid_repo])
  66. get :status, format: :json
  67. expect(response).to have_gitlab_http_status(:ok)
  68. expect(json_response['incompatible_repos'].length).to eq(1)
  69. expect(json_response.dig("incompatible_repos", 0, "id")).to eq(@invalid_repo.full_name)
  70. expect(json_response['provider_repos'].length).to eq(1)
  71. expect(json_response.dig("provider_repos", 0, "id")).to eq(@repo.full_name)
  72. end
  73. context 'when filtering' do
  74. let(:filter) { '<html>test</html>' }
  75. let(:expected_filter) { 'test' }
  76. subject { get :status, params: { filter: filter }, as: :json }
  77. it 'passes sanitized filter param to bitbucket client' do
  78. expect_next_instance_of(Bitbucket::Client) do |client|
  79. expect(client).to receive(:repos).with(filter: expected_filter).and_return([@repo])
  80. end
  81. subject
  82. end
  83. end
  84. end
  85. describe "POST create" do
  86. let(:bitbucket_username) { user.username }
  87. let(:bitbucket_user) do
  88. double(username: bitbucket_username)
  89. end
  90. let(:bitbucket_repo) do
  91. double(slug: "vim", owner: bitbucket_username, name: 'vim')
  92. end
  93. let(:project) { create(:project) }
  94. before do
  95. allow_any_instance_of(Bitbucket::Client).to receive(:repo).and_return(bitbucket_repo)
  96. allow_any_instance_of(Bitbucket::Client).to receive(:user).and_return(bitbucket_user)
  97. assign_session_tokens
  98. end
  99. it 'returns 200 response when the project is imported successfully' do
  100. allow(Gitlab::BitbucketImport::ProjectCreator)
  101. .to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
  102. .and_return(double(execute: project))
  103. post :create, format: :json
  104. expect(response).to have_gitlab_http_status(:ok)
  105. end
  106. it 'returns 422 response when the project could not be imported' do
  107. allow(Gitlab::BitbucketImport::ProjectCreator)
  108. .to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
  109. .and_return(double(execute: build(:project)))
  110. post :create, format: :json
  111. expect(response).to have_gitlab_http_status(:unprocessable_entity)
  112. end
  113. it_behaves_like 'project import rate limiter'
  114. context "when the repository owner is the Bitbucket user" do
  115. context "when the Bitbucket user and GitLab user's usernames match" do
  116. it "takes the current user's namespace" do
  117. expect(Gitlab::BitbucketImport::ProjectCreator)
  118. .to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
  119. .and_return(double(execute: project))
  120. post :create, format: :json
  121. end
  122. end
  123. context "when the Bitbucket user and GitLab user's usernames don't match" do
  124. let(:bitbucket_username) { "someone_else" }
  125. it "takes the current user's namespace" do
  126. expect(Gitlab::BitbucketImport::ProjectCreator)
  127. .to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
  128. .and_return(double(execute: project))
  129. post :create, format: :json
  130. end
  131. end
  132. context 'when the Bitbucket user is unauthorized' do
  133. render_views
  134. it 'returns unauthorized' do
  135. allow(controller).to receive(:current_user).and_return(user)
  136. allow(user).to receive(:can?).and_return(false)
  137. post :create, format: :json
  138. end
  139. end
  140. end
  141. context "when the repository owner is not the Bitbucket user" do
  142. let(:other_username) { "someone_else" }
  143. before do
  144. allow(bitbucket_repo).to receive(:owner).and_return(other_username)
  145. end
  146. context "when a namespace with the Bitbucket user's username already exists" do
  147. let!(:existing_namespace) { create(:group, name: other_username) }
  148. context "when the namespace is owned by the GitLab user" do
  149. before do
  150. existing_namespace.add_owner(user)
  151. end
  152. it "takes the existing namespace" do
  153. expect(Gitlab::BitbucketImport::ProjectCreator)
  154. .to receive(:new).with(bitbucket_repo, bitbucket_repo.name, existing_namespace, user, access_params)
  155. .and_return(double(execute: project))
  156. post :create, format: :json
  157. end
  158. end
  159. context "when the namespace is not owned by the GitLab user" do
  160. it "doesn't create a project" do
  161. expect(Gitlab::BitbucketImport::ProjectCreator)
  162. .not_to receive(:new)
  163. post :create, format: :json
  164. end
  165. end
  166. end
  167. context "when a namespace with the Bitbucket user's username doesn't exist" do
  168. context "when current user can create namespaces" do
  169. it "creates the namespace" do
  170. expect(Gitlab::BitbucketImport::ProjectCreator)
  171. .to receive(:new).and_return(double(execute: project))
  172. expect { post :create, format: :json }.to change(Namespace, :count).by(1)
  173. end
  174. it "takes the new namespace" do
  175. expect(Gitlab::BitbucketImport::ProjectCreator)
  176. .to receive(:new).with(bitbucket_repo, bitbucket_repo.name, an_instance_of(Group), user, access_params)
  177. .and_return(double(execute: project))
  178. post :create, format: :json
  179. end
  180. end
  181. context "when current user can't create namespaces" do
  182. before do
  183. user.update_attribute(:can_create_group, false)
  184. end
  185. it "doesn't create the namespace" do
  186. expect(Gitlab::BitbucketImport::ProjectCreator)
  187. .to receive(:new).and_return(double(execute: project))
  188. expect { post :create, format: :json }.not_to change(Namespace, :count)
  189. end
  190. it "takes the current user's namespace" do
  191. expect(Gitlab::BitbucketImport::ProjectCreator)
  192. .to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
  193. .and_return(double(execute: project))
  194. post :create, format: :json
  195. end
  196. end
  197. end
  198. context "when exceptions occur" do
  199. shared_examples "handles exceptions" do
  200. it "logs an exception" do
  201. expect(Bitbucket::Client).to receive(:new).and_raise(error)
  202. expect(controller).to receive(:log_exception)
  203. post :create, format: :json
  204. end
  205. end
  206. context "for OAuth2 errors" do
  207. let(:fake_response) { double('Faraday::Response', headers: {}, body: '', status: 403) }
  208. let(:error) { OAuth2::Error.new(OAuth2::Response.new(fake_response)) }
  209. it_behaves_like "handles exceptions"
  210. end
  211. context "for Bitbucket errors" do
  212. let(:error) { Bitbucket::Error::Unauthorized.new("error") }
  213. it_behaves_like "handles exceptions"
  214. end
  215. end
  216. end
  217. context 'user has chosen an existing nested namespace and name for the project' do
  218. let(:parent_namespace) { create(:group, name: 'foo') }
  219. let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) }
  220. let(:test_name) { 'test_name' }
  221. before do
  222. parent_namespace.add_owner(user)
  223. nested_namespace.add_owner(user)
  224. end
  225. it 'takes the selected namespace and name' do
  226. expect(Gitlab::BitbucketImport::ProjectCreator)
  227. .to receive(:new).with(bitbucket_repo, test_name, nested_namespace, user, access_params)
  228. .and_return(double(execute: project))
  229. post :create, params: { target_namespace: nested_namespace.full_path, new_name: test_name }, format: :json
  230. end
  231. end
  232. context 'user has chosen a non-existent nested namespaces and name for the project' do
  233. let(:test_name) { 'test_name' }
  234. it 'takes the selected namespace and name' do
  235. expect(Gitlab::BitbucketImport::ProjectCreator)
  236. .to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
  237. .and_return(double(execute: project))
  238. post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json
  239. end
  240. it 'creates the namespaces' do
  241. allow(Gitlab::BitbucketImport::ProjectCreator)
  242. .to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
  243. .and_return(double(execute: project))
  244. expect { post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json }
  245. .to change { Namespace.count }.by(2)
  246. end
  247. it 'new namespace has the right parent' do
  248. allow(Gitlab::BitbucketImport::ProjectCreator)
  249. .to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
  250. .and_return(double(execute: project))
  251. post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json
  252. expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo')
  253. end
  254. end
  255. context 'user has chosen existent and non-existent nested namespaces and name for the project' do
  256. let(:test_name) { 'test_name' }
  257. let!(:parent_namespace) { create(:group, name: 'foo') }
  258. before do
  259. parent_namespace.add_owner(user)
  260. end
  261. it 'takes the selected namespace and name' do
  262. expect(Gitlab::BitbucketImport::ProjectCreator)
  263. .to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
  264. .and_return(double(execute: project))
  265. post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :json
  266. end
  267. it 'creates the namespaces' do
  268. allow(Gitlab::BitbucketImport::ProjectCreator)
  269. .to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
  270. .and_return(double(execute: project))
  271. expect { post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :json }
  272. .to change { Namespace.count }.by(2)
  273. end
  274. end
  275. context 'when user can not create projects in the chosen namespace' do
  276. it 'returns 422 response' do
  277. other_namespace = create(:group, name: 'other_namespace')
  278. post :create, params: { target_namespace: other_namespace.name }, format: :json
  279. expect(response).to have_gitlab_http_status(:unprocessable_entity)
  280. end
  281. end
  282. end
  283. end