Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rustemmukhamadiev/d2b8716dd48f251500d4a963331a6a0a to your computer and use it in GitHub Desktop.
Save rustemmukhamadiev/d2b8716dd48f251500d4a963331a6a0a to your computer and use it in GitHub Desktop.
Рейк таски
class RecalculateControlsPassedColumnWithNotApplicable < GrcShared::DoctorBase
def invalid_records
Control.joins(:control_tests, :walkthrough)
.where(walkthroughs: { control_verified: [true, nil] })
.where(control_tests: { not_applicable: true })
.distinct
.ids
end
def perform
ActivityLogging.disabled do
doctor do
invalid_records.in_groups_of(1000, false) do |ids|
result = ActiveRecord::Base.connection.execute(update_query(ids))
increment_changed_count by: result.cmd_tuples
end
end
end
end
private
def doctor
display_mode
display_start_info
yield unless dry_run?
display_finish_info
end
def join_ids(ids)
ids.join(", ")
end
def control_passed_query(control_ids)
<<-SQL
SELECT
ctl.id,
(
CASE WHEN #{passed_null} THEN NULL ELSE
CASE WHEN #{passed_true} THEN TRUE ELSE
FALSE END
END
) AS passed
FROM controls ctl
LEFT JOIN control_tests ON control_tests.control_id = ctl.id AND control_tests.not_applicable IS FALSE
LEFT JOIN walkthroughs ON walkthroughs.control_id = ctl.id
WHERE ctl.id IN (#{join_ids(control_ids)})
GROUP BY ctl.id, walkthroughs.control_verified
SQL
end
def passed_null
<<-SQL
(
walkthroughs.control_verified IS TRUE AND
COUNT(control_tests.id) > 0 AND
COUNT(CASE WHEN control_tests.conclusion IS NULL THEN 1 ELSE NULL END) > 0 AND
COUNT(CASE WHEN control_tests.conclusion IS FALSE THEN 1 ELSE NULL END) = 0
) OR (
walkthroughs.control_verified IS NULL AND
COUNT(CASE WHEN control_tests.conclusion IS FALSE THEN 1 ELSE NULL END) = 0
)
SQL
end
def passed_true
<<-SQL
walkthroughs.control_verified IS TRUE AND
(
COUNT(control_tests.id) = 0 OR
BOOL_AND(COALESCE(control_tests.conclusion, false)) IS TRUE
)
SQL
end
def update_query(control_ids)
<<-SQL
UPDATE controls
SET passed = x.passed
FROM (#{control_passed_query(control_ids)}) x
WHERE controls.id = x.id AND controls.id IN (#{join_ids(control_ids)})
SQL
end
end
require "spec_helper"
require "tasks/support/recalculate_controls_passed_column_with_not_applicable"
describe RecalculateControlsPassedColumnWithNotApplicable do
describe "#perform" do
let(:audit) { create :audit }
let(:objective) { create :objective, audit: audit }
let(:control) { create :control, objective: objective }
def perform
described_class.new.perform
end
shared_examples_for "rake-task that updates Control's passed column" do |current_value:, new_value:|
it "updates Control's passed column" do
control.update_column(:passed, current_value)
expect { perform }.to change { control.reload.passed }.from(current_value).to(new_value)
end
end
shared_examples_for "rake-task that does NOT update Control's passed column" do |current_value:|
it "does NOT update Control's passed column" do
control.update_column(:passed, current_value)
expect { perform }.not_to change { control.reload.passed }
end
end
shared_examples "all Control Tests are PASSED" do |current_value:|
context "when all Control Tests are PASSED" do
before { control.control_tests.update_all(conclusion: true) }
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
context "and NOT applicable" do
before { control.control_tests.update_all(not_applicable: true) }
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
end
end
shared_examples "all Control Tests are FAILED" do |should_update:, current_value:, na_value:|
context "when all Control Tests are FAILED" do
before { control.control_tests.update_all(conclusion: false) }
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
context "and NOT applicable" do
before { control.control_tests.update_all(not_applicable: true) }
if should_update
it_behaves_like "rake-task that updates Control's passed column",
current_value: current_value,
new_value: na_value
else
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
end
end
end
shared_examples "all Control Tests are NOT TESTED" do |should_update:, current_value:, na_value:|
context "when all Control Tests are NOT TESTED" do
before { control.control_tests.update_all(conclusion: nil) }
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
context "and NOT applicable" do
before { control.control_tests.update_all(not_applicable: true) }
if should_update
it_behaves_like "rake-task that updates Control's passed column",
current_value: current_value,
new_value: na_value
else
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
end
end
end
shared_examples "Control Tests are PASSED and FAILED" do |should_update:, current_value:, failed_na_value:|
context "when Control Tests are PASSED and FAILED" do
before do
control.control_tests.update_all(conclusion: true)
control.control_tests.first.update_column(:conclusion, false)
end
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
context "and FAILED is NOT applicable" do
before do
control.control_tests.where(conclusion: false).update_all(not_applicable: true)
end
if should_update
it_behaves_like "rake-task that updates Control's passed column",
current_value: current_value,
new_value: failed_na_value
else
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
end
context "and PASSED is NOT applicable" do
before do
control.control_tests.where(conclusion: true).update_all(not_applicable: true)
end
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
end
end
shared_examples "Control Tests are PASSED and NOT TESTED" do |should_update:, current_value:, not_tested_na_value:|
context "when Control Tests are PASSED and NOT TESTED" do
before do
control.control_tests.update_all(conclusion: true)
control.control_tests.first.update_column(:conclusion, nil)
end
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
context "and NOT TESTED is NOT applicable" do
before do
control.control_tests.where(conclusion: nil).update_all(not_applicable: true)
end
if should_update
it_behaves_like "rake-task that updates Control's passed column",
current_value: current_value,
new_value: not_tested_na_value
else
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
end
context "and PASSED is NOT applicable" do
before do
control.control_tests.where(conclusion: true).update_all(not_applicable: true)
end
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
end
end
shared_examples "Control Tests are FAILED and NOT TESTED" do |should_update:, current_value:, failed_na_value:|
context "when Control Tests are FAILED and NOT TESTED" do
before do
control.control_tests.update_all(conclusion: false)
control.control_tests.first.update_column(:conclusion, nil)
end
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
context "and NOT TESTED is NOT applicable" do
before do
control.control_tests.where(conclusion: nil).update_all(not_applicable: true)
end
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
context "and FAILED is NOT applicable" do
before do
control.control_tests.where(conclusion: false).update_all(not_applicable: true)
end
if should_update
it_behaves_like "rake-task that updates Control's passed column",
current_value: current_value,
new_value: failed_na_value
else
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
end
end
end
shared_examples "Control has no Control Tests" do |current_value:|
context "when Control has no Control Tests" do
before { control.control_tests.destroy_all }
it_behaves_like "rake-task that does NOT update Control's passed column", current_value: current_value
end
end
context "when in dry-run mode" do
context "and Control's Walkthrough is PASSED" do
before { control.walkthrough.update_column(:control_verified, true) }
include_examples "all Control Tests are NOT TESTED",
should_update: false,
current_value: false,
na_value: false
include_examples "Control Tests are PASSED and NOT TESTED",
should_update: false,
current_value: false,
not_tested_na_value: false
end
context "and Control's Walkthrough is NOT TESTED" do
before { control.walkthrough.update_column(:control_verified, nil) }
include_examples "all Control Tests are PASSED", current_value: false
include_examples "all Control Tests are NOT TESTED",
should_update: false,
current_value: false,
na_value: false
include_examples "Control Tests are PASSED and NOT TESTED",
should_update: false,
current_value: false,
not_tested_na_value: false
include_examples "Control has no Control Tests", current_value: false
end
end
context "when in live mode" do
before do
allow(ENV).to receive(:[]).with("LIVE").and_return("true")
end
context "and Control's Walkthrough is PASSED" do
before { control.walkthrough.update_column(:control_verified, true) }
include_examples "all Control Tests are PASSED", current_value: true
include_examples "all Control Tests are FAILED",
should_update: true,
current_value: false,
na_value: true
include_examples "all Control Tests are NOT TESTED",
should_update: true,
current_value: nil,
na_value: true
include_examples "Control Tests are PASSED and FAILED",
should_update: true,
current_value: false,
failed_na_value: true
include_examples "Control Tests are PASSED and NOT TESTED",
should_update: true,
current_value: nil,
not_tested_na_value: true
include_examples "Control Tests are FAILED and NOT TESTED",
should_update: true,
current_value: false,
failed_na_value: nil
include_examples "Control has no Control Tests", current_value: true
end
context "and Control's Walkthrough is FAILED" do
before { control.walkthrough.update_column(:control_verified, false) }
include_examples "all Control Tests are PASSED", current_value: false
include_examples "all Control Tests are FAILED",
should_update: false,
current_value: false,
na_value: false
include_examples "all Control Tests are NOT TESTED",
should_update: false,
current_value: false,
na_value: false
include_examples "Control Tests are PASSED and FAILED",
should_update: false,
current_value: false,
failed_na_value: false
include_examples "Control Tests are PASSED and NOT TESTED",
should_update: false,
current_value: false,
not_tested_na_value: false
include_examples "Control Tests are FAILED and NOT TESTED",
should_update: false,
current_value: false,
failed_na_value: false
include_examples "Control has no Control Tests", current_value: false
end
context "and Control's Walkthrough is NOT TESTED" do
before { control.walkthrough.update_column(:control_verified, nil) }
include_examples "all Control Tests are PASSED", current_value: nil
include_examples "all Control Tests are FAILED",
should_update: false,
current_value: nil,
na_value: nil
include_examples "all Control Tests are NOT TESTED",
should_update: false,
current_value: nil,
na_value: nil
include_examples "Control Tests are PASSED and FAILED",
should_update: true,
current_value: false,
failed_na_value: nil
include_examples "Control Tests are PASSED and NOT TESTED",
should_update: nil,
current_value: nil,
not_tested_na_value: nil
include_examples "Control Tests are FAILED and NOT TESTED",
should_update: true,
current_value: false,
failed_na_value: nil
include_examples "Control has no Control Tests", current_value: nil
end
end
end
end
class RemoveWhitespacesFromFindingsFields < GrcShared::DoctorBase
TRIM_CHARACTER = "'\s\n\t\r'".freeze
def invalid_records
Finding.where(id: invalid_records_ids)
end
def perform
ActivityLogging.disabled do
doctor do
return if invalid_records_ids.count == 0
result = ActiveRecord::Base.connection.execute(update_query(invalid_records_ids))
increment_changed_count by: result.cmd_tuples
end
end
end
private
def invalid_records_ids
@_invalid_records_ids ||= ActiveRecord::Base.connection.execute(invalid_records_ids_query).field_values("id")
end
def invalid_records_ids_query
<<-SQL
SELECT id
FROM findings
WHERE #{whitespaces_in('deficiency_type')}
OR #{whitespaces_in('severity')}
OR #{whitespaces_in('scope')}
OR #{whitespaces_in('escalation')}
OR #{whitespaces_in('remediation_status')}
SQL
end
def whitespaces_in(field)
<<-SQL
#{field} ~* '\\s(.)|(.)\\s'
SQL
end
def update_query(ids)
<<-SQL
UPDATE findings
SET
deficiency_type = TRIM(#{TRIM_CHARACTER} from deficiency_type),
severity = TRIM(#{TRIM_CHARACTER} from severity),
scope = TRIM(#{TRIM_CHARACTER} from scope),
escalation = TRIM(#{TRIM_CHARACTER} from escalation),
remediation_status = TRIM(#{TRIM_CHARACTER} from remediation_status)
WHERE id in (#{ids.join(',')})
SQL
end
end
require "spec_helper"
require "tasks/support/remove_whitespaces_from_findings_fields"
describe RemoveWhitespacesFromFindingsFields do
def run
described_class.new.perform
end
describe "#perform" do
let(:findings) { build_list :finding, 2, default_attributes }
before do
findings.each do |finding|
finding.save(validate: false)
end
end
let(:default_attributes) {
{
"deficiency_type" => " \tType ",
"severity" => nil,
"scope" => " ",
"escalation" => " \rEscalation \f",
"remediation_status" => "\r Remediation status \n\v"
}
}
context "when in dry-run mode" do
it "does NOT update findings fields" do
run
findings.each do |finding|
expect(finding.reload.slice(*default_attributes.keys)).to eq(default_attributes)
end
end
end
context "when in live mode", live: true do
let(:expected_attributes) {
{
"deficiency_type" => "Type",
"severity" => nil,
"scope" => "",
"escalation" => "Escalation",
"remediation_status" => "Remediation status"
}
}
it "updates findings fields" do
run
findings.each do |finding|
expect(finding.reload.slice(*default_attributes.keys)).to eq(expected_attributes)
end
end
describe "activity logging" do
before { setup_activity_context }
after { reset_activity_context }
it "does NOT create activity logs" do
expect { run }.not_to change(ActivityLog, :count)
end
end
end
end
end
@rustemmukhamadiev
Copy link
Author

rustemmukhamadiev commented Dec 19, 2017

  1. Рейк таск на пересчет значения полей, после изменения логики их подсчета в приложении. То есть фикс невалидных записей + ТЕСТ
  2. Рейк таск на удаление пробелов (\s\n\t\r) в начале и конце слов. Сделаны с помощью SQL для более быстрой работы. + ТЕСТ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment