From dd4a8df4cb5da30bf918725143f3e038a6fa7a79 Mon Sep 17 00:00:00 2001
From: Shinya Maeda <shinya@gitlab.com>
Date: Mon, 3 Dec 2018 20:10:13 +0900
Subject: [PATCH] Validate enum uniqueness

---
 spec/models/ci/build_metadata_spec.rb             | 2 ++
 spec/models/ci/build_trace_chunk_spec.rb          | 2 ++
 spec/models/ci/job_artifact_spec.rb               | 2 ++
 spec/models/ci/pipeline_spec.rb                   | 2 ++
 spec/models/ci/runner_spec.rb                     | 2 ++
 spec/models/ci/stage_spec.rb                      | 2 ++
 spec/models/clusters/applications/ingress_spec.rb | 1 +
 spec/models/clusters/cluster_spec.rb              | 2 ++
 spec/models/clusters/platforms/kubernetes_spec.rb | 2 ++
 spec/models/commit_status_spec.rb                 | 2 ++
 spec/models/deployment_spec.rb                    | 2 ++
 spec/models/gpg_signature_spec.rb                 | 2 ++
 spec/models/internal_id_spec.rb                   | 2 ++
 spec/models/list_spec.rb                          | 2 ++
 spec/models/notification_setting_spec.rb          | 2 ++
 spec/models/project_auto_devops_spec.rb           | 2 ++
 spec/models/project_spec.rb                       | 2 ++
 spec/models/prometheus_metric_spec.rb             | 2 ++
 spec/models/push_event_payload_spec.rb            | 2 ++
 spec/models/resource_label_event_spec.rb          | 2 ++
 spec/models/user_callout_spec.rb                  | 2 ++
 spec/models/user_spec.rb                          | 2 ++
 spec/support/active_record_enum.rb                | 9 +++++++++
 23 files changed, 52 insertions(+)
 create mode 100644 spec/support/active_record_enum.rb

diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb
index 6dba132184c..c8a67535755 100644
--- a/spec/models/ci/build_metadata_spec.rb
+++ b/spec/models/ci/build_metadata_spec.rb
@@ -15,6 +15,8 @@ describe Ci::BuildMetadata do
   let(:build) { create(:ci_build, pipeline: pipeline) }
   let(:build_metadata) { build.metadata }
 
+  it_behaves_like 'Unique enum values'
+
   describe '#update_timeout_state' do
     subject { build_metadata }
 
diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb
index 859287bb0c8..8fbaa550633 100644
--- a/spec/models/ci/build_trace_chunk_spec.rb
+++ b/spec/models/ci/build_trace_chunk_spec.rb
@@ -12,6 +12,8 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
     described_class.new(build: build, chunk_index: chunk_index, data_store: data_store, raw_data: raw_data)
   end
 
+  it_behaves_like 'Unique enum values'
+
   before do
     stub_feature_flags(ci_enable_live_trace: true)
     stub_artifacts_object_storage
diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb
index fb5bec4108a..811b1a24fb4 100644
--- a/spec/models/ci/job_artifact_spec.rb
+++ b/spec/models/ci/job_artifact_spec.rb
@@ -15,6 +15,8 @@ describe Ci::JobArtifact do
   it { is_expected.to delegate_method(:open).to(:file) }
   it { is_expected.to delegate_method(:exists?).to(:file) }
 
+  it_behaves_like 'Unique enum values'
+
   describe '.test_reports' do
     subject { described_class.test_reports }
 
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 9e6146b8a44..4526248be92 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -28,6 +28,8 @@ describe Ci::Pipeline, :mailer do
   it { is_expected.to respond_to :short_sha }
   it { is_expected.to delegate_method(:full_path).to(:project).with_prefix }
 
+  it_behaves_like 'Unique enum values'
+
   describe 'associations' do
     it 'has a bidirectional relationship with projects' do
       expect(described_class.reflect_on_association(:project).has_inverse?).to eq(:pipelines)
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index b545e036aa1..db348ec5a33 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -1,6 +1,8 @@
 require 'spec_helper'
 
 describe Ci::Runner do
+  it_behaves_like 'Unique enum values'
+
   describe 'validation' do
     it { is_expected.to validate_presence_of(:access_level) }
     it { is_expected.to validate_presence_of(:runner_type) }
diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb
index 5076f7faeac..0e5e309d0a7 100644
--- a/spec/models/ci/stage_spec.rb
+++ b/spec/models/ci/stage_spec.rb
@@ -3,6 +3,8 @@ require 'spec_helper'
 describe Ci::Stage, :models do
   let(:stage) { create(:ci_stage_entity) }
 
+  it_behaves_like 'Unique enum values'
+
   describe 'associations' do
     before do
       create(:ci_build, stage_id: stage.id)
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index cfe0e216c78..e06d14b714f 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -6,6 +6,7 @@ describe Clusters::Applications::Ingress do
   include_examples 'cluster application core specs', :clusters_applications_ingress
   include_examples 'cluster application status specs', :clusters_applications_ingress
   include_examples 'cluster application helm specs', :clusters_applications_ingress
+  it_behaves_like 'Unique enum values'
 
   before do
     allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in)
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index eb68ebccdcb..6e89c0f16e7 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -30,6 +30,8 @@ describe Clusters::Cluster do
 
   it { is_expected.to respond_to :project }
 
+  it_behaves_like 'Unique enum values'
+
   describe '.enabled' do
     subject { described_class.enabled }
 
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index 99fd6ccc4d8..8235e4667f9 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -18,6 +18,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
   it { is_expected.to delegate_method(:managed?).to(:cluster) }
   it { is_expected.to delegate_method(:kubernetes_namespace).to(:cluster) }
 
+  it_behaves_like 'Unique enum values'
+
   describe 'before_validation' do
     context 'when namespace includes upper case' do
       let(:kubernetes) { create(:cluster_platform_kubernetes, :configured, namespace: namespace) }
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 917685399d4..e7944c1b331 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -29,6 +29,8 @@ describe CommitStatus do
   it { is_expected.to respond_to :running? }
   it { is_expected.to respond_to :pending? }
 
+  it_behaves_like 'Unique enum values'
+
   describe '#author' do
     subject { commit_status.author }
 
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index 270b2767c68..ca33205af8e 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -16,6 +16,8 @@ describe Deployment do
   it { is_expected.to validate_presence_of(:ref) }
   it { is_expected.to validate_presence_of(:sha) }
 
+  it_behaves_like 'Unique enum values'
+
   describe '#scheduled_actions' do
     subject { deployment.scheduled_actions }
 
diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb
index 0136bb61c07..f9237cff823 100644
--- a/spec/models/gpg_signature_spec.rb
+++ b/spec/models/gpg_signature_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe GpgSignature do
   let(:gpg_key) { create(:gpg_key) }
   let(:gpg_key_subkey) { create(:gpg_key_subkey) }
 
+  it_behaves_like 'Unique enum values'
+
   describe 'associations' do
     it { is_expected.to belong_to(:project) }
     it { is_expected.to belong_to(:gpg_key) }
diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb
index 52c00a74b4b..17a838db3ce 100644
--- a/spec/models/internal_id_spec.rb
+++ b/spec/models/internal_id_spec.rb
@@ -11,6 +11,8 @@ describe InternalId do
     it { is_expected.to validate_presence_of(:usage) }
   end
 
+  it_behaves_like 'Unique enum values'
+
   describe '.generate_next' do
     subject { described_class.generate_next(issue, scope, usage, init) }
 
diff --git a/spec/models/list_spec.rb b/spec/models/list_spec.rb
index 17dc27bd132..1c14ca113d5 100644
--- a/spec/models/list_spec.rb
+++ b/spec/models/list_spec.rb
@@ -21,6 +21,8 @@ describe List do
     end
   end
 
+  it_behaves_like 'Unique enum values'
+
   describe '#destroy' do
     it 'can be destroyed when list_type is set to label' do
       subject = create(:list)
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index e545b674b4f..ad09172e36a 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -6,6 +6,8 @@ RSpec.describe NotificationSetting do
     it { is_expected.to belong_to(:source) }
   end
 
+  it_behaves_like 'Unique enum values'
+
   describe "Validation" do
     subject { described_class.new(source_id: 1, source_type: 'Project') }
 
diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb
index 342798f730b..cf9e6ccf87b 100644
--- a/spec/models/project_auto_devops_spec.rb
+++ b/spec/models/project_auto_devops_spec.rb
@@ -10,6 +10,8 @@ describe ProjectAutoDevops do
   it { is_expected.to respond_to(:created_at) }
   it { is_expected.to respond_to(:updated_at) }
 
+  it_behaves_like 'Unique enum values'
+
   describe '#has_domain?' do
     context 'when domain is defined' do
       let(:auto_devops) { build_stubbed(:project_auto_devops, project: project, domain: 'domain.com') }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index af5b0939ca2..ea4a97c0745 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -375,6 +375,8 @@ describe Project do
     end
   end
 
+  it_behaves_like 'Unique enum values'
+
   describe 'Respond to' do
     it { is_expected.to respond_to(:url_to_repo) }
     it { is_expected.to respond_to(:repo_exists?) }
diff --git a/spec/models/prometheus_metric_spec.rb b/spec/models/prometheus_metric_spec.rb
index a83a31ae88c..f1c209d8c3f 100644
--- a/spec/models/prometheus_metric_spec.rb
+++ b/spec/models/prometheus_metric_spec.rb
@@ -11,6 +11,8 @@ describe PrometheusMetric do
   it { is_expected.to validate_presence_of(:query) }
   it { is_expected.to validate_presence_of(:group) }
 
+  it_behaves_like 'Unique enum values'
+
   describe 'common metrics' do
     using RSpec::Parameterized::TableSyntax
 
diff --git a/spec/models/push_event_payload_spec.rb b/spec/models/push_event_payload_spec.rb
index a049ad35584..ec559517549 100644
--- a/spec/models/push_event_payload_spec.rb
+++ b/spec/models/push_event_payload_spec.rb
@@ -1,6 +1,8 @@
 require 'spec_helper'
 
 describe PushEventPayload do
+  it_behaves_like 'Unique enum values'
+
   describe 'saving payloads' do
     it 'does not allow commit messages longer than 70 characters' do
       event = create(:push_event)
diff --git a/spec/models/resource_label_event_spec.rb b/spec/models/resource_label_event_spec.rb
index da6e1b5610d..2e718948c53 100644
--- a/spec/models/resource_label_event_spec.rb
+++ b/spec/models/resource_label_event_spec.rb
@@ -7,6 +7,8 @@ RSpec.describe ResourceLabelEvent, type: :model do
   let(:issue) { create(:issue) }
   let(:merge_request) { create(:merge_request) }
 
+  it_behaves_like 'Unique enum values'
+
   describe 'associations' do
     it { is_expected.to belong_to(:user) }
     it { is_expected.to belong_to(:issue) }
diff --git a/spec/models/user_callout_spec.rb b/spec/models/user_callout_spec.rb
index 64ba17c81fe..d845fdf33a5 100644
--- a/spec/models/user_callout_spec.rb
+++ b/spec/models/user_callout_spec.rb
@@ -3,6 +3,8 @@ require 'rails_helper'
 describe UserCallout do
   let!(:callout) { create(:user_callout) }
 
+  it_behaves_like 'Unique enum values'
+
   describe 'relationships' do
     it { is_expected.to belong_to(:user) }
   end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 7bd6dccd0ad..c43921bb0f0 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -159,6 +159,8 @@ describe User do
 
     it { is_expected.to validate_length_of(:bio).is_at_most(255) }
 
+    it_behaves_like 'Unique enum values'
+
     it_behaves_like 'an object with email-formated attributes', :email do
       subject { build(:user) }
     end
diff --git a/spec/support/active_record_enum.rb b/spec/support/active_record_enum.rb
new file mode 100644
index 00000000000..4bb1f696315
--- /dev/null
+++ b/spec/support/active_record_enum.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+shared_examples 'Unique enum values' do
+  described_class.defined_enums.each do |name, hash|
+    it "has unique values in #{name}" do
+      expect(hash.values).to contain_exactly(*hash.values.uniq)
+    end
+  end
+end
-- 
2.30.9