From 7d25b651fa9011b040fab2f19fb315679519edb2 Mon Sep 17 00:00:00 2001 From: Dominik Sander Date: Tue, 17 Apr 2018 22:03:02 +0200 Subject: [PATCH] Fix exception in AS::Timezone.all when any tzinfo data is missing Before this change missing timezone data for any of the time zones defined in `ActiveSupport::Timezone::MAPPING` caused a `comparison of NilClass with ActiveSupport::TimeZone failed` exception. Attempting to get a timezone by passing a number/duration to `[]` or calling `all` directly will try to sort sort the values of `zones_map`. Those values are initialized by the return value of `create(zonename)` which returns `nil` if `TZInfo` is unable to find the timezone information. In our case the exception was triggered by an outdated tzdata package which did not include information for the "recently" added time zones. Before 078421bacba178eac6a8e607b16f3f4511c5d72f `zones_map` only returned the information that have been loaded into `@lazy_zone_map` which ignored time zones for which the data could not be loaded, this change restores the previous behaviour. --- activesupport/CHANGELOG.md | 5 +++++ .../lib/active_support/values/time_zone.rb | 3 ++- activesupport/test/time_zone_test.rb | 15 +++++++++++++++ activesupport/test/time_zone_test_helpers.rb | 13 +++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 82c985fae2c18..aa7e206bb2090 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,8 @@ +* Fix bug where `ActiveSupport::Timezone.all` would fail when tzinfo data for + any timezone defined in `ActiveSupport::MAPPING` is missing. + + *Dominik Sander* + * Fix bug where `ActiveSupport::Cache` will massively inflate the storage size when compression is enabled (which is true by default). This patch does not attempt to repair existing data: please manually flush the cache diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 9dfaddb825c22..5f709c5fd9539 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -279,7 +279,8 @@ def load_country_zones(code) def zones_map @zones_map ||= MAPPING.each_with_object({}) do |(name, _), zones| - zones[name] = self[name] + timezone = self[name] + zones[name] = timezone if timezone end end end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index 63ca22efb536f..120afa61f282c 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -725,6 +725,21 @@ def test_all_uninfluenced_by_time_zone_lookups_delegated_to_tzinfo assert_not_includes all_zones, galapagos end + def test_all_not_raises_exception_with_mizzing_tzinfo_data + mappings = { + "Puerto Rico" => "America/Unknown", + "Pittsburgh" => "America/New_York" + } + + with_tz_mappings(mappings) do + assert_nil ActiveSupport::TimeZone["Puerto Rico"] + assert_nil ActiveSupport::TimeZone[-9] + assert_nothing_raised do + ActiveSupport::TimeZone.all + end + end + end + def test_index assert_nil ActiveSupport::TimeZone["bogus"] assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone["Central Time (US & Canada)"] diff --git a/activesupport/test/time_zone_test_helpers.rb b/activesupport/test/time_zone_test_helpers.rb index 051703a781a43..85ed727c9be82 100644 --- a/activesupport/test/time_zone_test_helpers.rb +++ b/activesupport/test/time_zone_test_helpers.rb @@ -23,4 +23,17 @@ def with_preserve_timezone(value) ensure ActiveSupport.to_time_preserves_timezone = old_preserve_tz end + + def with_tz_mappings(mappings) + old_mappings = ActiveSupport::TimeZone::MAPPING.dup + ActiveSupport::TimeZone.clear + ActiveSupport::TimeZone::MAPPING.clear + ActiveSupport::TimeZone::MAPPING.merge!(mappings) + + yield + ensure + ActiveSupport::TimeZone.clear + ActiveSupport::TimeZone::MAPPING.clear + ActiveSupport::TimeZone::MAPPING.merge!(old_mappings) + end end