diff --git a/lib/pact_broker/db/clean.rb b/lib/pact_broker/db/clean.rb index 5e910795f..71f8c5c7c 100644 --- a/lib/pact_broker/db/clean.rb +++ b/lib/pact_broker/db/clean.rb @@ -14,40 +14,91 @@ def initialize database_connection, options = {} end def call + deleted_counts = {} + kept_counts = {} + date = options[:date] + pact_publication_ids_to_delete = if date + db[:pact_publications].select(:id).where(Sequel.lit('created_at < ?', date)) + else + db[:pact_publications].select(:id).where(id: db[:head_matrix].select(:pact_publication_id)).invert + end + + deleted_counts[:pact_publications] = pact_publication_ids_to_delete.count + kept_counts[:pact_publications] = db[:pact_publications].where(id: pact_publication_ids_to_delete).invert.count + # TODO head matrix is the head for the consumer tags, not the provider tags. # Work out how to keep the head verifications for the provider tags. - verification_ids = db[:verifications].where(id: db[:head_matrix].select(:verification_id)).invert.select(:verification_id) - - triggered_webhook_ids = db[:triggered_webhooks].where(verification_id: verification_ids).select(:id) - db[:webhook_executions].where(triggered_webhook_id: triggered_webhook_ids).delete - db[:triggered_webhooks].where(id: triggered_webhook_ids).delete + verification_ids = get_verification_ids(pact_publication_ids_to_delete) + deleted_counts[:verification_results] = verification_ids.count + kept_counts[:verification_results] = db[:verifications].where(id:verification_ids ).invert.count + delete_webhook_data(db[:triggered_webhooks].where(verification_id: verification_ids).select(:id)) verification_ids.delete - pp_ids = db[:head_matrix].select(:pact_publication_id) + delete_webhook_data(db[:triggered_webhooks].where(pact_publication_id: pact_publication_ids_to_delete).select(:id)) + delete_deprecated_webhook_executions(pact_publication_ids_to_delete) + delete_pact_publications(pact_publication_ids_to_delete) + + delete_orphan_pact_versions + overwritten_delete_counts = delete_overwritten_verifications + deleted_counts[:verification_results] = deleted_counts[:verification_results] + overwritten_delete_counts[:verification_results] + kept_counts[:verification_results] = kept_counts[:verification_results] - overwritten_delete_counts[:verification_results] + + + referenced_version_ids = db[:pact_publications].select(:consumer_version_id).collect{ | h| h[:consumer_version_id] } + + db[:verifications].select(:provider_version_id).collect{ | h| h[:provider_version_id] } + + delete_orphan_tags(referenced_version_ids) + delete_orphan_versions(referenced_version_ids) + + { kept: kept_counts, deleted: deleted_counts } + end + + private + + attr_reader :db, :options + + def get_verification_ids(pact_publication_ids) + db[:verifications].select(:id).where(pact_version_id: db[:pact_publications].select(:pact_version_id).where(id: pact_publication_ids)) + end - triggered_webhook_ids = db[:triggered_webhooks].where(pact_publication_id: pp_ids).invert.select(:id) + def delete_webhook_data(triggered_webhook_ids) db[:webhook_executions].where(triggered_webhook_id: triggered_webhook_ids).delete db[:triggered_webhooks].where(id: triggered_webhook_ids).delete - db[:webhook_executions].where(pact_publication_id: pp_ids).invert.delete - db[:pact_publications].where(id: pp_ids).invert.delete + end + def delete_deprecated_webhook_executions(pact_publication_ids) + db[:webhook_executions].where(pact_publication_id: pact_publication_ids).delete + end + + def delete_pact_publications(pact_publication_ids) + db[:pact_publications].where(id: pact_publication_ids).delete + db[:pact_versions].where(id: db[:pact_publications].select(:pact_version_id)).invert.delete + end + + def delete_orphan_pact_versions + # TODO use union referenced_pact_version_ids = db[:pact_publications].select(:pact_version_id).collect{ | h| h[:pact_version_id] } + db[:verifications].select(:pact_version_id).collect{ | h| h[:pact_version_id] } db[:pact_versions].where(id: referenced_pact_version_ids).invert.delete + end - referenced_version_ids = db[:pact_publications].select(:consumer_version_id).collect{ | h| h[:consumer_version_id] } + - db[:verifications].select(:provider_version_id).collect{ | h| h[:provider_version_id] } - + def delete_orphan_tags(referenced_version_ids) db[:tags].where(version_id: referenced_version_ids).invert.delete - db[:versions].where(id: referenced_version_ids).invert.delete end - private - - attr_reader :db + def delete_orphan_versions(referenced_version_ids) + db[:versions].where(id: referenced_version_ids).invert.delete + end + def delete_overwritten_verifications + verification_ids = db[:verifications].select(:id).where(id: db[:latest_verification_id_for_pact_version_and_provider_version].select(:verification_id)).invert + deleted_counts = { verification_results: verification_ids.count } + delete_webhook_data(db[:triggered_webhooks].where(verification_id: verification_ids).select(:id)) + verification_ids.delete + deleted_counts + end end end end diff --git a/spec/lib/pact_broker/db/clean_spec.rb b/spec/lib/pact_broker/db/clean_spec.rb index e770a014d..ea52ec626 100644 --- a/spec/lib/pact_broker/db/clean_spec.rb +++ b/spec/lib/pact_broker/db/clean_spec.rb @@ -4,11 +4,14 @@ module PactBroker module DB - describe Clean do - # Inner queries don't work on MySQL. Seriously, MySQL??? - describe ".call", pending: IS_MYSQL do - let(:td) { TestDataBuilder.new } - let(:db) { PactBroker::DB.connection } + # Inner queries don't work on MySQL. Seriously, MySQL??? + describe Clean, pending: IS_MYSQL do + let(:options) { {} } + let(:db) { PactBroker::DB.connection } + + subject { Clean.call(PactBroker::DB.connection, options) } + + describe ".call"do before do td.create_pact_with_hierarchy("Foo", "0", "Bar") @@ -33,10 +36,10 @@ module DB .create_pact .comment("keep") .create_verification(provider_version: "40") - .create_verification(provider_version: "50", number: 2) + .create_verification(provider_version: "40", number: 2) + .create_verification(provider_version: "50", number: 3) end - subject { Clean.call(PactBroker::DB.connection) } it "does not delete any rows in the head matrix" do head_matrix_before = db[:head_matrix].select_all @@ -59,9 +62,64 @@ module DB subject expect(db[:versions].where(number: "20").count).to be 1 expect(db[:versions].where(number: "30").count).to be 0 - expect(db[:versions].where(number: "40").count).to be 0 + expect(db[:versions].where(number: "40").count).to be 1 expect(db[:versions].where(number: "50").count).to be 1 end + + it "deletes overwritten verifications" do + expect(db[:matrix].where(provider_version_number: "40").count).to eq 2 + subject + expect(db[:matrix].where(provider_version_number: "40", verification_number: 2).count).to eq 1 + end + end + + describe ".call with a date" do + before do + td.set_now(DateTime.new(2019, 1, 1)) + .create_pact_with_hierarchy + .create_verification + end + let(:options) { { date: date } } + + context "when the data is older than the given date" do + let(:date) { DateTime.new(2019, 1, 2) } + let(:expected_report) do + { + kept: { pact_publications: 0, verification_results: 0 }, + deleted: { pact_publications: 1, verification_results: 1 } + } + end + + it "is deleted" do + subject + expect(db[:head_matrix].count).to be 0 + end + + it "returns a report" do + expect(subject).to include(expected_report) + end + end + + context "when the data is not older than the given date" do + let(:date) { DateTime.new(2019, 1, 1) } + let(:expected_report) do + { + kept: { pact_publications: 1, verification_results: 1 }, + deleted: { pact_publications: 0, verification_results: 0 } + } + end + + it "is not deleted" do + subject + expect(db[:head_matrix].count).to be 1 + expect(db[:pact_publications].count).to be 1 + expect(db[:verifications].count).to be 1 + end + + it "returns a report" do + expect(subject).to include(expected_report) + end + end end end end