Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Composite key in AP school codes #27866

Merged
merged 14 commits into from Jul 12, 2019
Merged

Conversation

bencodeorg
Copy link
Contributor

@bencodeorg bencodeorg commented Apr 3, 2019

This PR updates model relationships to reflect that AP school codes are now unique at the [school_year, school_code] level.

edit: in the process of this PR, the file ap_school_codes.csv was (manually) moved from the bucket cdo-census into a folder called ap_school_codes inside of cdo-census, and was renamed 2016-2017.csv.

@@ -55,7 +56,7 @@ def self.seed_from_s3

def self.seed
if CDO.stub_school_data
seed_from_csv("test/fixtures/census/ap_school_codes.csv")
seed_from_csv("test/fixtures/census/ap_school_codes.csv", 2016)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we borrow the convention from the state course offerings seeding logic where the school year is in the filename and picked up dynamically?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can make that change. Any thoughts on how to test this change more broadly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended up doing what you suggested here. I tested the impact of moving the existing ap_school_code.csv file to a place like "ap_school_codes/#{school_year}-#{school_year + 1}.csv" by:

  1. copying down existing ap_school_codes table from production
  2. doing complete seeding of ap_school_codes using files in new location
  3. checking whether any rows with school_year = 2016 (ie, existing data) had a modified updated_at (they did not).

@bencodeorg bencodeorg changed the title [WIP, DO NOT MERGE] Composite key in AP school codes Composite key in AP school codes Apr 8, 2019
@bencodeorg bencodeorg requested review from uponthesun and removed request for hacodeorg May 31, 2019 21:32
ap_cs_offering {build_list(:ap_cs_offering, 1, school_year: school_year)}
end
end

factory :ap_cs_offering, class: 'Census::ApCsOffering' do
ap_school_code {build :ap_school_code}
ap_school_code {build :ap_school_code, school_year: school_year}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding school_year here resolved ActiveRecord issues we were having when testing.

ap_offerings_this_year = ap_offerings.select {|o| o.school_year == school_year}
ap_offerings_this_year.each do |offering|
audit[:ap_cs_offerings].push(offering.id)
ap_offerings_this_year = []
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we resolved the ActiveRecord error in the ap_school_code factory, we resolved a real test failure that resulted from the prior assumption that each school had only one ap_school_code. Now a school can have a different ap_school_code per year.

@bencodeorg
Copy link
Contributor Author

Two months later... @uponthesun helped get this across the finish line! @sureshc as a neutral party could you take a look at this again and see if it looks good to you?

@sureshc
Copy link
Contributor

sureshc commented Jun 4, 2019

So awesome that @uponthesun helped you solve the problem with the Factory!

Would it be good to have tests that exercise the two Associations to School and ApCsOffering? They depend on a gem to be able to establish relationships with ApSchoolCode through the composite key. Might be handy to make sure the Association through the composite key continues to work even when the gem is upgraded in the future or other foundational components (like ActiveRecord) change in the future. Should we have a test that creates two ApSchoolCodes that point to the same school and two different ApCsOfferings that use those two school codes?

@bencodeorg
Copy link
Contributor Author

@sureshc forgot about this PR, but there's a bit of a fire drill around the access report this week that I'll need to resolve this for...I think what you are suggesting is sort of happening in the test that @uponthesun and I were working on. This test:

https://github.com/code-dot-org/code-dot-org/blob/staging/dashboard/test/models/census/census_summary_test.rb#L175

Makes sure we can create an ApSchoolCode and ApCsOffering for a given School -- it doesn't quite do what you're suggesting (make sure that a single School can have multiple ApSchoolCodes), but I think does at least make sure that the base functionality (ie, joining between models via composite key) works?

@bencodeorg
Copy link
Contributor Author

@sureshc I was being lazy, took your advice and added a test per your comment (in this commit).

I also committed code changes required to ingest the new mappings and AP data in this commit. I might want to break that out into a different PR though, per @Erin007's presentation yesterday.

@@ -142,6 +142,22 @@ class Census::CensusSummaryTest < ActiveSupport::TestCase
assert Census::CensusSummary.submission_teaches_cs?(submission, is_high_school: nil, is_k8_school: nil)
end

test "School with different AP school codes in different years functions correctly" do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I was thinking of! Test ability to create two ap school codes for the same school for different years with different codes. I think these tests belong in ap_school_code_test.rb though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of putting it in census_school_test.rb, but that doesn't exist -- what assertion would you suggest using then (instead of checking the summarization)? FWIW, the validate_summary approach I used here actually caught a problem.

@sureshc sureshc self-requested a review July 11, 2019 21:02
refute school_code.valid?
end

test "Composite key relationship between AP school code and AP CS offering" do
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sureshc added another test that mirrors some of the scenarios you whiteboarded yesterday. I have three assertions here -- should I split into different tests?

school_id = School.normalize_school_id(row.to_hash['school_id'])
school = School.find_by(id: school_id)
if school.nil?
puts "AP School Code seed: school not found - skipping row for school_code:#{normalized_school_code} school_id:#{school_id}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
puts "AP School Code seed: school not found - skipping row for school_code:#{normalized_school_code} school_id:#{school_id}"
CDO.log.warn "AP School Code seed: school not found - skipping row for school_code:#{normalized_school_code} school_id:#{school_id}"

"ap_school_codes/#{school_year}-#{school_year + 1}.csv"
end

def self.seed_from_csv(filename, school_year)
ActiveRecord::Base.transaction do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this functionality isn’t changing from what already existed, but I don’t think there’s any benefit to wrapping the CSV import in a transaction. Do we really want to ROLLBACK all of the INSERTed rows if a single row encounters an error? There’s a likely small database performance penalty, as well, for carrying out all of the INSERTs in a single transaction.

@@ -45,7 +46,7 @@ def self.seed_from_csv(course, school_year, filename)
rescue ActiveRecord::RecordNotFound
# We don't have mapping for every school code so skip over any that
# can't be found in the database.
puts "AP CS Offering seeding: skipping unknown school code #{normalized_school_code}"
puts "AP CS Offering seeding: skipping unknown school code #{normalized_school_code}, school name #{raw_school_name}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
puts "AP CS Offering seeding: skipping unknown school code #{normalized_school_code}, school name #{raw_school_name}"
CDO.log.warn "AP CS Offering seeding: skipping unknown school code #{normalized_school_code}, school name #{raw_school_name}"

Copy link
Contributor

@sureshc sureshc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Definitely change the puts to CDO.log.warn before merging.

@bencodeorg
Copy link
Contributor Author

Switched out puts statements in both ApSchoolCode and ApCsOffering models -- for the record, as the great Shaggy once said, it wasn't me.

@bencodeorg bencodeorg merged commit 9cbf900 into staging Jul 12, 2019
@bencodeorg bencodeorg deleted the composite-key-in-ap-school-codes branch July 29, 2019 20:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants