diff options
author | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2018-02-09 13:53:20 +0100 |
---|---|---|
committer | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2018-02-09 13:53:20 +0100 |
commit | 6c7422fbcc5f9e5ddc0ebf7be52b952cd15d1d51 (patch) | |
tree | 88a5ac4c7105e6a280745253f1f67a9eb05c67ff /spec/migrations | |
parent | c181683d99e4447c44a5963afe3c2680f0c82a9a (diff) | |
parent | 7534f7a892d6e8c50475720e387b8689c94582da (diff) | |
download | gitlab-ce-6c7422fbcc5f9e5ddc0ebf7be52b952cd15d1d51.tar.gz |
Merge branch 'master' into backstage/gb/build-stages-catch-up-migration
* master: (1480 commits)
Conflicts:
db/schema.rb
Diffstat (limited to 'spec/migrations')
24 files changed, 685 insertions, 76 deletions
diff --git a/spec/migrations/add_foreign_keys_to_todos_spec.rb b/spec/migrations/add_foreign_keys_to_todos_spec.rb new file mode 100644 index 00000000000..4a22bd6f342 --- /dev/null +++ b/spec/migrations/add_foreign_keys_to_todos_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' +require Rails.root.join('db', 'migrate', '20180201110056_add_foreign_keys_to_todos.rb') + +describe AddForeignKeysToTodos, :migration do + let(:todos) { table(:todos) } + + let(:project) { create(:project) } + let(:user) { create(:user) } + + context 'add foreign key on user_id' do + let!(:todo_with_user) { create_todo(user_id: user.id) } + let!(:todo_without_user) { create_todo(user_id: 4711) } + + it 'removes orphaned todos without corresponding user' do + expect { migrate! }.to change { Todo.count }.from(2).to(1) + end + + it 'does not remove entries with valid user_id' do + expect { migrate! }.not_to change { todo_with_user.reload } + end + end + + context 'add foreign key on author_id' do + let!(:todo_with_author) { create_todo(author_id: user.id) } + let!(:todo_with_invalid_author) { create_todo(author_id: 4711) } + + it 'removes orphaned todos by author_id' do + expect { migrate! }.to change { Todo.count }.from(2).to(1) + end + + it 'does not touch author_id for valid entries' do + expect { migrate! }.not_to change { todo_with_author.reload } + end + end + + context 'add foreign key on note_id' do + let(:note) { create(:note) } + let!(:todo_with_note) { create_todo(note_id: note.id) } + let!(:todo_with_invalid_note) { create_todo(note_id: 4711) } + let!(:todo_without_note) { create_todo(note_id: nil) } + + it 'deletes todo if note_id is set but does not exist in notes table' do + expect { migrate! }.to change { Todo.count }.from(3).to(2) + end + + it 'does not touch entry if note_id is nil' do + expect { migrate! }.not_to change { todo_without_note.reload } + end + + it 'does not touch note_id for valid entries' do + expect { migrate! }.not_to change { todo_with_note.reload } + end + end + + def create_todo(**opts) + todos.create!( + project_id: project.id, + user_id: user.id, + author_id: user.id, + target_type: '', + action: 0, + state: '', **opts + ) + end +end diff --git a/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb b/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb index 84c2e9f7e52..63defcb39bf 100644 --- a/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb +++ b/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170508170547_add_head_pipeline_for_each_merge_request.rb') -describe AddHeadPipelineForEachMergeRequest, :truncate do +describe AddHeadPipelineForEachMergeRequest, :delete do include ProjectForksHelper let(:migration) { described_class.new } diff --git a/spec/migrations/calculate_conv_dev_index_percentages_spec.rb b/spec/migrations/calculate_conv_dev_index_percentages_spec.rb index 597d8eab51c..f3a46025376 100644 --- a/spec/migrations/calculate_conv_dev_index_percentages_spec.rb +++ b/spec/migrations/calculate_conv_dev_index_percentages_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170803090603_calculate_conv_dev_index_percentages.rb') -describe CalculateConvDevIndexPercentages, truncate: true do +describe CalculateConvDevIndexPercentages, :delete do let(:migration) { described_class.new } let!(:conv_dev_index) do create(:conversational_development_index_metric, diff --git a/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb b/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb index 759e77ac9db..d1bf6bdf9d6 100644 --- a/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb +++ b/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb @@ -21,7 +21,7 @@ describe ConvertCustomNotificationSettingsToColumns, :migration do events[event] = true end - user = build(:user).becomes(user_class).tap(&:save!) + user = user_class.create!(email: "user-#{SecureRandom.hex}@example.org", username: "user-#{SecureRandom.hex}", encrypted_password: '12345678') create_params = { user_id: user.id, level: params[:level], events: events } notification_setting = described_class::NotificationSetting.create(create_params) @@ -37,7 +37,7 @@ describe ConvertCustomNotificationSettingsToColumns, :migration do events[event] = true end - user = build(:user).becomes(user_class).tap(&:save!) + user = user_class.create!(email: "user-#{SecureRandom.hex}@example.org", username: "user-#{SecureRandom.hex}", encrypted_password: '12345678') create_params = events.merge(user_id: user.id, level: params[:level]) notification_setting = described_class::NotificationSetting.create(create_params) diff --git a/spec/migrations/fix_wrongly_renamed_routes_spec.rb b/spec/migrations/fix_wrongly_renamed_routes_spec.rb index 5ef10b92a3a..543cf55f076 100644 --- a/spec/migrations/fix_wrongly_renamed_routes_spec.rb +++ b/spec/migrations/fix_wrongly_renamed_routes_spec.rb @@ -1,29 +1,35 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170518231126_fix_wrongly_renamed_routes.rb') -describe FixWronglyRenamedRoutes, truncate: true do +describe FixWronglyRenamedRoutes, :migration do let(:subject) { described_class.new } + let(:namespaces_table) { table(:namespaces) } + let(:projects_table) { table(:projects) } + let(:routes_table) { table(:routes) } let(:broken_namespace) do - namespace = create(:group, name: 'apiis') - namespace.route.update_attribute(:path, 'api0is') - namespace + namespaces_table.create!(name: 'apiis', path: 'apiis').tap do |namespace| + routes_table.create!(source_type: 'Namespace', source_id: namespace.id, name: 'api0is', path: 'api0is') + end end + let(:broken_namespace_route) { routes_table.where(source_type: 'Namespace', source_id: broken_namespace.id).first } describe '#wrongly_renamed' do it "includes routes that have names that don't match their namespace" do broken_namespace - _other_namespace = create(:group, name: 'api0') + other_namespace = namespaces_table.create!(name: 'api0', path: 'api0') + routes_table.create!(source_type: 'Namespace', source_id: other_namespace.id, name: 'api0', path: 'api0') expect(subject.wrongly_renamed.map(&:id)) - .to contain_exactly(broken_namespace.route.id) + .to contain_exactly(broken_namespace_route.id) end end describe "#paths_and_corrections" do it 'finds the wrong path and gets the correction from the namespace' do broken_namespace - namespace = create(:group, name: 'uploads-test') - namespace.route.update_attribute(:path, 'uploads0-test') + namespaces_table.create!(name: 'uploads-test', path: 'uploads-test').tap do |namespace| + routes_table.create!(source_type: 'Namespace', source_id: namespace.id, name: 'uploads-test', path: 'uploads0-test') + end expected_result = [ { 'namespace_path' => 'apiis', 'path' => 'api0is' }, @@ -36,38 +42,45 @@ describe FixWronglyRenamedRoutes, truncate: true do describe '#routes_in_namespace_query' do it 'includes only the required routes' do - namespace = create(:group, path: 'hello') - project = create(:project, namespace: namespace) - _other_namespace = create(:group, path: 'hello0') - - result = Route.where(subject.routes_in_namespace_query('hello')) - - expect(result).to contain_exactly(namespace.route, project.route) + namespace = namespaces_table.create!(name: 'hello', path: 'hello') + namespace_route = routes_table.create!(source_type: 'Namespace', source_id: namespace.id, name: 'hello', path: 'hello') + project = projects_table.new(name: 'my-project', path: 'my-project', namespace_id: namespace.id).tap do |project| + project.save!(validate: false) + end + routes_table.create!(source_type: 'Project', source_id: project.id, name: 'my-project', path: 'hello/my-project') + _other_namespace = namespaces_table.create!(name: 'hello0', path: 'hello0') + + result = routes_table.where(subject.routes_in_namespace_query('hello')) + project_route = routes_table.where(source_type: 'Project', source_id: project.id).first + + expect(result).to contain_exactly(namespace_route, project_route) end end describe '#up' do - let(:broken_project) do - project = create(:project, namespace: broken_namespace, path: 'broken-project') - project.route.update_attribute(:path, 'api0is/broken-project') - project - end - it 'renames incorrectly named routes' do - broken_project + broken_project = + projects_table.new(name: 'broken-project', path: 'broken-project', namespace_id: broken_namespace.id).tap do |project| + project.save!(validate: false) + routes_table.create!(source_type: 'Project', source_id: project.id, name: 'broken-project', path: 'api0is/broken-project') + end subject.up - expect(broken_project.route.reload.path).to eq('apiis/broken-project') - expect(broken_namespace.route.reload.path).to eq('apiis') + broken_project_route = routes_table.where(source_type: 'Project', source_id: broken_project.id).first + + expect(broken_project_route.path).to eq('apiis/broken-project') + expect(broken_namespace_route.reload.path).to eq('apiis') end it "doesn't touch namespaces that look like something that should be renamed" do - namespace = create(:group, path: 'api0') + namespaces_table.create!(name: 'apiis', path: 'apiis') + namespace = namespaces_table.create!(name: 'hello', path: 'api0') + namespace_route = routes_table.create!(source_type: 'Namespace', source_id: namespace.id, name: 'hello', path: 'api0') subject.up - expect(namespace.route.reload.path).to eq('api0') + expect(namespace_route.reload.path).to eq('api0') end end end diff --git a/spec/migrations/migrate_issues_to_ghost_user_spec.rb b/spec/migrations/migrate_issues_to_ghost_user_spec.rb index cfd4021fbac..ff0d44e1ed2 100644 --- a/spec/migrations/migrate_issues_to_ghost_user_spec.rb +++ b/spec/migrations/migrate_issues_to_ghost_user_spec.rb @@ -8,10 +8,10 @@ describe MigrateIssuesToGhostUser, :migration do let(:users) { table(:users) } before do - projects.create!(name: 'gitlab') + project = projects.create!(name: 'gitlab') user = users.create(email: 'test@example.com') - issues.create(title: 'Issue 1', author_id: nil, project_id: 1) - issues.create(title: 'Issue 2', author_id: user.id, project_id: 1) + issues.create(title: 'Issue 1', author_id: nil, project_id: project.id) + issues.create(title: 'Issue 2', author_id: user.id, project_id: project.id) end context 'when ghost user exists' do diff --git a/spec/migrations/migrate_kubernetes_service_to_new_clusters_architectures_spec.rb b/spec/migrations/migrate_kubernetes_service_to_new_clusters_architectures_spec.rb new file mode 100644 index 00000000000..df0015b6dd3 --- /dev/null +++ b/spec/migrations/migrate_kubernetes_service_to_new_clusters_architectures_spec.rb @@ -0,0 +1,312 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb') + +describe MigrateKubernetesServiceToNewClustersArchitectures, :migration do + context 'when unique KubernetesService exists' do + shared_examples 'KubernetesService migration' do + let(:sample_num) { 2 } + + let(:projects) do + (1..sample_num).each_with_object([]) do |n, array| + array << MigrateKubernetesServiceToNewClustersArchitectures::Project.create! + end + end + + let!(:kubernetes_services) do + projects.map do |project| + MigrateKubernetesServiceToNewClustersArchitectures::Service.create!( + project: project, + active: active, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"namespace\":\"prod\",\"api_url\":\"https://kubernetes#{project.id}.com\",\"ca_pem\":\"ca_pem#{project.id}\",\"token\":\"token#{project.id}\"}") + end + end + + it 'migrates the KubernetesService to Platform::Kubernetes' do + expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(sample_num) + + projects.each do |project| + project.clusters.last.tap do |cluster| + expect(cluster.enabled).to eq(active) + expect(cluster.platform_kubernetes.api_url).to eq(project.kubernetes_service.api_url) + expect(cluster.platform_kubernetes.ca_cert).to eq(project.kubernetes_service.ca_pem) + expect(cluster.platform_kubernetes.token).to eq(project.kubernetes_service.token) + expect(project.kubernetes_service).not_to be_active + end + end + end + end + + context 'when KubernetesService is active' do + let(:active) { true } + + it_behaves_like 'KubernetesService migration' + end + end + + context 'when unique KubernetesService spawned from Service Template' do + let(:sample_num) { 2 } + + let(:projects) do + (1..sample_num).each_with_object([]) do |n, array| + array << MigrateKubernetesServiceToNewClustersArchitectures::Project.create! + end + end + + let!(:kubernetes_service_template) do + MigrateKubernetesServiceToNewClustersArchitectures::Service.create!( + template: true, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}") + end + + let!(:kubernetes_services) do + projects.map do |project| + MigrateKubernetesServiceToNewClustersArchitectures::Service.create!( + project: project, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"namespace\":\"prod\",\"api_url\":\"#{kubernetes_service_template.api_url}\",\"ca_pem\":\"#{kubernetes_service_template.ca_pem}\",\"token\":\"#{kubernetes_service_template.token}\"}") + end + end + + it 'migrates the KubernetesService to Platform::Kubernetes without template' do + expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(sample_num) + + projects.each do |project| + project.clusters.last.tap do |cluster| + expect(cluster.platform_kubernetes.api_url).to eq(project.kubernetes_service.api_url) + expect(cluster.platform_kubernetes.ca_cert).to eq(project.kubernetes_service.ca_pem) + expect(cluster.platform_kubernetes.token).to eq(project.kubernetes_service.token) + expect(project.kubernetes_service).not_to be_active + end + end + end + end + + context 'when managed KubernetesService exists' do + let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! } + + let(:cluster) do + MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!( + projects: [project], + name: 'sample-cluster', + platform_type: :kubernetes, + provider_type: :user, + platform_kubernetes_attributes: { + api_url: 'https://sample.kubernetes.com', + ca_cert: 'ca_pem-sample', + token: 'token-sample' + } ) + end + + let!(:kubernetes_service) do + MigrateKubernetesServiceToNewClustersArchitectures::Service.create!( + project: project, + active: cluster.enabled, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"api_url\":\"#{cluster.platform_kubernetes.api_url}\"}") + end + + it 'does not migrate the KubernetesService and disables the kubernetes_service' do # Because the corresponding Platform::Kubernetes already exists + expect { migrate! }.not_to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count } + + kubernetes_service.reload + expect(kubernetes_service).not_to be_active + end + end + + context 'when production cluster has already been existed' do # i.e. There are no environment_scope conflicts + let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! } + + let(:cluster) do + MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!( + projects: [project], + name: 'sample-cluster', + platform_type: :kubernetes, + provider_type: :user, + environment_scope: 'production/*', + platform_kubernetes_attributes: { + api_url: 'https://sample.kubernetes.com', + ca_cert: 'ca_pem-sample', + token: 'token-sample' + } ) + end + + let!(:kubernetes_service) do + MigrateKubernetesServiceToNewClustersArchitectures::Service.create!( + project: project, + active: true, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"api_url\":\"https://debug.kube.com\"}") + end + + it 'migrates the KubernetesService to Platform::Kubernetes' do + expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(1) + + kubernetes_service.reload + project.clusters.last.tap do |cluster| + expect(cluster.environment_scope).to eq('*') + expect(cluster.platform_kubernetes.api_url).to eq(kubernetes_service.api_url) + expect(cluster.platform_kubernetes.ca_cert).to eq(kubernetes_service.ca_pem) + expect(cluster.platform_kubernetes.token).to eq(kubernetes_service.token) + expect(kubernetes_service).not_to be_active + end + end + end + + context 'when default cluster has already been existed' do + let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! } + + let!(:cluster) do + MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!( + projects: [project], + name: 'sample-cluster', + platform_type: :kubernetes, + provider_type: :user, + environment_scope: '*', + platform_kubernetes_attributes: { + api_url: 'https://sample.kubernetes.com', + ca_cert: 'ca_pem-sample', + token: 'token-sample' + } ) + end + + let!(:kubernetes_service) do + MigrateKubernetesServiceToNewClustersArchitectures::Service.create!( + project: project, + active: true, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"api_url\":\"https://debug.kube.com\"}") + end + + it 'migrates the KubernetesService to Platform::Kubernetes with dedicated environment_scope' do # Because environment_scope is duplicated + expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(1) + + kubernetes_service.reload + project.clusters.last.tap do |cluster| + expect(cluster.environment_scope).to eq('migrated/*') + expect(cluster.platform_kubernetes.api_url).to eq(kubernetes_service.api_url) + expect(cluster.platform_kubernetes.ca_cert).to eq(kubernetes_service.ca_pem) + expect(cluster.platform_kubernetes.token).to eq(kubernetes_service.token) + expect(kubernetes_service).not_to be_active + end + end + end + + context 'when default cluster and migrated cluster has already been existed' do + let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! } + + let!(:cluster) do + MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!( + projects: [project], + name: 'sample-cluster', + platform_type: :kubernetes, + provider_type: :user, + environment_scope: '*', + platform_kubernetes_attributes: { + api_url: 'https://sample.kubernetes.com', + ca_cert: 'ca_pem-sample', + token: 'token-sample' + } ) + end + + let!(:migrated_cluster) do + MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!( + projects: [project], + name: 'sample-cluster', + platform_type: :kubernetes, + provider_type: :user, + environment_scope: 'migrated/*', + platform_kubernetes_attributes: { + api_url: 'https://sample.kubernetes.com', + ca_cert: 'ca_pem-sample', + token: 'token-sample' + } ) + end + + let!(:kubernetes_service) do + MigrateKubernetesServiceToNewClustersArchitectures::Service.create!( + project: project, + active: true, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"api_url\":\"https://debug.kube.com\"}") + end + + it 'migrates the KubernetesService to Platform::Kubernetes with dedicated environment_scope' do # Because environment_scope is duplicated + expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(1) + + kubernetes_service.reload + project.clusters.last.tap do |cluster| + expect(cluster.environment_scope).to eq('migrated0/*') + expect(cluster.platform_kubernetes.api_url).to eq(kubernetes_service.api_url) + expect(cluster.platform_kubernetes.ca_cert).to eq(kubernetes_service.ca_pem) + expect(cluster.platform_kubernetes.token).to eq(kubernetes_service.token) + expect(kubernetes_service).not_to be_active + end + end + end + + context 'when KubernetesService has nullified parameters' do + let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! } + + before do + MigrateKubernetesServiceToNewClustersArchitectures::Service.create!( + project: project, + active: false, + category: 'deployment', + type: 'KubernetesService', + properties: "{}") + end + + it 'does not migrate the KubernetesService and disables the kubernetes_service' do + expect { migrate! }.not_to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count } + + expect(project.kubernetes_service).not_to be_active + end + end + + # Platforms::Kubernetes validates `token` reagdless of the activeness, + # whereas KubernetesService validates `token` if only it's activated + # However, in this migration file, there are no validations because of the re-defined model class + # therefore, we should safely add this raw to Platform::Kubernetes + context 'when KubernetesService has empty token' do + let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! } + + before do + MigrateKubernetesServiceToNewClustersArchitectures::Service.create!( + project: project, + active: false, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"namespace\":\"prod\",\"api_url\":\"http://111.111.111.111\",\"ca_pem\":\"a\",\"token\":\"\"}") + end + + it 'does not migrate the KubernetesService and disables the kubernetes_service' do + expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(1) + + project.clusters.last.tap do |cluster| + expect(cluster.environment_scope).to eq('*') + expect(cluster.platform_kubernetes.namespace).to eq('prod') + expect(cluster.platform_kubernetes.api_url).to eq('http://111.111.111.111') + expect(cluster.platform_kubernetes.ca_cert).to eq('a') + expect(cluster.platform_kubernetes.token).to be_empty + expect(project.kubernetes_service).not_to be_active + end + end + end + + context 'when KubernetesService does not exist' do + let!(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! } + + it 'does not migrate the KubernetesService' do + expect { migrate! }.not_to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count } + end + end +end diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb index e5793a3c0ee..657113812bd 100644 --- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb +++ b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require Rails.root.join('db', 'migrate', '20161124141322_migrate_process_commit_worker_jobs.rb') describe MigrateProcessCommitWorkerJobs do - let(:project) { create(:project, :repository) } + let(:project) { create(:project, :legacy_storage, :repository) } let(:user) { create(:user) } let(:commit) { project.commit.raw.rugged_commit } diff --git a/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb b/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb index 063829be546..a17c9c72bde 100644 --- a/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb +++ b/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170324160416_migrate_user_activities_to_users_last_activity_on.rb') -describe MigrateUserActivitiesToUsersLastActivityOn, :clean_gitlab_redis_shared_state, :truncate do +describe MigrateUserActivitiesToUsersLastActivityOn, :clean_gitlab_redis_shared_state, :delete do let(:migration) { described_class.new } let!(:user_active_1) { create(:user) } let!(:user_active_2) { create(:user) } diff --git a/spec/migrations/migrate_user_project_view_spec.rb b/spec/migrations/migrate_user_project_view_spec.rb index 5e16769d63a..31d16e17d7b 100644 --- a/spec/migrations/migrate_user_project_view_spec.rb +++ b/spec/migrations/migrate_user_project_view_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170406142253_migrate_user_project_view.rb') -describe MigrateUserProjectView, :truncate do +describe MigrateUserProjectView, :delete do let(:migration) { described_class.new } let!(:user) { create(:user, project_view: 'readme') } diff --git a/spec/migrations/normalize_ldap_extern_uids_spec.rb b/spec/migrations/normalize_ldap_extern_uids_spec.rb index 262d7742aaf..56a78f52802 100644 --- a/spec/migrations/normalize_ldap_extern_uids_spec.rb +++ b/spec/migrations/normalize_ldap_extern_uids_spec.rb @@ -27,11 +27,11 @@ describe NormalizeLdapExternUids, :migration, :sidekiq do migrate! expect(BackgroundMigrationWorker.jobs[0]['args']).to eq([described_class::MIGRATION, [1, 2]]) - expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.seconds.from_now.to_f) + expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(5.minutes.from_now.to_f) expect(BackgroundMigrationWorker.jobs[1]['args']).to eq([described_class::MIGRATION, [3, 4]]) - expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(20.seconds.from_now.to_f) + expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(10.minutes.from_now.to_f) expect(BackgroundMigrationWorker.jobs[2]['args']).to eq([described_class::MIGRATION, [5, 5]]) - expect(BackgroundMigrationWorker.jobs[2]['at']).to eq(30.seconds.from_now.to_f) + expect(BackgroundMigrationWorker.jobs[2]['at']).to eq(15.minutes.from_now.to_f) expect(BackgroundMigrationWorker.jobs.size).to eq 3 end end diff --git a/spec/migrations/populate_can_push_from_deploy_keys_projects_spec.rb b/spec/migrations/populate_can_push_from_deploy_keys_projects_spec.rb new file mode 100644 index 00000000000..0ff98933d5c --- /dev/null +++ b/spec/migrations/populate_can_push_from_deploy_keys_projects_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' +require Rails.root.join('db', 'migrate', '20171215113714_populate_can_push_from_deploy_keys_projects.rb') + +describe PopulateCanPushFromDeployKeysProjects, :migration do + let(:migration) { described_class.new } + let(:deploy_keys) { table(:keys) } + let(:deploy_keys_projects) { table(:deploy_keys_projects) } + let(:projects) { table(:projects) } + + before do + deploy_keys.inheritance_column = nil + + projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1') + (1..10).each do |index| + deploy_keys.create!(id: index, title: 'dummy', type: 'DeployKey', key: Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate + ' dummy@gitlab.com') + deploy_keys_projects.create!(id: index, deploy_key_id: index, project_id: 1) + end + end + + describe '#up' do + it 'migrates can_push from deploy_keys to deploy_keys_projects' do + deploy_keys.limit(5).update_all(can_push: true) + + expected = deploy_keys.order(:id).pluck(:id, :can_push) + + migration.up + + expect(deploy_keys_projects.order(:id).pluck(:deploy_key_id, :can_push)).to eq expected + end + end + + describe '#down' do + it 'migrates can_push from deploy_keys_projects to deploy_keys' do + deploy_keys_projects.limit(5).update_all(can_push: true) + + expected = deploy_keys_projects.order(:id).pluck(:deploy_key_id, :can_push) + + migration.down + + expect(deploy_keys.order(:id).pluck(:id, :can_push)).to eq expected + end + end +end diff --git a/spec/migrations/remove_duplicate_mr_events_spec.rb b/spec/migrations/remove_duplicate_mr_events_spec.rb index e393374028f..e51872239ad 100644 --- a/spec/migrations/remove_duplicate_mr_events_spec.rb +++ b/spec/migrations/remove_duplicate_mr_events_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170815060945_remove_duplicate_mr_events.rb') -describe RemoveDuplicateMrEvents, truncate: true do +describe RemoveDuplicateMrEvents, :delete do let(:migration) { described_class.new } describe '#up' do diff --git a/spec/migrations/remove_empty_fork_networks_spec.rb b/spec/migrations/remove_empty_fork_networks_spec.rb index cf6ae5cda74..7f7ce91378b 100644 --- a/spec/migrations/remove_empty_fork_networks_spec.rb +++ b/spec/migrations/remove_empty_fork_networks_spec.rb @@ -3,12 +3,19 @@ require Rails.root.join('db', 'post_migrate', '20171114104051_remove_empty_fork_ describe RemoveEmptyForkNetworks, :migration do let!(:fork_networks) { table(:fork_networks) } + let!(:projects) { table(:projects) } + let!(:fork_network_members) { table(:fork_network_members) } - let(:deleted_project) { create(:project) } - let!(:empty_network) { create(:fork_network, id: 1, root_project_id: deleted_project.id) } - let!(:other_network) { create(:fork_network, id: 2, root_project_id: create(:project).id) } + let(:deleted_project) { projects.create! } + let!(:empty_network) { fork_networks.create!(id: 1, root_project_id: deleted_project.id) } + let!(:other_network) { fork_networks.create!(id: 2, root_project_id: projects.create.id) } before do + fork_network_members.create(fork_network_id: empty_network.id, + project_id: empty_network.root_project_id) + fork_network_members.create(fork_network_id: other_network.id, + project_id: other_network.root_project_id) + deleted_project.destroy! end diff --git a/spec/migrations/remove_project_labels_group_id_spec.rb b/spec/migrations/remove_project_labels_group_id_spec.rb new file mode 100644 index 00000000000..d80d61af20b --- /dev/null +++ b/spec/migrations/remove_project_labels_group_id_spec.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20180202111106_remove_project_labels_group_id.rb') + +describe RemoveProjectLabelsGroupId, :delete do + let(:migration) { described_class.new } + let(:group) { create(:group) } + let!(:project_label) { create(:label, group_id: group.id) } + let!(:group_label) { create(:group_label) } + + describe '#up' do + it 'updates the project labels group ID' do + expect { migration.up }.to change { project_label.reload.group_id }.to(nil) + end + + it 'keeps the group labels group ID' do + expect { migration.up }.not_to change { group_label.reload.group_id } + end + end +end diff --git a/spec/migrations/remove_redundant_pipeline_stages_spec.rb b/spec/migrations/remove_redundant_pipeline_stages_spec.rb new file mode 100644 index 00000000000..8325f986594 --- /dev/null +++ b/spec/migrations/remove_redundant_pipeline_stages_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20180119121225_remove_redundant_pipeline_stages.rb') + +describe RemoveRedundantPipelineStages, :migration do + let(:projects) { table(:projects) } + let(:pipelines) { table(:ci_pipelines) } + let(:stages) { table(:ci_stages) } + let(:builds) { table(:ci_builds) } + + before do + projects.create!(id: 123, name: 'gitlab', path: 'gitlab-ce') + pipelines.create!(id: 234, project_id: 123, ref: 'master', sha: 'adf43c3a') + + stages.create!(id: 6, project_id: 123, pipeline_id: 234, name: 'build') + stages.create!(id: 10, project_id: 123, pipeline_id: 234, name: 'build') + stages.create!(id: 21, project_id: 123, pipeline_id: 234, name: 'build') + stages.create!(id: 41, project_id: 123, pipeline_id: 234, name: 'test') + stages.create!(id: 62, project_id: 123, pipeline_id: 234, name: 'test') + stages.create!(id: 102, project_id: 123, pipeline_id: 234, name: 'deploy') + + builds.create!(id: 1, commit_id: 234, project_id: 123, stage_id: 10) + builds.create!(id: 2, commit_id: 234, project_id: 123, stage_id: 21) + builds.create!(id: 3, commit_id: 234, project_id: 123, stage_id: 21) + builds.create!(id: 4, commit_id: 234, project_id: 123, stage_id: 41) + builds.create!(id: 5, commit_id: 234, project_id: 123, stage_id: 62) + builds.create!(id: 6, commit_id: 234, project_id: 123, stage_id: 102) + end + + it 'removes ambiguous stages and preserves builds' do + expect(stages.all.count).to eq 6 + expect(builds.all.count).to eq 6 + + migrate! + + expect(stages.all.count).to eq 1 + expect(builds.all.count).to eq 6 + expect(builds.all.pluck(:stage_id).compact).to eq [102] + end + + it 'retries when incorrectly added index exception is caught' do + allow_any_instance_of(described_class) + .to receive(:remove_redundant_pipeline_stages!) + + expect_any_instance_of(described_class) + .to receive(:remove_outdated_index!) + .exactly(100).times.and_call_original + + expect { migrate! } + .to raise_error StandardError, /Failed to add an unique index/ + end + + it 'does not retry when unknown exception is being raised' do + allow(subject).to receive(:remove_outdated_index!) + expect(subject).to receive(:remove_redundant_pipeline_stages!).once + allow(subject).to receive(:add_unique_index!).and_raise(StandardError) + + expect { subject.up(attempts: 3) }.to raise_error StandardError + end +end diff --git a/spec/migrations/remove_soft_removed_objects_spec.rb b/spec/migrations/remove_soft_removed_objects_spec.rb new file mode 100644 index 00000000000..ec089f9106d --- /dev/null +++ b/spec/migrations/remove_soft_removed_objects_spec.rb @@ -0,0 +1,77 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20171207150343_remove_soft_removed_objects.rb') + +describe RemoveSoftRemovedObjects, :migration do + describe '#up' do + it 'removes various soft removed objects' do + 5.times do + create_with_deleted_at(:issue) + end + + regular_issue = create(:issue) + + run_migration + + expect(Issue.count).to eq(1) + expect(Issue.first).to eq(regular_issue) + end + + it 'removes the temporary indexes once soft removed data has been removed' do + migration = described_class.new + + run_migration + + disable_migrations_output do + expect(migration.temporary_index_exists?(Issue)).to eq(false) + end + end + + it 'removes routes of soft removed personal namespaces' do + namespace = create_with_deleted_at(:namespace) + group = create(:group) + + expect(Route.where(source: namespace).exists?).to eq(true) + expect(Route.where(source: group).exists?).to eq(true) + + run_migration + + expect(Route.where(source: namespace).exists?).to eq(false) + expect(Route.where(source: group).exists?).to eq(true) + end + + it 'schedules the removal of soft removed groups' do + group = create_with_deleted_at(:group) + admin = create(:user, admin: true) + + expect_any_instance_of(GroupDestroyWorker) + .to receive(:perform) + .with(group.id, admin.id) + + run_migration + end + + it 'does not remove soft removed groups when no admin user could be found' do + create_with_deleted_at(:group) + + expect_any_instance_of(GroupDestroyWorker) + .not_to receive(:perform) + + run_migration + end + end + + def run_migration + disable_migrations_output do + migrate! + end + end + + def create_with_deleted_at(*args) + row = create(*args) + + # We set "deleted_at" this way so we don't run into any column cache issues. + row.class.where(id: row.id).update_all(deleted_at: 1.year.ago) + + row + end +end diff --git a/spec/migrations/rename_more_reserved_project_names_spec.rb b/spec/migrations/rename_more_reserved_project_names_spec.rb index ae3a4cb9b29..75310075cc5 100644 --- a/spec/migrations/rename_more_reserved_project_names_spec.rb +++ b/spec/migrations/rename_more_reserved_project_names_spec.rb @@ -5,8 +5,8 @@ require Rails.root.join('db', 'post_migrate', '20170313133418_rename_more_reserv # This migration uses multiple threads, and thus different transactions. This # means data created in this spec may not be visible to some threads. To work -# around this we use the TRUNCATE cleaning strategy. -describe RenameMoreReservedProjectNames, truncate: true do +# around this we use the DELETE cleaning strategy. +describe RenameMoreReservedProjectNames, :delete do let(:migration) { described_class.new } let!(:project) { create(:project) } diff --git a/spec/migrations/rename_reserved_project_names_spec.rb b/spec/migrations/rename_reserved_project_names_spec.rb index 462f4c08d63..e6555b1fe6b 100644 --- a/spec/migrations/rename_reserved_project_names_spec.rb +++ b/spec/migrations/rename_reserved_project_names_spec.rb @@ -5,8 +5,8 @@ require Rails.root.join('db', 'post_migrate', '20161221153951_rename_reserved_pr # This migration uses multiple threads, and thus different transactions. This # means data created in this spec may not be visible to some threads. To work -# around this we use the TRUNCATE cleaning strategy. -describe RenameReservedProjectNames, truncate: true do +# around this we use the DELETE cleaning strategy. +describe RenameReservedProjectNames, :delete do let(:migration) { described_class.new } let!(:project) { create(:project) } diff --git a/spec/migrations/rename_users_with_renamed_namespace_spec.rb b/spec/migrations/rename_users_with_renamed_namespace_spec.rb index 1e9aab3d9a1..cbc0ebeb44d 100644 --- a/spec/migrations/rename_users_with_renamed_namespace_spec.rb +++ b/spec/migrations/rename_users_with_renamed_namespace_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170518200835_rename_users_with_renamed_namespace.rb') -describe RenameUsersWithRenamedNamespace, truncate: true do +describe RenameUsersWithRenamedNamespace, :delete do it 'renames a user that had their namespace renamed to the namespace path' do other_user = create(:user, username: 'kodingu') other_user1 = create(:user, username: 'api0') diff --git a/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb b/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb index 2e6b2cff0ab..7494624066a 100644 --- a/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb +++ b/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb @@ -2,6 +2,12 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20171128214150_schedule_populate_merge_request_metrics_with_events_data.rb') describe SchedulePopulateMergeRequestMetricsWithEventsData, :migration, :sidekiq do + # commits_count attribute is added in a next migration + before do + allow_any_instance_of(MergeRequestDiff) + .to receive(:commits_count=).and_return(nil) + end + let!(:mrs) { create_list(:merge_request, 3) } it 'correctly schedules background migrations' do diff --git a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb index 6f7a730edff..528dc54781d 100644 --- a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb +++ b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb @@ -4,7 +4,7 @@ require Rails.root.join('db', 'migrate', '20170503140202_turn_nested_groups_into describe TurnNestedGroupsIntoRegularGroupsForMysql do let!(:parent_group) { create(:group) } let!(:child_group) { create(:group, parent: parent_group) } - let!(:project) { create(:project, :empty_repo, namespace: child_group) } + let!(:project) { create(:project, :legacy_storage, :empty_repo, namespace: child_group) } let!(:member) { create(:user) } let(:migration) { described_class.new } diff --git a/spec/migrations/update_retried_for_ci_build_spec.rb b/spec/migrations/update_retried_for_ci_build_spec.rb index 3742b4dafe5..ccb77766b84 100644 --- a/spec/migrations/update_retried_for_ci_build_spec.rb +++ b/spec/migrations/update_retried_for_ci_build_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170503004427_update_retried_for_ci_build.rb') -describe UpdateRetriedForCiBuild, truncate: true do +describe UpdateRetriedForCiBuild, :delete do let(:pipeline) { create(:ci_pipeline) } let!(:build_old) { create(:ci_build, pipeline: pipeline, name: 'test') } let!(:build_new) { create(:ci_build, pipeline: pipeline, name: 'test') } diff --git a/spec/migrations/update_upload_paths_to_system_spec.rb b/spec/migrations/update_upload_paths_to_system_spec.rb index d4a1553fb0e..984b428a020 100644 --- a/spec/migrations/update_upload_paths_to_system_spec.rb +++ b/spec/migrations/update_upload_paths_to_system_spec.rb @@ -1,53 +1,59 @@ -require "spec_helper" -require Rails.root.join("db", "post_migrate", "20170317162059_update_upload_paths_to_system.rb") +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170317162059_update_upload_paths_to_system.rb') -describe UpdateUploadPathsToSystem do +describe UpdateUploadPathsToSystem, :migration do let(:migration) { described_class.new } + let(:uploads_table) { table(:uploads) } + let(:base_upload_attributes) { { size: 42, uploader: 'John Doe' } } before do allow(migration).to receive(:say) end - describe "#uploads_to_switch_to_new_path" do - it "contains only uploads with the old path for the correct models" do - _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg") - _upload_with_system_path = create(:upload, model: create(:project), path: "uploads/-/system/project/avatar.jpg") - _upload_with_other_path = create(:upload, model: create(:project), path: "thelongsecretforafileupload/avatar.jpg") - old_upload = create(:upload, model: create(:project), path: "uploads/project/avatar.jpg") - group_upload = create(:upload, model: create(:group), path: "uploads/group/avatar.jpg") + describe '#uploads_to_switch_to_new_path' do + it 'contains only uploads with the old path for the correct models' do + _upload_for_other_type = create_upload('Pipeline', 'uploads/ci_pipeline/avatar.jpg') + _upload_with_system_path = create_upload('Project', 'uploads/-/system/project/avatar.jpg') + _upload_with_other_path = create_upload('Project', 'thelongsecretforafileupload/avatar.jpg') + old_upload = create_upload('Project', 'uploads/project/avatar.jpg') + group_upload = create_upload('Namespace', 'uploads/group/avatar.jpg') - expect(Upload.where(migration.uploads_to_switch_to_new_path)).to contain_exactly(old_upload, group_upload) + expect(uploads_table.where(migration.uploads_to_switch_to_new_path)).to contain_exactly(old_upload, group_upload) end end - describe "#uploads_to_switch_to_old_path" do - it "contains only uploads with the new path for the correct models" do - _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg") - upload_with_system_path = create(:upload, model: create(:project), path: "uploads/-/system/project/avatar.jpg") - _upload_with_other_path = create(:upload, model: create(:project), path: "thelongsecretforafileupload/avatar.jpg") - _old_upload = create(:upload, model: create(:project), path: "uploads/project/avatar.jpg") + describe '#uploads_to_switch_to_old_path' do + it 'contains only uploads with the new path for the correct models' do + _upload_for_other_type = create_upload('Pipeline', 'uploads/ci_pipeline/avatar.jpg') + upload_with_system_path = create_upload('Project', 'uploads/-/system/project/avatar.jpg') + _upload_with_other_path = create_upload('Project', 'thelongsecretforafileupload/avatar.jpg') + _old_upload = create_upload('Project', 'uploads/project/avatar.jpg') - expect(Upload.where(migration.uploads_to_switch_to_old_path)).to contain_exactly(upload_with_system_path) + expect(uploads_table.where(migration.uploads_to_switch_to_old_path)).to contain_exactly(upload_with_system_path) end end - describe "#up", :truncate do - it "updates old upload records to the new path" do - old_upload = create(:upload, model: create(:project), path: "uploads/project/avatar.jpg") + describe '#up' do + it 'updates old upload records to the new path' do + old_upload = create_upload('Project', 'uploads/project/avatar.jpg') migration.up - expect(old_upload.reload.path).to eq("uploads/-/system/project/avatar.jpg") + expect(old_upload.reload.path).to eq('uploads/-/system/project/avatar.jpg') end end - describe "#down", :truncate do - it "updates the new system patsh to the old paths" do - new_upload = create(:upload, model: create(:project), path: "uploads/-/system/project/avatar.jpg") + describe '#down' do + it 'updates the new system patsh to the old paths' do + new_upload = create_upload('Project', 'uploads/-/system/project/avatar.jpg') migration.down - expect(new_upload.reload.path).to eq("uploads/project/avatar.jpg") + expect(new_upload.reload.path).to eq('uploads/project/avatar.jpg') end end + + def create_upload(type, path) + uploads_table.create(base_upload_attributes.merge(model_type: type, path: path)) + end end |