Here is a not valid comment with Link text
" } } let(:content) { "Here is a not valid comment with Link text
" } let(:deprecated_url) { "https://#{deprecated_endpoint}/xxxx?response-content-disposition=inline%3Bfilename%3D\"BuPa23_reglement-interieur.pdf\"%3Bfilename*%3DUTF-8''BuPa23_r%25C3%25A8glement-int%25C3%25A9rieur.pdf&response-content-type=application%2Fpdf" } - let!(:blob) { ActiveStorage::Blob.create_after_upload!(filename: "BuPa23_reglement-interieur.pdf", io: File.open("spec/fixtures/BuPa23_reglement-interieur.pdf"), content_type: "application/pdf") } + let!(:blob) { ActiveStorage::Blob.create_and_upload!(filename: "BuPa23_reglement-interieur.pdf", io: File.open("spec/fixtures/BuPa23_reglement-interieur.pdf"), content_type: "application/pdf") } let(:blob_path) { Rails.application.routes.url_helpers.rails_blob_path(ActiveStorage::Blob.find(blob.id), only_path: true) } describe "#repair" do diff --git a/spec/lib/decidim/translator_configuration_helper_spec.rb b/spec/lib/decidim/translator_configuration_helper_spec.rb new file mode 100644 index 0000000000..7d9e90a1a2 --- /dev/null +++ b/spec/lib/decidim/translator_configuration_helper_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require "spec_helper" +require "decidim/translator_configuration_helper" + +RSpec.describe Decidim::TranslatorConfigurationHelper do + let!(:original_queue_adapter) { Rails.configuration.active_job.queue_adapter } + let!(:original_enable_machine_translations) { Decidim.enable_machine_translations } + let(:with_incompatible_backend) { Rails.configuration.active_job.queue_adapter = :async } + let(:with_compatible_backend) { Rails.configuration.active_job.queue_adapter = :something } + let(:with_translations_enabled) { Decidim.enable_machine_translations = true } + let(:with_translations_disabled) { Decidim.enable_machine_translations = false } + + after do + Rails.configuration.active_job.queue_adapter = original_queue_adapter + Decidim.enable_machine_translations = original_enable_machine_translations + end + + describe ".able_to_seed?" do + context "when Decidim translations are enabled" do + before { with_translations_enabled } + + context "when the backend is 'async'" do + before { with_incompatible_backend } + + it "raises an error" do + expect do + Decidim::TranslatorConfigurationHelper.able_to_seed? + end.to raise_error RuntimeError, /^You can't seed the database/ + end + end + + context "when the backend is not 'async'" do + before { with_compatible_backend } + + it "returns nil" do + expect(Decidim::TranslatorConfigurationHelper.able_to_seed?).to be_nil + end + end + end + + context "when Decidim translations are disabled" do + before { with_translations_disabled } + + it "returns true" do + expect(Decidim::TranslatorConfigurationHelper.able_to_seed?).to be true + end + end + end + + describe ".compatible_backend" do + context "with an 'async' backend" do + before { with_incompatible_backend } + + it "returns false" do + expect(Decidim::TranslatorConfigurationHelper.compatible_backend?).to be false + end + end + + context "with another backend" do + before { with_compatible_backend } + + it "returns true" do + expect(Decidim::TranslatorConfigurationHelper.compatible_backend?).to be true + end + end + end + + describe ".translator_activated?" do + context "when translations are active" do + before { with_translations_enabled } + + it "returns true" do + expect(Decidim::TranslatorConfigurationHelper.translator_activated?).to be true + end + end + + context "when translations are inactive" do + before { with_translations_disabled } + + it "returns true" do + expect(Decidim::TranslatorConfigurationHelper.translator_activated?).to be false + end + end + end +end diff --git a/spec/lib/decidim_app/decidim_initiatives_spec.rb b/spec/lib/decidim_app/decidim_initiatives_spec.rb index 810e44bbbd..4aa3499a90 100644 --- a/spec/lib/decidim_app/decidim_initiatives_spec.rb +++ b/spec/lib/decidim_app/decidim_initiatives_spec.rb @@ -5,6 +5,17 @@ describe DecidimApp::DecidimInitiatives do subject { described_class } + describe ".apply_configuration" do + it "sets the configuration values" do + skip_if_undefined "Decidim::Initiatives", "decidim-initiatives" + + allow(Decidim::Initiatives).to receive(:configure) + subject.apply_configuration + + expect(Decidim::Initiatives).to have_received(:configure) + end + end + describe "#creation_enabled?" do it "returns true" do expect(subject).to be_creation_enabled @@ -109,6 +120,21 @@ end end + describe ".default_components" do + it "handles empty array string" do + allow(Rails.application.secrets).to receive(:dig).with(:decidim, :initiatives, :default_components).and_return(["[]"]) + + expect(subject.default_components).to eq [] + end + + it "returns the configured value" do + expected = ["a", 1, true] + allow(Rails.application.secrets).to receive(:dig).with(:decidim, :initiatives, :default_components).and_return(expected) + + expect(subject.default_components).to eq expected + end + end + describe "#first_notification_percentage" do context "when rails secret '25'" do before do @@ -196,4 +222,48 @@ end end end + + describe ".print_enabled?" do + context "when rails secret has a value" do + [10, true, "hello"].each do |value| + it "returns false for '#{value}'" do + allow(Rails.application.secrets).to receive(:dig).with(:decidim, :initiatives, :print_enabled).and_return(value) + + expect(subject.print_enabled?).to be true + end + end + end + + context "when rails secret has no value" do + [false, nil, ""].each do |value| + it "returns false for '#{value}'" do + allow(Rails.application.secrets).to receive(:dig).with(:decidim, :initiatives, :print_enabled).and_return(value) + + expect(subject.print_enabled?).to be false + end + end + end + end + + describe ".do_not_require_authorization?" do + context "when rails secret has a value" do + [10, true, "hello"].each do |value| + it "returns false for '#{value}'" do + allow(Rails.application.secrets).to receive(:dig).with(:decidim, :initiatives, :do_not_require_authorization).and_return(value) + + expect(subject.do_not_require_authorization?).to be true + end + end + end + + context "when rails secret has no value" do + [false, nil, ""].each do |value| + it "returns false for '#{value}'" do + allow(Rails.application.secrets).to receive(:dig).with(:decidim, :initiatives, :do_not_require_authorization).and_return(value) + + expect(subject.do_not_require_authorization?).to be false + end + end + end + end end diff --git a/spec/lib/decidim_app/sentry_setup_spec.rb b/spec/lib/decidim_app/sentry_setup_spec.rb index 93a23c04d7..ef1a209afd 100644 --- a/spec/lib/decidim_app/sentry_setup_spec.rb +++ b/spec/lib/decidim_app/sentry_setup_spec.rb @@ -52,6 +52,23 @@ end end + describe "#sample_trace" do + let(:transaction_name) { "/some_page" } + let(:context) { { transaction_context: { op: "http", name: transaction_name } } } + + context "when transaction is about the health check" do + let(:transaction_name) { "/health_check" } + + it "returns 0" do + expect(subject.send(:sample_trace, context)).to eq 0.0 + end + end + + it "returns a Float" do + expect(subject.send(:sample_trace, context)).to be_a Float + end + end + describe ".ip" do it "returns the ip" do expect(subject.send(:ip)).to eq("123.123.123.123") diff --git a/spec/lib/migrations_fixer_spec.rb b/spec/lib/migrations_fixer_spec.rb new file mode 100644 index 0000000000..f926860d13 --- /dev/null +++ b/spec/lib/migrations_fixer_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require "spec_helper" + +require "migrations_fixer" + +RSpec.describe MigrationsFixer do + let(:logger) { Logger.new nil } + let(:migration_path_env) { Rails.root.to_s } + let(:instance) { described_class.new logger } + + before do + @old_migration_path_env = ENV.fetch("MIGRATIONS_PATH", nil) + ENV["MIGRATIONS_PATH"] = migration_path_env + end + + after do + ENV["MIGRATIONS_PATH"] = @old_migration_path_env # rubocop:disable RSpec/InstanceVariable + end + + describe ".new" do + context "with valid parameters" do + it "sets the logger" do + expect(instance.logger).to eq logger + end + + it "sets the migrations path" do + expect(instance.migrations_path).not_to be_blank + end + end + + context "with missing logger" do + let(:logger) { nil } + + it "raises an exception" do + expect do + described_class.new logger + end.to raise_error "Undefined logger" + end + end + + context "with missing environment" do + let(:migration_path_env) { nil } + + it "raises an exception" do + expect do + described_class.new logger + end.to raise_error "Invalid configuration, aborting" + end + end + + context "with non-existing MIGRATIONS_PATH variable" do + let(:migration_path_env) { "/some/inexistant/dir" } + + it "raises an exception" do + expect do + described_class.new logger + end.to raise_error "Invalid configuration, aborting" + end + end + + context "with missing project migrations" do + it "raises an exception" do + allow(ActiveRecord::Base.connection.migration_context.migrations_paths).to receive(:first).and_return "/some/invalid/directory" + + expect do + described_class.new logger + end.to raise_error "Invalid configuration, aborting" + end + end + end +end diff --git a/spec/lib/rails_migrations_spec.rb b/spec/lib/rails_migrations_spec.rb new file mode 100644 index 0000000000..f47d15c488 --- /dev/null +++ b/spec/lib/rails_migrations_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require "spec_helper" + +require "rails_migrations" +require "migrations_fixer" + +class FakeMigrationsFixer + attr_reader :logger + + def initialize(logger) + @logger = logger + end + + def osp_app_path + "/some/dir" + end + + def migrations_path + "/something_else" + end +end + +RSpec.describe RailsMigrations do + let(:logger) { Logger.new nil } + let(:migration_fixer) { FakeMigrationsFixer.new logger } + let(:instance) { described_class.new migration_fixer } + let(:migrations_status) do + [ + ["up", "20230824135802", "Change something in db structure"], + ["down", "20230824135803", "Change something else"], + ["down", "20230824135804", "********** NO FILE **********"] + ] + end + + before do + allow(instance).to receive(:migration_status).and_return migrations_status + instance.reload_migrations! + end + + describe "#reload_down!" do + it "reloads and find down migrations" do + allow(instance).to receive(:reload_migrations!) + allow(instance).to receive(:down) + + instance.reload_down! + + aggregate_failures do + expect(instance).to have_received(:reload_migrations!) + expect(instance).to have_received(:down) + end + end + end + + describe "#down" do + it "returns all migrations marked 'down'" do + expect(instance.down.size).to eq 2 + end + end + + describe "#reload_migrations!" do + it "resets @fetch_all" do + new_list = [1, 2, 3] + allow(instance).to receive(:migration_status).and_return new_list + + instance.reload_migrations! + expect(instance.fetch_all).to eq new_list + end + end + + describe "#display_status!" do + it "logs statuses" do + allow(logger).to receive(:info) + + instance.display_status! + + expect(logger).to have_received(:info).exactly(3).times + end + end + + describe "#not_found" do + it "returns the amount of missing migrations files" do + expect(instance.not_found.size).to eq 1 + end + end + + describe "#versions_down_but_already_passed" do + it "returns the list of possible files for missing versions" do + allow(Dir).to receive(:glob).and_return ["20230824135804_change_something_else_again.rb"] + expect(instance.versions_down_but_already_passed).to eq ["20230824135804"] + end + end +end diff --git a/spec/lib/rspec_runner_spec.rb b/spec/lib/rspec_runner_spec.rb index 70db486aa5..5411e53473 100644 --- a/spec/lib/rspec_runner_spec.rb +++ b/spec/lib/rspec_runner_spec.rb @@ -69,6 +69,38 @@ module Decidim end end + describe "#for" do + context "with missing arguments" do + it "fails without pattern" do + expect do + described_class.for nil, mask, slice + end.to raise_error("Missing pattern") + end + + it "fails without mask" do + expect do + described_class.for pattern, nil, slice + end.to raise_error("Missing mask") + end + + it "fails without slice" do + expect do + described_class.for pattern, mask, nil + end.to raise_error("Missing slice") + end + end + + context "with all the arguments" do + # This is tightly coupled with the implementation + it "runs the suite" do + allow(described_class).to receive(:new).and_return subject + allow(subject).to receive(:run).and_return "__success__" + + expect(described_class.for(pattern, mask, slice)).to eq "__success__" + end + end + end + describe "#sliced_files" do before do allow(Dir).to receive(:glob).and_return(files) diff --git a/spec/lib/tasks/decidim/db/admin_log/clear_spec.rb b/spec/lib/tasks/decidim/db/admin_log/clear_spec.rb new file mode 100644 index 0000000000..2f03d7b1a0 --- /dev/null +++ b/spec/lib/tasks/decidim/db/admin_log/clear_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "rake decidim:db:admin_log:clean", type: :task do + it "preloads the Rails environment" do + expect(task.prerequisites).to include "environment" + end + + it "invokes the 'clear' method" do + stub = Decidim::ActionLogService.new + allow(Decidim::ActionLogService).to receive(:new).and_return stub + allow(stub).to receive(:clear).and_return(true) + + task.execute + + expect(stub).to have_received(:clear) + end +end diff --git a/spec/lib/tasks/decidim/db/admin_log/orphans_spec.rb b/spec/lib/tasks/decidim/db/admin_log/orphans_spec.rb new file mode 100644 index 0000000000..1acb661c93 --- /dev/null +++ b/spec/lib/tasks/decidim/db/admin_log/orphans_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "rake decidim:db:admin_log:orphans", type: :task do + it "preloads the Rails environment" do + expect(task.prerequisites).to include "environment" + end + + it "invokes the 'orphans' method" do + stub = Decidim::ActionLogService.new + allow(Decidim::ActionLogService).to receive(:new).and_return stub + allow(stub).to receive(:orphans).and_return(true) + + task.execute + + expect(stub).to have_received(:orphans) + end +end diff --git a/spec/lib/tasks/decidim/db/notification/clear_spec.rb b/spec/lib/tasks/decidim/db/notification/clear_spec.rb new file mode 100644 index 0000000000..9b5b9d29a0 --- /dev/null +++ b/spec/lib/tasks/decidim/db/notification/clear_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "rake decidim:db:notification:clean", type: :task do + it "preloads the Rails environment" do + expect(task.prerequisites).to include "environment" + end + + it "invokes the 'clear' method" do + stub = Decidim::NotificationService.new + allow(Decidim::NotificationService).to receive(:new).and_return stub + allow(stub).to receive(:clear).and_return(true) + + task.execute + + expect(stub).to have_received(:clear) + end +end diff --git a/spec/lib/tasks/decidim/db/notification/orphans_spec.rb b/spec/lib/tasks/decidim/db/notification/orphans_spec.rb new file mode 100644 index 0000000000..621a1ab025 --- /dev/null +++ b/spec/lib/tasks/decidim/db/notification/orphans_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "rake decidim:db:notification:orphans", type: :task do + it "preloads the Rails environment" do + expect(task.prerequisites).to include "environment" + end + + it "invokes the 'orphans' method" do + stub = Decidim::NotificationService.new + allow(Decidim::NotificationService).to receive(:new).and_return stub + allow(stub).to receive(:orphans).and_return(true) + + task.execute + + expect(stub).to have_received(:orphans) + end +end diff --git a/spec/lib/tasks/decidim/db/surveys/clear_spec.rb b/spec/lib/tasks/decidim/db/surveys/clear_spec.rb new file mode 100644 index 0000000000..a61433cbe8 --- /dev/null +++ b/spec/lib/tasks/decidim/db/surveys/clear_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "rake decidim:db:surveys:clean", type: :task do + it "preloads the Rails environment" do + expect(task.prerequisites).to include "environment" + end + + it "invokes the 'clear' method" do + stub = Decidim::SurveysService.new + allow(Decidim::SurveysService).to receive(:new).and_return stub + allow(stub).to receive(:clear).and_return(true) + + task.execute + + expect(stub).to have_received(:clear) + end +end diff --git a/spec/lib/tasks/decidim/db/surveys/orphans_spec.rb b/spec/lib/tasks/decidim/db/surveys/orphans_spec.rb new file mode 100644 index 0000000000..1d9747995a --- /dev/null +++ b/spec/lib/tasks/decidim/db/surveys/orphans_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "rake decidim:db:surveys:orphans", type: :task do + it "preloads the Rails environment" do + expect(task.prerequisites).to include "environment" + end + + it "invokes the 'orphans' method" do + stub = Decidim::SurveysService.new + allow(Decidim::SurveysService).to receive(:new).and_return stub + allow(stub).to receive(:orphans).and_return(true) + + task.execute + + expect(stub).to have_received(:orphans) + end +end diff --git a/spec/lib/tasks/decidim/repair/comments_spec.rb b/spec/lib/tasks/decidim/repair/comments_spec.rb new file mode 100644 index 0000000000..8b1b7ca10b --- /dev/null +++ b/spec/lib/tasks/decidim/repair/comments_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe "rake decidim:repair:comments", type: :task do + it "uses the appropriate service" do + allow(Decidim::RepairCommentsService).to receive(:run) + + task.execute + + expect(Decidim::RepairCommentsService).to have_received(:run).once + end + + describe "logging" do + let!(:logger) { Logger.new($stdout) } + + before do + # Stub the logger + allow(logger).to receive(:info) + allow(Logger).to receive(:new).and_return(logger) + + allow(Decidim::RepairCommentsService).to receive(:run).and_return updated_comments_ids + end + + context "when no nickname was repaired" do + let(:updated_comments_ids) { [] } + + it "logs a message" do + task.execute + + expect(logger).to have_received(:info).with("No comments updated") + end + end + + context "when some nicknames were repaired" do + let(:updated_comments_ids) { [1, 2, 3] } + + it "logs a message" do + task.execute + + expect(logger).to have_received(:info).with("Updated comments ID : 1, 2, 3") + end + end + end +end diff --git a/spec/lib/tasks/decidim/repair/nickname_spec.rb b/spec/lib/tasks/decidim/repair/nickname_spec.rb new file mode 100644 index 0000000000..60f157c18d --- /dev/null +++ b/spec/lib/tasks/decidim/repair/nickname_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe "rake decidim:repair:nickname", type: :task do + it "uses the appropriate service" do + allow(Decidim::RepairNicknameService).to receive(:run) + + task.execute + + expect(Decidim::RepairNicknameService).to have_received(:run).once + end + + describe "logging" do + let!(:logger) { Logger.new($stdout) } + + before do + # Stub the logger + allow(logger).to receive(:info) + allow(Logger).to receive(:new).and_return(logger) + + allow(Decidim::RepairNicknameService).to receive(:run).and_return updated_user_ids + end + + context "when no nickname was repaired" do + let(:updated_user_ids) { [] } + + it "logs a message" do + task.execute + + expect(logger).to have_received(:info).with("No users updated") + end + end + + context "when some nicknames were repaired" do + let(:updated_user_ids) { [1, 2, 3] } + + it "logs a message" do + task.execute + + expect(logger).to have_received(:info).with("Updated users ID : 1, 2, 3") + end + end + end +end diff --git a/spec/lib/tasks/repair_data_translations_spec.rb b/spec/lib/tasks/decidim/repair/translations_spec.rb similarity index 55% rename from spec/lib/tasks/repair_data_translations_spec.rb rename to spec/lib/tasks/decidim/repair/translations_spec.rb index 328994515b..f419c48485 100644 --- a/spec/lib/tasks/repair_data_translations_spec.rb +++ b/spec/lib/tasks/decidim/repair/translations_spec.rb @@ -36,4 +36,36 @@ task.execute end end + + describe "logging" do + let!(:logger) { Logger.new($stdout) } + + before do + # Stub the logger + allow(logger).to receive(:info) + allow(Logger).to receive(:new).and_return(logger) + + allow(Decidim::RepairTranslationsService).to receive(:run).and_return updated_resources_ids + end + + context "when no nickname was repaired" do + let(:updated_resources_ids) { [] } + + it "logs a message" do + task.execute + + expect(logger).to have_received(:info).with("No resources updated") + end + end + + context "when some nicknames were repaired" do + let(:updated_resources_ids) { [1, 2, 3] } + + it "logs a message" do + task.execute + + expect(logger).to have_received(:info).with("Enqueued resources : 1, 2, 3") + end + end + end end diff --git a/spec/lib/tasks/repair_data_url_in_content_spec.rb b/spec/lib/tasks/decidim/repair/url_in_content_spec.rb similarity index 100% rename from spec/lib/tasks/repair_data_url_in_content_spec.rb rename to spec/lib/tasks/decidim/repair/url_in_content_spec.rb diff --git a/spec/lib/tasks/decidim_app/k8s/install_task_spec.rb b/spec/lib/tasks/decidim_app/k8s/install_task_spec.rb new file mode 100644 index 0000000000..9386dde5a1 --- /dev/null +++ b/spec/lib/tasks/decidim_app/k8s/install_task_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "rake decidim_app:k8s:install", type: :task do + it "preloads the Rails environment" do + expect(task.prerequisites).to include "environment" + end + + it "calls db:migrate" do + expect(Rake::Task["db:migrate"]).to receive(:invoke) + + task.execute + end +end diff --git a/spec/services/decidim/action_log_service_spec.rb b/spec/services/decidim/action_log_service_spec.rb index 1f0a7de1e6..98d6fd600f 100644 --- a/spec/services/decidim/action_log_service_spec.rb +++ b/spec/services/decidim/action_log_service_spec.rb @@ -40,4 +40,16 @@ end.to change(Decidim::ActionLog, :count).from(10).to(0) end end + + describe "#orphans_for" do + context "when the class does not exist" do + it "logs the error" do + logger = Logger.new($stdout) + allow(logger).to receive(:warn) + described_class.new(logger: logger).send(:orphans_for, "NonExistingClass") + + expect(logger).to have_received(:warn).with("Skipping class : NonExistingClass") + end + end + end end diff --git a/spec/services/decidim/database_service_spec.rb b/spec/services/decidim/database_service_spec.rb index 613f43064e..2e2d13d7ac 100644 --- a/spec/services/decidim/database_service_spec.rb +++ b/spec/services/decidim/database_service_spec.rb @@ -2,6 +2,18 @@ require "spec_helper" +class FakeDatabaseService < Decidim::DatabaseService + def initialize(resource_types: nil, **args) + @resource_types = resource_types + + super(**args) + end + + def resource_types # rubocop:disable Style/TrivialAccessors + @resource_types + end +end + describe Decidim::DatabaseService do subject { described_class.new } @@ -28,4 +40,19 @@ end.to raise_error RuntimeError, "Method clear_data_for isn't defined for Decidim::DatabaseService" end end + + describe "when used as class parent" do + let(:fake_instance) { FakeDatabaseService.new(**instance_args) } + let(:instance_args) { {} } + + describe "#orphans" do + context "with no resource type" do + let(:instance_args) { { resource_types: nil } } + + it "returns nil" do + expect(fake_instance.orphans).to be_nil + end + end + end + end end diff --git a/spec/services/decidim/s3_retention_service_spec.rb b/spec/services/decidim/s3_retention_service_spec.rb new file mode 100644 index 0000000000..c6f46a9c3f --- /dev/null +++ b/spec/services/decidim/s3_retention_service_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Decidim::S3RetentionService do + let(:options) { {} } + let(:instance) { described_class.new(options) } + + describe ".run" do + it "executes the service" do + allow(described_class).to receive(:new).with(options).and_return instance + allow(instance).to receive(:execute).and_return "__success__" + + expect(described_class.run({})).to eq "__success__" + end + end + + describe "#default_options" do + let(:option_keys) { instance.default_options.keys } + + it "returns a hash" do + expect(instance.default_options).to be_a Hash + end + + it "has keys existing in backup configuration" do + config_keys = Rails.application.config.backup[:s3sync].keys + .map { |k| "s3_#{k}".to_sym } + + aggregate_failures do + option_keys.each do |key| + expect(config_keys).to include key + end + end + end + end + + describe "#subfolder" do + it "returns a memoized string" do + subfolder = instance.subfolder + + expect(subfolder).to be_a String + expect(instance.instance_variable_get(:@subfolder)).to eq subfolder + end + + context "with an option given" do + let(:options) { { subfolder: "something" } } + + it "uses the given path" do + expect(instance.subfolder).to eq "something" + end + end + + context "without an option given" do + it "generates a path" do + expect(instance.subfolder).not_to be_blank + end + end + end + + describe "#retention_dates" do + let(:retention_dates) { instance.retention_dates } + + it "returns an array" do + expect(instance.retention_dates).to be_a Array + end + + it "contains no duplicates" do + expect(retention_dates.size).to eq retention_dates.uniq.size + end + end + + describe "#service" do + it "memoizes the storage service" do + allow(Fog::Storage).to receive(:new).and_return("__success__") + + 2.times { instance.send(:service) } + expect(Fog::Storage).to have_received(:new).once + end + end +end diff --git a/spec/services/decidim/s3_sync_service_spec.rb b/spec/services/decidim/s3_sync_service_spec.rb new file mode 100644 index 0000000000..ddc4c9d98b --- /dev/null +++ b/spec/services/decidim/s3_sync_service_spec.rb @@ -0,0 +1,166 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Decidim::S3SyncService do + let(:temp_directory) { Dir.mktmpdir } + let(:options) { {} } + let(:instance) { described_class.new(options) } + + after do + FileUtils.rm_rf temp_directory + end + + describe ".run" do + it "executes the service" do + allow(described_class).to receive(:new).with(options).and_return instance + allow(instance).to receive(:execute).and_return "__success__" + + expect(described_class.run({})).to eq "__success__" + end + end + + describe "#default_options" do + let(:option_keys) { instance.default_options.keys } + + it "returns a hash" do + expect(instance.default_options).to be_a Hash + end + + it "has keys existing in backup configuration" do + config_keys = Rails.application.config.backup[:s3sync].keys + .map { |k| "s3_#{k}".to_sym } + + aggregate_failures do + option_keys.filter { |k| k.match?(/^s3_/) }.each do |key| + expect(config_keys).to include key + end + end + end + end + + describe "#has_local_backup_directory?" do + let(:options) { { local_backup_dir: temp_directory } } + + context "when the directory exists and is readable" do + it "returns true" do + expect(instance.has_local_backup_directory?).to be true + end + end + + context "when the directory does not exists" do + before { FileUtils.rm_rf temp_directory } + + it "returns false" do + expect(instance.has_local_backup_directory?).to be false + end + end + + context "when the directory exists but is not readable" do + before { FileUtils.chmod("ugo=wx", temp_directory) } + + it "returns false" do + expect(instance.has_local_backup_directory?).to be false + end + end + end + + describe "#subfolder" do + it "returns a memoized string" do + subfolder = instance.subfolder + + expect(subfolder).to be_a String + expect(instance.instance_variable_get(:@subfolder)).to eq subfolder + end + + context "with an option given" do + let(:options) { { subfolder: "something" } } + + it "uses the given path" do + expect(instance.subfolder).to eq "something" + end + end + + context "without an option given" do + it "generates a path" do + expect(instance.subfolder).not_to be_blank + end + end + end + + describe "#force_upload?" do + context "when option was not provided" do + it "defaults to false" do + expect(instance.force_upload?).to be false + end + end + + [true, false].each do |state| + context "when option was set to #{state}" do + let(:options) { { force_upload: state } } + + it "returns #{state}" do + expect(instance.force_upload?).to be state + end + end + end + end + + describe "#timestamp" do + it "returns a memoized string" do + timestamp = instance.timestamp + + expect(timestamp).to be_a String + expect(instance.instance_variable_get(:@timestamp)).to eq timestamp + end + end + + describe "#file_list" do + context "when no file list was provided" do + let(:options) { { local_backup_dir: temp_directory } } + + before do + Dir.chdir(temp_directory) { `touch file_1.txt file_2.txt` } + end + + it "reads from the backup directory" do + expected = [ + "#{temp_directory}/file_1.txt", + "#{temp_directory}/file_2.txt" + ] + expect(instance.file_list.sort).to eq expected + end + end + + context "when both a file list and a directory are provided" do + let(:options) do + { + local_backup_dir: temp_directory, + local_backup_files: %w(file_list_1.txt file_list_2.txt) + } + end + + before do + Dir.chdir(temp_directory) { `touch file_1.txt file_2.txt` } + end + + it "reads from the file list" do + expected = [ + "file_list_1.txt", + "file_list_2.txt" + ] + + expect(instance.file_list.sort).to eq expected + end + end + end + + describe "#service" do + it "memoizes the storage service" do + allow(Fog::Storage).to receive(:new).and_return("__success__") + + 2.times { instance.send(:service) } + expect(Fog::Storage).to have_received(:new).once + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d00ba7081b..af1e085061 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -9,6 +9,7 @@ RSpec.configure do |config| config.formatter = ENV.fetch("RSPEC_FORMAT", "progress").to_sym config.include EnvironmentVariablesHelper + config.include SkipIfUndefinedHelper config.before do # Initializers configs diff --git a/spec/support/skip_if_undefined_helper.rb b/spec/support/skip_if_undefined_helper.rb new file mode 100644 index 0000000000..adc421ffc7 --- /dev/null +++ b/spec/support/skip_if_undefined_helper.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module SkipIfUndefinedHelper + # Skips a test if a given class is undefined (i.e. : from another gem) + def skip_if_undefined(klass, gem) + skip "'#{gem}' gem is not present" unless klass.safe_constantize + end +end From a489a50dfb8ae348f7dc2ca60d3a0f2857bf7202 Mon Sep 17 00:00:00 2001 From: moustachu