diff options
author | Kamil Trzcinski <ayufan@ayufan.eu> | 2017-11-06 22:38:35 +0100 |
---|---|---|
committer | Kamil Trzcinski <ayufan@ayufan.eu> | 2017-11-06 22:38:35 +0100 |
commit | 7599009c2726bfdbd73da360961e4d8611641b02 (patch) | |
tree | 1578ea9216c4430e2d5d5043edc85f445716c28b /spec/models | |
parent | c708931a327edcc70b92be7fcddb84fbbe2c0394 (diff) | |
parent | 83c3c19ce5eb6a88cd9ed428fa0f8d68d5fa7167 (diff) | |
download | gitlab-ce-7599009c2726bfdbd73da360961e4d8611641b02.tar.gz |
Merge remote-tracking branch 'origin/move-kubernetes-from-service-to-clusters-page-10-2-ver' into 35616-move-gke-form-1st-iteration
Diffstat (limited to 'spec/models')
23 files changed, 1050 insertions, 371 deletions
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 41ecdb604f1..5ed2e1ca99a 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1271,6 +1271,7 @@ describe Ci::Build do { key: 'CI_PROJECT_PATH_SLUG', value: project.full_path_slug, public: true }, { key: 'CI_PROJECT_NAMESPACE', value: project.namespace.full_path, public: true }, { key: 'CI_PROJECT_URL', value: project.web_url, public: true }, + { key: 'CI_PROJECT_VISIBILITY', value: 'private', public: true }, { key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true }, { key: 'CI_CONFIG_PATH', value: pipeline.ci_yaml_file_path, public: true }, { key: 'CI_REGISTRY_USER', value: 'gitlab-ci-token', public: true }, diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb new file mode 100644 index 00000000000..12123a3d753 --- /dev/null +++ b/spec/models/clusters/cluster_spec.rb @@ -0,0 +1,181 @@ +require 'spec_helper' + +describe Clusters::Cluster do + it { is_expected.to belong_to(:user) } + it { is_expected.to have_many(:projects) } + it { is_expected.to have_one(:provider_gcp) } + it { is_expected.to have_one(:platform_kubernetes) } + it { is_expected.to delegate_method(:status).to(:provider) } + it { is_expected.to delegate_method(:status_reason).to(:provider) } + it { is_expected.to delegate_method(:status_name).to(:provider) } + it { is_expected.to delegate_method(:on_creation?).to(:provider) } + it { is_expected.to delegate_method(:update_kubernetes_integration!).to(:platform) } + it { is_expected.to respond_to :project } + + describe '.enabled' do + subject { described_class.enabled } + + let!(:cluster) { create(:cluster, enabled: true) } + + before do + create(:cluster, enabled: false) + end + + it { is_expected.to contain_exactly(cluster) } + end + + describe '.disabled' do + subject { described_class.disabled } + + let!(:cluster) { create(:cluster, enabled: false) } + + before do + create(:cluster, enabled: true) + end + + it { is_expected.to contain_exactly(cluster) } + end + + describe 'validation' do + subject { cluster.valid? } + + context 'when validates name' do + context 'when provided by user' do + let!(:cluster) { build(:cluster, :provided_by_user, name: name) } + + context 'when name is empty' do + let(:name) { '' } + + it { is_expected.to be_falsey } + end + + context 'when name is nil' do + let(:name) { nil } + + it { is_expected.to be_falsey } + end + + context 'when name is present' do + let(:name) { 'cluster-name-1' } + + it { is_expected.to be_truthy } + end + end + + context 'when provided by gcp' do + let!(:cluster) { build(:cluster, :provided_by_gcp, name: name) } + + context 'when name is shorter than 1' do + let(:name) { '' } + + it { is_expected.to be_falsey } + end + + context 'when name is longer than 63' do + let(:name) { 'a' * 64 } + + it { is_expected.to be_falsey } + end + + context 'when name includes invalid character' do + let(:name) { '!!!!!!' } + + it { is_expected.to be_falsey } + end + + context 'when name is present' do + let(:name) { 'cluster-name-1' } + + it { is_expected.to be_truthy } + end + + context 'when record is persisted' do + let(:name) { 'cluster-name-1' } + + before do + cluster.save! + end + + context 'when name is changed' do + before do + cluster.name = 'new-cluster-name' + end + + it { is_expected.to be_falsey } + end + + context 'when name is same' do + before do + cluster.name = name + end + + it { is_expected.to be_truthy } + end + end + end + end + + context 'when validates restrict_modification' do + context 'when creation is on going' do + let!(:cluster) { create(:cluster, :providing_by_gcp) } + + it { expect(cluster.update(enabled: false)).to be_falsey } + end + + context 'when creation is done' do + let!(:cluster) { create(:cluster, :provided_by_gcp) } + + it { expect(cluster.update(enabled: false)).to be_truthy } + end + end + end + + describe '#provider' do + subject { cluster.provider } + + context 'when provider is gcp' do + let(:cluster) { create(:cluster, :provided_by_gcp) } + + it 'returns a provider' do + is_expected.to eq(cluster.provider_gcp) + expect(subject.class.name.deconstantize).to eq(Clusters::Providers.to_s) + end + end + + context 'when provider is user' do + let(:cluster) { create(:cluster, :provided_by_user) } + + it { is_expected.to be_nil } + end + end + + describe '#platform' do + subject { cluster.platform } + + context 'when platform is kubernetes' do + let(:cluster) { create(:cluster, :provided_by_user) } + + it 'returns a platform' do + is_expected.to eq(cluster.platform_kubernetes) + expect(subject.class.name.deconstantize).to eq(Clusters::Platforms.to_s) + end + end + end + + describe '#first_project' do + subject { cluster.first_project } + + context 'when cluster belongs to a project' do + let(:cluster) { create(:cluster, :project) } + let(:project) { Clusters::Project.find_by_cluster_id(cluster.id).project } + + it { is_expected.to eq(project) } + end + + context 'when cluster does not belong to projects' do + let(:cluster) { create(:cluster) } + + it { is_expected.to be_nil } + end + end +end diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb new file mode 100644 index 00000000000..e6ebe079ceb --- /dev/null +++ b/spec/models/clusters/platforms/kubernetes_spec.rb @@ -0,0 +1,188 @@ +require 'spec_helper' + +describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching do + include KubernetesHelpers + include ReactiveCachingHelpers + + it { is_expected.to belong_to(:cluster) } + it { is_expected.to respond_to :ca_pem } + + describe 'before_validation' do + context 'when namespace includes upper case' do + let(:kubernetes) { create(:platform_kubernetes, :configured, namespace: namespace) } + let(:namespace) { 'ABC' } + + it 'converts to lower case' do + expect(kubernetes.namespace).to eq('abc') + end + end + end + + describe 'validation' do + subject { kubernetes.valid? } + + context 'when validates namespace' do + let(:kubernetes) { build(:platform_kubernetes, :configured, namespace: namespace) } + + context 'when namespace is blank' do + let(:namespace) { '' } + + it { is_expected.to be_truthy } + end + + context 'when namespace is longer than 63' do + let(:namespace) { 'a' * 64 } + + it { is_expected.to be_falsey } + end + + context 'when namespace includes invalid character' do + let(:namespace) { '!!!!!!' } + + it { is_expected.to be_falsey } + end + + context 'when namespace is vaild' do + let(:namespace) { 'namespace-123' } + + it { is_expected.to be_truthy } + end + end + + context 'when validates api_url' do + let(:kubernetes) { build(:platform_kubernetes, :configured) } + + before do + kubernetes.api_url = api_url + end + + context 'when api_url is invalid url' do + let(:api_url) { '!!!!!!' } + + it { expect(kubernetes.save).to be_falsey } + end + + context 'when api_url is nil' do + let(:api_url) { nil } + + it { expect(kubernetes.save).to be_falsey } + end + + context 'when api_url is valid url' do + let(:api_url) { 'https://111.111.111.111' } + + it { expect(kubernetes.save).to be_truthy } + end + end + + context 'when validates token' do + let(:kubernetes) { build(:platform_kubernetes, :configured) } + + before do + kubernetes.token = token + end + + context 'when token is nil' do + let(:token) { nil } + + it { expect(kubernetes.save).to be_falsey } + end + end + end + + describe 'after_save from Clusters::Cluster' do + context 'when platform_kubernetes is being cerated' do + let(:enabled) { true } + let(:project) { create(:project) } + let(:cluster) { build(:cluster, provider_type: :gcp, platform_type: :kubernetes, platform_kubernetes: platform, provider_gcp: provider, enabled: enabled, projects: [project]) } + let(:platform) { build(:platform_kubernetes, :configured) } + let(:provider) { build(:provider_gcp) } + let(:kubernetes_service) { project.kubernetes_service } + + it 'updates KubernetesService' do + cluster.save! + + expect(kubernetes_service.active).to eq(enabled) + expect(kubernetes_service.api_url).to eq(platform.api_url) + expect(kubernetes_service.namespace).to eq(platform.namespace) + expect(kubernetes_service.ca_pem).to eq(platform.ca_cert) + end + end + + context 'when platform_kubernetes has been created' do + let(:enabled) { false } + let!(:project) { create(:project) } + let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } + let(:platform) { cluster.platform } + let(:kubernetes_service) { project.kubernetes_service } + + it 'updates KubernetesService' do + cluster.update(enabled: enabled) + + expect(kubernetes_service.active).to eq(enabled) + end + end + + context 'when kubernetes_service has been configured without cluster integration' do + let!(:project) { create(:project) } + let(:cluster) { build(:cluster, provider_type: :gcp, platform_type: :kubernetes, platform_kubernetes: platform, provider_gcp: provider, projects: [project]) } + let(:platform) { build(:platform_kubernetes, :configured, api_url: 'https://111.111.111.111') } + let(:provider) { build(:provider_gcp) } + + before do + create(:kubernetes_service, project: project) + end + + it 'raises an error' do + expect { cluster.save! }.to raise_error('Kubernetes service already configured') + end + end + end + + describe '#actual_namespace' do + subject { kubernetes.actual_namespace } + + let!(:cluster) { create(:cluster, :project, platform_kubernetes: kubernetes) } + let(:project) { cluster.project } + let(:kubernetes) { create(:platform_kubernetes, :configured, namespace: namespace) } + + context 'when namespace is present' do + let(:namespace) { 'namespace-123' } + + it { is_expected.to eq(namespace) } + end + + context 'when namespace is not present' do + let(:namespace) { nil } + + it { is_expected.to eq("#{project.path}-#{project.id}") } + end + end + + describe '.namespace_for_project' do + subject { described_class.namespace_for_project(project) } + + let(:project) { create(:project) } + + it { is_expected.to eq("#{project.path}-#{project.id}") } + end + + describe '#default_namespace' do + subject { kubernetes.default_namespace } + + let(:kubernetes) { create(:platform_kubernetes, :configured) } + + context 'when cluster belongs to a project' do + let!(:cluster) { create(:cluster, :project, platform_kubernetes: kubernetes) } + let(:project) { cluster.project } + + it { is_expected.to eq("#{project.path}-#{project.id}") } + end + + context 'when cluster belongs to nothing' do + let!(:cluster) { create(:cluster, platform_kubernetes: kubernetes) } + + it { is_expected.to be_nil } + end + end +end diff --git a/spec/models/clusters/project_spec.rb b/spec/models/clusters/project_spec.rb new file mode 100644 index 00000000000..7d75d6ab345 --- /dev/null +++ b/spec/models/clusters/project_spec.rb @@ -0,0 +1,6 @@ +require 'spec_helper' + +describe Clusters::Project do + it { is_expected.to belong_to(:cluster) } + it { is_expected.to belong_to(:project) } +end diff --git a/spec/models/clusters/providers/gcp_spec.rb b/spec/models/clusters/providers/gcp_spec.rb new file mode 100644 index 00000000000..99eb8c46e9a --- /dev/null +++ b/spec/models/clusters/providers/gcp_spec.rb @@ -0,0 +1,183 @@ +require 'spec_helper' + +describe Clusters::Providers::Gcp do + it { is_expected.to belong_to(:cluster) } + it { is_expected.to validate_presence_of(:zone) } + + describe 'default_value_for' do + let(:gcp) { build(:provider_gcp) } + + it "has default value" do + expect(gcp.zone).to eq('us-central1-a') + expect(gcp.num_nodes).to eq(3) + expect(gcp.machine_type).to eq('n1-standard-4') + end + end + + describe 'validation' do + subject { gcp.valid? } + + context 'when validates gcp_project_id' do + let(:gcp) { build(:provider_gcp, gcp_project_id: gcp_project_id) } + + context 'when gcp_project_id is shorter than 1' do + let(:gcp_project_id) { '' } + + it { is_expected.to be_falsey } + end + + context 'when gcp_project_id is longer than 63' do + let(:gcp_project_id) { 'a' * 64 } + + it { is_expected.to be_falsey } + end + + context 'when gcp_project_id includes invalid character' do + let(:gcp_project_id) { '!!!!!!' } + + it { is_expected.to be_falsey } + end + + context 'when gcp_project_id is valid' do + let(:gcp_project_id) { 'gcp-project-1' } + + it { is_expected.to be_truthy } + end + end + + context 'when validates num_nodes' do + let(:gcp) { build(:provider_gcp, num_nodes: num_nodes) } + + context 'when num_nodes is string' do + let(:num_nodes) { 'A3' } + + it { is_expected.to be_falsey } + end + + context 'when num_nodes is nil' do + let(:num_nodes) { nil } + + it { is_expected.to be_falsey } + end + + context 'when num_nodes is smaller than 1' do + let(:num_nodes) { 0 } + + it { is_expected.to be_falsey } + end + + context 'when num_nodes is valid' do + let(:num_nodes) { 3 } + + it { is_expected.to be_truthy } + end + end + end + + describe '#state_machine' do + context 'when any => [:created]' do + let(:gcp) { build(:provider_gcp, :creating) } + + before do + gcp.make_created + end + + it 'nullify access_token and operation_id' do + expect(gcp.access_token).to be_nil + expect(gcp.operation_id).to be_nil + expect(gcp).to be_created + end + end + + context 'when any => [:creating]' do + let(:gcp) { build(:provider_gcp) } + + context 'when operation_id is present' do + let(:operation_id) { 'operation-xxx' } + + before do + gcp.make_creating(operation_id) + end + + it 'sets operation_id' do + expect(gcp.operation_id).to eq(operation_id) + expect(gcp).to be_creating + end + end + + context 'when operation_id is nil' do + let(:operation_id) { nil } + + it 'raises an error' do + expect { gcp.make_creating(operation_id) } + .to raise_error('operation_id is required') + end + end + end + + context 'when any => [:errored]' do + let(:gcp) { build(:provider_gcp, :creating) } + let(:status_reason) { 'err msg' } + + it 'nullify access_token and operation_id' do + gcp.make_errored(status_reason) + + expect(gcp.access_token).to be_nil + expect(gcp.operation_id).to be_nil + expect(gcp.status_reason).to eq(status_reason) + expect(gcp).to be_errored + end + + context 'when status_reason is nil' do + let(:gcp) { build(:provider_gcp, :errored) } + + it 'does not set status_reason' do + gcp.make_errored(nil) + + expect(gcp.status_reason).not_to be_nil + end + end + end + end + + describe '#on_creation?' do + subject { gcp.on_creation? } + + context 'when status is creating' do + let(:gcp) { create(:provider_gcp, :creating) } + + it { is_expected.to be_truthy } + end + + context 'when status is created' do + let(:gcp) { create(:provider_gcp, :created) } + + it { is_expected.to be_falsey } + end + end + + describe '#api_client' do + subject { gcp.api_client } + + context 'when status is creating' do + let(:gcp) { build(:provider_gcp, :creating) } + + it 'returns Cloud Platform API clinet' do + expect(subject).to be_an_instance_of(GoogleApi::CloudPlatform::Client) + expect(subject.access_token).to eq(gcp.access_token) + end + end + + context 'when status is created' do + let(:gcp) { build(:provider_gcp, :created) } + + it { is_expected.to be_nil } + end + + context 'when status is errored' do + let(:gcp) { build(:provider_gcp, :errored) } + + it { is_expected.to be_nil } + end + end +end diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index ab8773b7ede..3106207811a 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -134,6 +134,7 @@ describe Group, 'Routable' do context 'with RequestStore active', :request_store do it 'does not load the route table more than once' do + group.expires_full_path_cache expect(group).to receive(:uncached_full_path).once.and_call_original 3.times { group.full_path } diff --git a/spec/models/concerns/subscribable_spec.rb b/spec/models/concerns/subscribable_spec.rb index 28ff8158e0e..45dfb136aea 100644 --- a/spec/models/concerns/subscribable_spec.rb +++ b/spec/models/concerns/subscribable_spec.rb @@ -6,6 +6,12 @@ describe Subscribable, 'Subscribable' do let(:user_1) { create(:user) } describe '#subscribed?' do + context 'without user' do + it 'returns false' do + expect(resource.subscribed?(nil, project)).to be_falsey + end + end + context 'without project' do it 'returns false when no subscription exists' do expect(resource.subscribed?(user_1)).to be_falsey diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb index 882afeccfc6..dfb83578fce 100644 --- a/spec/models/concerns/token_authenticatable_spec.rb +++ b/spec/models/concerns/token_authenticatable_spec.rb @@ -12,7 +12,7 @@ shared_examples 'TokenAuthenticatable' do end describe User, 'TokenAuthenticatable' do - let(:token_field) { :authentication_token } + let(:token_field) { :rss_token } it_behaves_like 'TokenAuthenticatable' describe 'ensures authentication token' do diff --git a/spec/models/email_spec.rb b/spec/models/email_spec.rb index b32dd31ae6d..47eb0717c0c 100644 --- a/spec/models/email_spec.rb +++ b/spec/models/email_spec.rb @@ -40,4 +40,12 @@ describe Email do expect(user.emails.confirmed.count).to eq 1 end end + + describe 'delegation' do + let(:user) { create(:user) } + + it 'delegates to :user' do + expect(build(:email, user: user).username).to eq user.username + end + end end diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index e1be23541e8..1ce1d595c60 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -18,7 +18,6 @@ describe Environment do it { is_expected.to validate_length_of(:slug).is_at_most(24) } it { is_expected.to validate_length_of(:external_url).is_at_most(255) } - it { is_expected.to validate_uniqueness_of(:external_url).scoped_to(:project_id) } describe '.order_by_last_deployed_at' do let(:project) { create(:project, :repository) } @@ -547,6 +546,15 @@ describe Environment do expect(environment.slug).to eq(original_slug) end + + it "regenerates the slug if nil" do + environment = build(:environment, slug: nil) + + new_slug = environment.slug + + expect(new_slug).not_to be_nil + expect(environment.slug).to eq(new_slug) + end end describe '#generate_slug' do @@ -583,6 +591,12 @@ describe Environment do it 'returns a path that uses the slug and does not have spaces' do expect(environment.ref_path).to start_with('refs/environments/staging-review-1-') end + + it "doesn't change when the slug is nil initially" do + environment.slug = nil + + expect(environment.ref_path).to eq(environment.ref_path) + end end describe '#external_url_for' do diff --git a/spec/models/fork_network_spec.rb b/spec/models/fork_network_spec.rb index 605ccd6db06..a43baf1820a 100644 --- a/spec/models/fork_network_spec.rb +++ b/spec/models/fork_network_spec.rb @@ -24,6 +24,16 @@ describe ForkNetwork do end end + describe '#merge_requests' do + it 'finds merge requests within the fork network' do + project = create(:project) + forked_project = fork_project(project) + merge_request = create(:merge_request, source_project: forked_project, target_project: project) + + expect(project.fork_network.merge_requests).to include(merge_request) + end + end + context 'for a deleted project' do it 'keeps the fork network' do project = create(:project, :public) diff --git a/spec/models/gcp/cluster_spec.rb b/spec/models/gcp/cluster_spec.rb deleted file mode 100644 index 8f39fff6394..00000000000 --- a/spec/models/gcp/cluster_spec.rb +++ /dev/null @@ -1,264 +0,0 @@ -require 'spec_helper' - -describe Gcp::Cluster do - it { is_expected.to belong_to(:project) } - it { is_expected.to belong_to(:user) } - it { is_expected.to belong_to(:service) } - - it { is_expected.to validate_presence_of(:gcp_cluster_zone) } - - describe '.enabled' do - subject { described_class.enabled } - - let!(:cluster) { create(:gcp_cluster, enabled: true) } - - before do - create(:gcp_cluster, enabled: false) - end - - it { is_expected.to contain_exactly(cluster) } - end - - describe '.disabled' do - subject { described_class.disabled } - - let!(:cluster) { create(:gcp_cluster, enabled: false) } - - before do - create(:gcp_cluster, enabled: true) - end - - it { is_expected.to contain_exactly(cluster) } - end - - describe '#default_value_for' do - let(:cluster) { described_class.new } - - it { expect(cluster.gcp_cluster_zone).to eq('us-central1-a') } - it { expect(cluster.gcp_cluster_size).to eq(3) } - it { expect(cluster.gcp_machine_type).to eq('n1-standard-4') } - end - - describe '#validates' do - subject { cluster.valid? } - - context 'when validates gcp_project_id' do - let(:cluster) { build(:gcp_cluster, gcp_project_id: gcp_project_id) } - - context 'when valid' do - let(:gcp_project_id) { 'gcp-project-12345' } - - it { is_expected.to be_truthy } - end - - context 'when empty' do - let(:gcp_project_id) { '' } - - it { is_expected.to be_falsey } - end - - context 'when too long' do - let(:gcp_project_id) { 'A' * 64 } - - it { is_expected.to be_falsey } - end - - context 'when includes abnormal character' do - let(:gcp_project_id) { '!!!!!!' } - - it { is_expected.to be_falsey } - end - end - - context 'when validates gcp_cluster_name' do - let(:cluster) { build(:gcp_cluster, gcp_cluster_name: gcp_cluster_name) } - - context 'when valid' do - let(:gcp_cluster_name) { 'test-cluster' } - - it { is_expected.to be_truthy } - end - - context 'when empty' do - let(:gcp_cluster_name) { '' } - - it { is_expected.to be_falsey } - end - - context 'when too long' do - let(:gcp_cluster_name) { 'A' * 64 } - - it { is_expected.to be_falsey } - end - - context 'when includes abnormal character' do - let(:gcp_cluster_name) { '!!!!!!' } - - it { is_expected.to be_falsey } - end - end - - context 'when validates gcp_cluster_size' do - let(:cluster) { build(:gcp_cluster, gcp_cluster_size: gcp_cluster_size) } - - context 'when valid' do - let(:gcp_cluster_size) { 1 } - - it { is_expected.to be_truthy } - end - - context 'when zero' do - let(:gcp_cluster_size) { 0 } - - it { is_expected.to be_falsey } - end - end - - context 'when validates project_namespace' do - let(:cluster) { build(:gcp_cluster, project_namespace: project_namespace) } - - context 'when valid' do - let(:project_namespace) { 'default-namespace' } - - it { is_expected.to be_truthy } - end - - context 'when empty' do - let(:project_namespace) { '' } - - it { is_expected.to be_truthy } - end - - context 'when too long' do - let(:project_namespace) { 'A' * 64 } - - it { is_expected.to be_falsey } - end - - context 'when includes abnormal character' do - let(:project_namespace) { '!!!!!!' } - - it { is_expected.to be_falsey } - end - end - - context 'when validates restrict_modification' do - let(:cluster) { create(:gcp_cluster) } - - before do - cluster.make_creating! - end - - context 'when created' do - before do - cluster.make_created! - end - - it { is_expected.to be_truthy } - end - - context 'when creating' do - it { is_expected.to be_falsey } - end - end - end - - describe '#state_machine' do - let(:cluster) { build(:gcp_cluster) } - - context 'when transits to created state' do - before do - cluster.gcp_token = 'tmp' - cluster.gcp_operation_id = 'tmp' - cluster.make_created! - end - - it 'nullify gcp_token and gcp_operation_id' do - expect(cluster.gcp_token).to be_nil - expect(cluster.gcp_operation_id).to be_nil - expect(cluster).to be_created - end - end - - context 'when transits to errored state' do - let(:reason) { 'something wrong' } - - before do - cluster.make_errored!(reason) - end - - it 'sets status_reason' do - expect(cluster.status_reason).to eq(reason) - expect(cluster).to be_errored - end - end - end - - describe '#project_namespace_placeholder' do - subject { cluster.project_namespace_placeholder } - - let(:cluster) { create(:gcp_cluster) } - - it 'returns a placeholder' do - is_expected.to eq("#{cluster.project.path}-#{cluster.project.id}") - end - end - - describe '#on_creation?' do - subject { cluster.on_creation? } - - let(:cluster) { create(:gcp_cluster) } - - context 'when status is creating' do - before do - cluster.make_creating! - end - - it { is_expected.to be_truthy } - end - - context 'when status is created' do - before do - cluster.make_created! - end - - it { is_expected.to be_falsey } - end - end - - describe '#api_url' do - subject { cluster.api_url } - - let(:cluster) { create(:gcp_cluster, :created_on_gke) } - let(:api_url) { 'https://' + cluster.endpoint } - - it { is_expected.to eq(api_url) } - end - - describe '#restrict_modification' do - subject { cluster.restrict_modification } - - let(:cluster) { create(:gcp_cluster) } - - context 'when status is created' do - before do - cluster.make_created! - end - - it { is_expected.to be_truthy } - end - - context 'when status is creating' do - before do - cluster.make_creating! - end - - it { is_expected.to be_falsey } - - it 'sets error' do - is_expected.to be_falsey - expect(cluster.errors).not_to be_empty - end - end - end -end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index f36d6eeb327..0e1a7fdce0b 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -488,6 +488,47 @@ describe Group do end end + describe '#path_changed_hook' do + let(:system_hook_service) { SystemHooksService.new } + + context 'for a new group' do + let(:group) { build(:group) } + + before do + expect(group).to receive(:system_hook_service).and_return(system_hook_service) + end + + it 'does not trigger system hook' do + expect(system_hook_service).to receive(:execute_hooks_for).with(group, :create) + + group.save! + end + end + + context 'for an existing group' do + let(:group) { create(:group, path: 'old-path') } + + context 'when the path is changed' do + let(:new_path) { 'very-new-path' } + + it 'triggers the rename system hook' do + expect(group).to receive(:system_hook_service).and_return(system_hook_service) + expect(system_hook_service).to receive(:execute_hooks_for).with(group, :rename) + + group.update_attributes!(path: new_path) + end + end + + context 'when the path is not changed' do + it 'does not trigger system hook' do + expect(group).not_to receive(:system_hook_service) + + group.update_attributes!(name: 'new name') + end + end + end + end + describe '#secret_variables_for' do let(:project) { create(:project, group: group) } diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb index 4ca6556d0f4..3ed048744de 100644 --- a/spec/models/identity_spec.rb +++ b/spec/models/identity_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe Identity do +describe Identity do describe 'relations' do it { is_expected.to belong_to(:user) } end @@ -22,4 +22,16 @@ RSpec.describe Identity do expect(other_identity.ldap?).to be_falsey end end + + describe '.with_extern_uid' do + context 'LDAP identity' do + let!(:ldap_identity) { create(:identity, provider: 'ldapmain', extern_uid: 'uid=john smith,ou=people,dc=example,dc=com') } + + it 'finds the identity when the DN is formatted differently' do + identity = described_class.with_extern_uid('ldapmain', 'uid=John Smith, ou=People, dc=example, dc=com').first + + expect(identity).to eq(ldap_identity) + end + end + end end diff --git a/spec/models/merge_request_diff_commit_spec.rb b/spec/models/merge_request_diff_commit_spec.rb index 9d4a0ecf8c0..7709cf43200 100644 --- a/spec/models/merge_request_diff_commit_spec.rb +++ b/spec/models/merge_request_diff_commit_spec.rb @@ -2,14 +2,93 @@ require 'rails_helper' describe MergeRequestDiffCommit do let(:merge_request) { create(:merge_request) } - subject { merge_request.commits.first } + let(:project) { merge_request.project } describe '#to_hash' do + subject { merge_request.commits.first } + it 'returns the same results as Commit#to_hash, except for parent_ids' do - commit_from_repo = merge_request.project.repository.commit(subject.sha) + commit_from_repo = project.repository.commit(subject.sha) commit_from_repo_hash = commit_from_repo.to_hash.merge(parent_ids: []) expect(subject.to_hash).to eq(commit_from_repo_hash) end end + + describe '.create_bulk' do + let(:sha_attribute) { Gitlab::Database::ShaAttribute.new } + let(:merge_request_diff_id) { merge_request.merge_request_diff.id } + let(:commits) do + [ + project.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e'), + project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') + ] + end + let(:rows) do + [ + { + "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "authored_date": "2014-02-27T10:01:38.000+01:00".to_time, + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T10:01:38.000+01:00".to_time, + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com", + "merge_request_diff_id": merge_request_diff_id, + "relative_order": 0, + "sha": sha_attribute.type_cast_for_database('5937ac0a7beb003549fc5fd26fc247adbce4a52e') + }, + { + "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "authored_date": "2014-02-27T09:57:31.000+01:00".to_time, + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T09:57:31.000+01:00".to_time, + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com", + "merge_request_diff_id": merge_request_diff_id, + "relative_order": 1, + "sha": sha_attribute.type_cast_for_database('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') + } + ] + end + + subject { described_class.create_bulk(merge_request_diff_id, commits) } + + it 'inserts the commits into the database en masse' do + expect(Gitlab::Database).to receive(:bulk_insert) + .with(described_class.table_name, rows) + + subject + end + + context 'with dates larger than the DB limit' do + let(:commits) do + # This commit's date is "Sun Aug 17 07:12:55 292278994 +0000" + [project.commit('ba3343bc4fa403a8dfbfcab7fc1a8c29ee34bd69')] + end + let(:timestamp) { Time.at((1 << 31) - 1) } + let(:rows) do + [{ + "message": "Weird commit date\n", + "authored_date": timestamp, + "author_name": "Alejandro RodrÃguez", + "author_email": "alejorro70@gmail.com", + "committed_date": timestamp, + "committer_name": "Alejandro RodrÃguez", + "committer_email": "alejorro70@gmail.com", + "merge_request_diff_id": merge_request_diff_id, + "relative_order": 0, + "sha": sha_attribute.type_cast_for_database('ba3343bc4fa403a8dfbfcab7fc1a8c29ee34bd69') + }] + end + + it 'uses a sanitized date' do + expect(Gitlab::Database).to receive(:bulk_insert) + .with(described_class.table_name, rows) + + subject + end + end + end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 73e038b61ed..476a2697605 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -86,7 +86,7 @@ describe MergeRequest do context 'when the target branch does not exist' do before do - project.repository.raw_repository.delete_branch(subject.target_branch) + project.repository.rm_branch(subject.author, subject.target_branch) end it 'returns nil' do @@ -1388,7 +1388,7 @@ describe MergeRequest do context 'when the target branch does not exist' do before do - subject.project.repository.raw_repository.delete_branch(subject.target_branch) + subject.project.repository.rm_branch(subject.author, subject.target_branch) end it 'returns nil' do @@ -1460,6 +1460,12 @@ describe MergeRequest do end describe '#merge_ongoing?' do + it 'returns true when the merge request is locked' do + merge_request = build_stubbed(:merge_request, state: :locked) + + expect(merge_request.merge_ongoing?).to be(true) + end + it 'returns true when merge_id, MR is not merged and it has no running job' do merge_request = build_stubbed(:merge_request, state: :open, merge_jid: 'foo') allow(Gitlab::SidekiqStatus).to receive(:running?).with('foo') { true } diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 2298dcab55f..7617e1f89b1 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -99,45 +99,34 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do describe '#actual_namespace' do subject { service.actual_namespace } - it "returns the default namespace" do - is_expected.to eq(service.send(:default_namespace)) - end - - context 'when namespace is specified' do - before do - service.namespace = 'my-namespace' + shared_examples 'a correctly formatted namespace' do + it 'returns a valid Kubernetes namespace name' do + expect(subject).to match(Gitlab::Regex.kubernetes_namespace_regex) + expect(subject).to eq(expected_namespace) end + end - it "returns the user-namespace" do - is_expected.to eq('my-namespace') - end + it_behaves_like 'a correctly formatted namespace' do + let(:expected_namespace) { service.send(:default_namespace) } end - context 'when service is not assigned to project' do + context 'when the project path contains forbidden characters' do before do - service.project = nil + project.path = '-a_Strange.Path--forSure' end - it "does not return namespace" do - is_expected.to be_nil + it_behaves_like 'a correctly formatted namespace' do + let(:expected_namespace) { "a-strange-path--forsure-#{project.id}" } end end - end - - describe '#actual_namespace' do - subject { service.actual_namespace } - - it "returns the default namespace" do - is_expected.to eq(service.send(:default_namespace)) - end context 'when namespace is specified' do before do service.namespace = 'my-namespace' end - it "returns the user-namespace" do - is_expected.to eq('my-namespace') + it_behaves_like 'a correctly formatted namespace' do + let(:expected_namespace) { 'my-namespace' } end end @@ -146,7 +135,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do service.project = nil end - it "does not return namespace" do + it 'does not return namespace' do is_expected.to be_nil end end @@ -156,7 +145,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do let(:discovery_url) { 'https://kubernetes.example.com/api/v1' } before do - stub_kubeclient_discover + stub_kubeclient_discover(service.api_url) end context 'with path prefix in api_url' do @@ -164,7 +153,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do it 'tests with the prefix' do service.api_url = 'https://kubernetes.example.com/prefix' - stub_kubeclient_discover + stub_kubeclient_discover(service.api_url) expect(service.test[:success]).to be_truthy expect(WebMock).to have_requested(:get, discovery_url).once diff --git a/spec/models/project_services/packagist_service_spec.rb b/spec/models/project_services/packagist_service_spec.rb new file mode 100644 index 00000000000..6acee311700 --- /dev/null +++ b/spec/models/project_services/packagist_service_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe PackagistService do + describe "Associations" do + it { is_expected.to belong_to :project } + it { is_expected.to have_one :service_hook } + end + + let(:project) { create(:project) } + + let(:packagist_server) { 'https://packagist.example.com' } + let(:packagist_username) { 'theUser' } + let(:packagist_token) { 'verySecret' } + let(:packagist_hook_url) do + "#{packagist_server}/api/update-package?username=#{packagist_username}&apiToken=#{packagist_token}" + end + + let(:packagist_params) do + { + active: true, + project: project, + properties: { + username: packagist_username, + token: packagist_token, + server: packagist_server + } + } + end + + describe '#execute' do + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } + let(:push_sample_data) { Gitlab::DataBuilder::Push.build_sample(project, user) } + let(:packagist_service) { described_class.create(packagist_params) } + + before do + stub_request(:post, packagist_hook_url) + end + + it 'calls Packagist API' do + packagist_service.execute(push_sample_data) + + expect(a_request(:post, packagist_hook_url)).to have_been_made.once + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 74eba7e33f6..e8588975118 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -24,6 +24,7 @@ describe Project do it { is_expected.to have_one(:slack_service) } it { is_expected.to have_one(:microsoft_teams_service) } it { is_expected.to have_one(:mattermost_service) } + it { is_expected.to have_one(:packagist_service) } it { is_expected.to have_one(:pushover_service) } it { is_expected.to have_one(:asana_service) } it { is_expected.to have_many(:boards) } @@ -1922,6 +1923,20 @@ describe Project do expect(forked_project.in_fork_network_of?(other_project)).to be_falsy end end + + describe '#fork_source' do + let!(:second_fork) { fork_project(forked_project) } + + it 'returns the direct source if it exists' do + expect(second_fork.fork_source).to eq(forked_project) + end + + it 'returns the root of the fork network when the directs source was deleted' do + forked_project.destroy + + expect(second_fork.fork_source).to eq(project) + end + end end describe '#pushes_since_gc' do @@ -2452,6 +2467,7 @@ describe Project do context 'legacy storage' do let(:project) { create(:project, :repository) } let(:gitlab_shell) { Gitlab::Shell.new } + let(:project_storage) { project.send(:storage) } before do allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) @@ -2493,7 +2509,7 @@ describe Project do describe '#hashed_storage?' do it 'returns false' do - expect(project.hashed_storage?).to be_falsey + expect(project.hashed_storage?(:repository)).to be_falsey end end @@ -2546,6 +2562,30 @@ describe Project do it { expect { subject }.to raise_error(StandardError) } end + + context 'gitlab pages' do + before do + expect(project_storage).to receive(:rename_repo) { true } + end + + it 'moves pages folder to new location' do + expect_any_instance_of(Gitlab::PagesTransfer).to receive(:rename_project) + + project.rename_repo + end + end + + context 'attachments' do + before do + expect(project_storage).to receive(:rename_repo) { true } + end + + it 'moves uploads folder to new location' do + expect_any_instance_of(Gitlab::UploadsTransfer).to receive(:rename_project) + + project.rename_repo + end + end end describe '#pages_path' do @@ -2605,8 +2645,14 @@ describe Project do end describe '#hashed_storage?' do - it 'returns true' do - expect(project.hashed_storage?).to be_truthy + it 'returns true if rolled out' do + expect(project.hashed_storage?(:attachments)).to be_truthy + end + + it 'returns false when not rolled out yet' do + project.storage_version = 1 + + expect(project.hashed_storage?(:attachments)).to be_falsey end end @@ -2649,10 +2695,6 @@ describe Project do .to receive(:execute_hooks_for) .with(project, :rename) - expect_any_instance_of(Gitlab::UploadsTransfer) - .to receive(:rename_project) - .with('foo', project.path, project.namespace.full_path) - expect(project).to receive(:expire_caches_before_rename) expect(project).to receive(:expires_full_path_cache) @@ -2673,6 +2715,32 @@ describe Project do it { expect { subject }.to raise_error(StandardError) } end + + context 'gitlab pages' do + it 'moves pages folder to new location' do + expect_any_instance_of(Gitlab::PagesTransfer).to receive(:rename_project) + + project.rename_repo + end + end + + context 'attachments' do + it 'keeps uploads folder location unchanged' do + expect_any_instance_of(Gitlab::UploadsTransfer).not_to receive(:rename_project) + + project.rename_repo + end + + context 'when not rolled out' do + let(:project) { create(:project, :repository, storage_version: 1) } + + it 'moves pages folder to new location' do + expect_any_instance_of(Gitlab::UploadsTransfer).to receive(:rename_project) + + project.rename_repo + end + end + end end describe '#pages_path' do diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index f10d9383ae2..3d46434fc27 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -117,65 +117,74 @@ describe ProjectWiki do end describe "#find_page" do - before do - create_page("index page", "This is an awesome Gollum Wiki") - end + shared_examples 'finding a wiki page' do + before do + create_page("index page", "This is an awesome Gollum Wiki") + end - after do - destroy_page(subject.pages.first.page) - end + after do + destroy_page(subject.pages.first.page) + end - it "returns the latest version of the page if it exists" do - page = subject.find_page("index page") - expect(page.title).to eq("index page") - end + it "returns the latest version of the page if it exists" do + page = subject.find_page("index page") + expect(page.title).to eq("index page") + end - it "returns nil if the page does not exist" do - expect(subject.find_page("non-existant")).to eq(nil) + it "returns nil if the page does not exist" do + expect(subject.find_page("non-existant")).to eq(nil) + end + + it "can find a page by slug" do + page = subject.find_page("index-page") + expect(page.title).to eq("index page") + end + + it "returns a WikiPage instance" do + page = subject.find_page("index page") + expect(page).to be_a WikiPage + end end - it "can find a page by slug" do - page = subject.find_page("index-page") - expect(page.title).to eq("index page") + context 'when Gitaly wiki_find_page is enabled' do + it_behaves_like 'finding a wiki page' end - it "returns a WikiPage instance" do - page = subject.find_page("index page") - expect(page).to be_a WikiPage + context 'when Gitaly wiki_find_page is disabled', :skip_gitaly_mock do + it_behaves_like 'finding a wiki page' end end describe '#find_file' do - before do - file = Gollum::File.new(subject.wiki) - allow_any_instance_of(Gollum::Wiki) - .to receive(:file).with('image.jpg', 'master') - .and_return(file) - allow_any_instance_of(Gollum::File) - .to receive(:mime_type) - .and_return('image/jpeg') - allow_any_instance_of(Gollum::Wiki) - .to receive(:file).with('non-existant', 'master') - .and_return(nil) - end + shared_examples 'finding a wiki file' do + before do + file = File.open(Rails.root.join('spec', 'fixtures', 'dk.png')) + subject.wiki # Make sure the wiki repo exists - after do - allow_any_instance_of(Gollum::Wiki).to receive(:file).and_call_original - allow_any_instance_of(Gollum::File).to receive(:mime_type).and_call_original - end + BareRepoOperations.new(subject.repository.path_to_repo).commit_file(file, 'image.png') + end + + it 'returns the latest version of the file if it exists' do + file = subject.find_file('image.png') + expect(file.mime_type).to eq('image/png') + end + + it 'returns nil if the page does not exist' do + expect(subject.find_file('non-existant')).to eq(nil) + end - it 'returns the latest version of the file if it exists' do - file = subject.find_file('image.jpg') - expect(file.mime_type).to eq('image/jpeg') + it 'returns a Gitlab::Git::WikiFile instance' do + file = subject.find_file('image.png') + expect(file).to be_a Gitlab::Git::WikiFile + end end - it 'returns nil if the page does not exist' do - expect(subject.find_file('non-existant')).to eq(nil) + context 'when Gitaly wiki_find_file is enabled' do + it_behaves_like 'finding a wiki file' end - it 'returns a Gitlab::Git::WikiFile instance' do - file = subject.find_file('image.jpg') - expect(file).to be_a Gitlab::Git::WikiFile + context 'when Gitaly wiki_find_file is disabled', :skip_gitaly_mock do + it_behaves_like 'finding a wiki file' end end @@ -265,23 +274,33 @@ describe ProjectWiki do end describe "#delete_page" do - before do - create_page("index", "some content") - @page = subject.wiki.page(title: "index") - end + shared_examples 'deleting a wiki page' do + before do + create_page("index", "some content") + @page = subject.wiki.page(title: "index") + end - it "deletes the page" do - subject.delete_page(@page) - expect(subject.pages.count).to eq(0) - end + it "deletes the page" do + subject.delete_page(@page) + expect(subject.pages.count).to eq(0) + end - it 'updates project activity' do - subject.delete_page(@page) + it 'updates project activity' do + subject.delete_page(@page) - project.reload + project.reload - expect(project.last_activity_at).to be_within(1.minute).of(Time.now) - expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now) + expect(project.last_activity_at).to be_within(1.minute).of(Time.now) + expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now) + end + end + + context 'when Gitaly wiki_delete_page is enabled' do + it_behaves_like 'deleting a wiki page' + end + + context 'when Gitaly wiki_delete_page is disabled', :skip_gitaly_mock do + it_behaves_like 'deleting a wiki page' end end @@ -343,6 +362,6 @@ describe ProjectWiki do end def destroy_page(page) - subject.delete_page(page, commit_details) + subject.delete_page(page, "test commit") end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 874368ada67..8a6aa767ce6 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -299,6 +299,24 @@ describe Repository do it { is_expected.to be_falsey } end + + context 'when pre-loaded merged branches are provided' do + using RSpec::Parameterized::TableSyntax + + where(:branch, :pre_loaded, :expected) do + 'not-merged-branch' | ['branch-merged'] | false + 'branch-merged' | ['not-merged-branch'] | false + 'branch-merged' | ['branch-merged'] | true + 'not-merged-branch' | ['not-merged-branch'] | false + 'master' | ['master'] | false + end + + with_them do + subject { repository.merged_to_root_ref?(branch, pre_loaded) } + + it { is_expected.to eq(expected) } + end + end end describe '#can_be_merged?' do @@ -2260,4 +2278,44 @@ describe Repository do end end end + + describe 'commit cache' do + set(:project) { create(:project, :repository) } + + it 'caches based on SHA' do + # Gets the commit oid, and warms the cache + oid = project.commit.id + + expect(Gitlab::Git::Commit).not_to receive(:find).once + + project.commit_by(oid: oid) + end + + it 'caches nil values' do + expect(Gitlab::Git::Commit).to receive(:find).once + + project.commit_by(oid: '1' * 40) + project.commit_by(oid: '1' * 40) + end + end + + describe '#raw_repository' do + subject { repository.raw_repository } + + it 'returns a Gitlab::Git::Repository representation of the repository' do + expect(subject).to be_a(Gitlab::Git::Repository) + expect(subject.relative_path).to eq(project.disk_path + '.git') + expect(subject.gl_repository).to eq("project-#{project.id}") + end + + context 'with a wiki repository' do + let(:repository) { project.wiki.repository } + + it 'creates a Gitlab::Git::Repository with the proper attributes' do + expect(subject).to be_a(Gitlab::Git::Repository) + expect(subject.relative_path).to eq(project.disk_path + '.wiki.git') + expect(subject.gl_repository).to eq("wiki-#{project.id}") + end + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 1c3c9068f12..e0896d64c8f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -346,7 +346,6 @@ describe User do describe "Respond to" do it { is_expected.to respond_to(:admin?) } it { is_expected.to respond_to(:name) } - it { is_expected.to respond_to(:private_token) } it { is_expected.to respond_to(:external?) } end @@ -526,14 +525,6 @@ describe User do end end - describe 'authentication token' do - it "has authentication token" do - user = create(:user) - - expect(user.authentication_token).not_to be_blank - end - end - describe 'ensure incoming email token' do it 'has incoming email token' do user = create(:user) @@ -2226,6 +2217,42 @@ describe User do end end + describe '#username_changed_hook' do + context 'for a new user' do + let(:user) { build(:user) } + + it 'does not trigger system hook' do + expect(user).not_to receive(:system_hook_service) + + user.save! + end + end + + context 'for an existing user' do + let(:user) { create(:user, username: 'old-username') } + + context 'when the username is changed' do + let(:new_username) { 'very-new-name' } + + it 'triggers the rename system hook' do + system_hook_service = SystemHooksService.new + expect(system_hook_service).to receive(:execute_hooks_for).with(user, :rename) + expect(user).to receive(:system_hook_service).and_return(system_hook_service) + + user.update_attributes!(username: new_username) + end + end + + context 'when the username is not changed' do + it 'does not trigger system hook' do + expect(user).not_to receive(:system_hook_service) + + user.update_attributes!(email: 'asdf@asdf.com') + end + end + end + end + describe '#sync_attribute?' do let(:user) { described_class.new } diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 1f14d06997e..a7227b38850 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -402,7 +402,7 @@ describe WikiPage do def destroy_page(title) page = wiki.wiki.page(title: title) - wiki.delete_page(page, commit_details) + wiki.delete_page(page, "test commit") end def get_slugs(page_or_dir) |