Commit Graph

4090 Commits

Author SHA1 Message Date
Sander Verdonschot 4cfdcfef8e
Make return values of Cache::Store#write consistent
The return value was not specified before. Now it returns `true` on a
successful write, `nil` if there was an error talking to the cache
backend, and `false` if the write failed for another reason (e.g. the
key already exists and `unless_exist: true` was passed).
2023-11-16 08:54:23 -05:00
Jean Boussier 37b0c603d5 Formally deprecate passing `caller` to `Deprecation#warn`
This emitted a warning since 2015, but it's likely most
offenders never saw it.

Ref: 211f55d4fd
2023-11-14 10:33:15 +01:00
Jean Boussier c2be3ea65c ActiveSupport::Deprecation handle blaming generated code
Fix: #50047

`Backtrace::Location` instance for code generated with eval always
have their `absolute_path` set to `nil`. So if absolute path is nil
we should fallback to checking `#path`.

Co-Authored-By: fatkodima <fatkodima123@gmail.com>
2023-11-14 09:51:41 +01:00
Hartley McGuire 9af99bfffc Fix logged cache key normalization
Previously, the `Cache::Store` instrumentation would call
`normalize_key` when adding a key to the log. However, this resulted in
the logged key not always matching the actual key written/read from the
cache:

```irb
irb(main):004> cache.write("foo", "bar", namespace: "baz")
D, [2023-11-10T12:44:59.286362 #169586] DEBUG -- : Cache write: baz:foo ({:compress=>false, :compress_threshold=>1024, :namespace=>"baz"})
=> true
irb(main):005> cache.delete("foo", namespace: "baz")
D, [2023-11-10T12:45:03.071300 #169586] DEBUG -- : Cache delete: foo
=> true
```

In this example, `#write` would correctly log that the key written to
was `baz:foo` because the `namespace` option would be passed to the
`instrument` method. However, other methods like `#delete` would log
that the `foo` key was deleted because the `namespace` option was _not_
passed to `instrument`.

This commit fixes the issue by making the caller responsible for passing
the correct key to `#instrument`. This allows `normalize_key` to be
removed from the log generation which both prevents the key from being
normalized a second time and removes the need to pass the full options
hash into `#instrument`.

Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2023-11-11 12:56:39 -06:00
fatkodima 096201f87d Fix `RedisCacheStore#write_multi` with `:expires_in` 2023-11-08 23:27:57 +02:00
Jean Boussier 9ade3f9b56
Merge pull request #49669 from intrip/fix-message-metadata-non-str
Fix decoding data encoded using a non-String purpose
2023-11-01 11:22:36 +01:00
Jean Boussier db92ea32e0 Simplify attr_internal_define
The `@` prefix is always stripped, so might as well not require it.

For backward compatibility reasons we still handle the prefix for now,
but we eagerly strip it and emit a deprecation.
2023-10-31 13:42:57 +01:00
Jonathan Hefner 1b195b30bc
Merge pull request #48482 from pcreux/improve-assert_changes-error-messages
Improve error messages of `assert_changes` and `assert_no_changes`
2023-10-30 13:43:51 -05:00
Philippe Creux 2b3a002a2a Improve error messages of assert_changes and assert_no_changes 2023-10-30 13:30:33 -05:00
Aashish Saini d8b3c557e9 Use cannonical form of library names 2023-10-30 12:51:35 -05:00
John Hawthorn b897b4c164
Merge pull request #49784 from jhawthorn/notification_exception_groups
Fix exception guards on multiple subscriber types
2023-10-30 08:25:11 -07:00
Jonathan Hefner bb17d787c8 Ensure {down,up}case_first returns non-frozen string
Prior to this commit, `String#downcase_first` and `String#upcase_first`
would return a frozen string when called on an empty string:

  ```ruby
  # BEFORE
  "foo".downcase_first.frozen? # => false
  "".downcase_first.frozen?    # => true

  # AFTER
  "foo".downcase_first.frozen? # => false
  "".downcase_first.frozen?    # => false
  ```
2023-10-29 12:28:06 -05:00
HolyWalley f455d5be03 [Fix #49796] Prevent global cache options being overwritten
The reason of removing dup 5 years ago in 6da99b4e99 was to decrease memory allocations, so, it makes sense to only dup options when we know they will be overwritten.
2023-10-26 13:58:40 -05:00
Jonathan Hefner 87609e821b
Merge pull request #49791 from Earlopain/number-human-size-negative
Handle negative numbers in `NumberToHumanSizeConverter`
2023-10-26 11:20:59 -05:00
Earlopain c6dcb11691
Handle negative numbers in NumberToHumanSizeConverter 2023-10-26 18:07:15 +02:00
Jean Boussier 9497f47131 Turn skips into errors on Rails CI
We had a few cases of tests being skipped accidentally on CI
hence not bein ran for a long time.

Skipping make sense when running the test suite locally, e.g.
you may not have Redis or some other dependency running.

But on CI, a test not being ran should be considered an error.
2023-10-26 12:46:01 +02:00
John Hawthorn 7beaacce51 Fix exception guards on multiple subscriber types
Previously in https://github.com/rails/rails/pull/43282, which shipped
with Rails 7.0, we added the guarantee that if an exception occurred
within an ActiveSupport::Notificaitons subscriber that the remaining
subscribers would still be run.

This was broken in https://github.com/rails/rails/pull/44469, where the
different types of subscribers were broken into groups by type for
performance. Although we would guard exceptions and allways run all (or
none) of the same group, that didn't work cross-group with different
types of subscriber.
2023-10-25 13:55:13 -07:00
Matt Brictson ac4c4c40a3
Fix Object.with test class name typo
`with_test.rb` should define a class named `WithTest`. Instead, it
redefines `BlankTest`. This seems to be a copy/paste typo.

This commit renames `BlankTest` to `WithTest` to follow convention, and
to avoid any potential conflicts of 2 test files defining the same
class.
2023-10-24 07:51:40 -07:00
Andrew Novoselac c14b98c28a Fix `BroadcastLogger#dup` so that it duplicates the logger's `broadcasts`. 2023-10-23 18:12:28 -04:00
yuuji.yaginuma bbe591d8f4 Don't use deprecated `#to_default_s` in `Date#to_fs`
In Rails 7.1.1, using `Date#to_fs` with an un-exist format, shows the
deprecation warning like the following.

```ruby
Date.current.to_fs(:doesnt_exist)
=> DEPRECATION WARNING: to_default_s is deprecated and will be removed from Rails 7.2 (use to_s instead) (called from <main> at ./bin/rails:4)
```

But other date-time-related classes still allow to use this.

6f6c211f47/activesupport/lib/active_support/core_ext/time/conversions.rb (L57)
6f6c211f47/activesupport/lib/active_support/core_ext/date_time/conversions.rb (L39)

So I thought this was just a typo and fixed to use `#to_s` like
other classes.
2023-10-22 17:17:42 +09:00
Jean Boussier f11c6ac45c
Merge pull request #49716 from Shopify/invalid-compressed-cache-entries
Handle outdated Marshal payloads in Cache::Entry with 6.1 cache_format
2023-10-20 15:59:25 +02:00
Ryuta Kamizono 10d880dcd2
Merge pull request #49718 from fatkodima/fix-ordered_options-nested-dig
Fix `OrderedOptions#dig` for array indexes
2023-10-20 19:57:22 +09:00
fatkodima 1b211421cd Fix `OrderedOptions#dig` for array indexes 2023-10-20 13:44:33 +03:00
Jean Boussier a6be798e5c Handle outdated Marshal payloads in Cache::Entry with 6.1 cache_format
Ref: https://github.com/rails/rails/issues/48611
Followup: https://github.com/rails/rails/pull/48663

It's the same logic than https://github.com/rails/rails/pull/48663
but now works for the 6.1 cache format.
2023-10-20 10:21:39 +02:00
fatkodima 7fd26579c0 Fix time travel helpers to work when nested using with separate classes 2023-10-20 02:46:42 +03:00
fatkodima 9e9fe7f391 Fix file cache store to split url-encoded keys on encode-sequence boundaries
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2023-10-19 21:33:02 +03:00
Jacopo cebdf71a00 Fix decoding data encoded using a non-String purpose
Data encoded using a non-String purpose and `use_message_serializer_for_metadata == false` was incorrectly decoded,
triggering a "mismatched purpose" error during decode.
Fix this by ensuring that we compare both sides as a String.
2023-10-17 10:02:10 +02:00
Nikita Vasilevsky 19f8ab2e7d
[Tests only] Enable `Minitest/AssertPredicate` rule 2023-10-13 19:26:47 +00:00
Jean Boussier e01d1e25dd ActiveSupport::LogSubscriber restore compatibility with SemanticLogger
Fix: https://github.com/rails/rails/pull/49563

The semantic_logger gems doesn't behave exactly like stdlib logger
in that `SemanticLogger#level` returns a Symbol while stdlib `Logger#level`
returns an Integer.

Because of this we can't simply compare integers, we have to use the
various `#{level}?` methods.
2023-10-13 14:21:23 +02:00
Ryuta Kamizono e8cad01402
Merge pull request #49576 from fatkodima/fix-number-helper-to_d
`NumberHelper`: handle objects responding `to_d`
2023-10-11 17:46:33 +09:00
fatkodima fe3b07f683 `NumberHelper`: handle objects responding `to_d` 2023-10-11 01:38:21 +03:00
Jean Boussier d4172bd44f
Merge pull request #49554 from Thomascountz/fix-redis-lt7-ttl-not-set-on-first-incr-decr
Fix `RedisCacheStore` INCR/DECR for Redis < v7.0.0
2023-10-11 00:15:16 +02:00
Jenny Shen 6070685cf9
Add support for kwargs when delegating calls to custom loggers
Currently, when a method is called on Rails.logger, the BroadcastLogger will find the loggers that will respond to that method. However, when the method has keyword arguments, they are passed as regular arguments and will throw an ArgumentError. This adds keyword argument support by double splatting hash args.

```
class CustomLogger
  def foo(bar:)
    true
  end
end

Rails.logger.foo(bar: "baz")
```

Expected: `true`

Actual: `wrong number of arguments (given 1, expected 0) (ArgumentError)`
2023-10-10 21:43:13 +01:00
Thomas Countz 600a052c8c Fix `RedisCacheStore` INCR/DECR for Redis < v7.0.0
This commit fixes a discrepancy in the behavior of the `#increment` and
`#decrement` methods in `RedisCacheStore` when used with Redis versions less
than 7.0.0. The existing condition `count != amount` prevented setting the
Time-To-Live (TTL) for keys that were equal to the increment/decrement amount
after the `INCRBY`/`DECRBY` operation. This occurs when incrementing a
non-existent key by `1`, for example.

Using Redis pipelining, we minimize the network overhead incurred by checking
for existing TTLs. It decouples the TTL operations from the increment/decrement
operation, allowing the TTL to be set correctly regardless of the resulting
value from the `INCRBY`/`DECRBY`.

New tests have been added to verify the correct behavior of `#increment` and
`#decrement` methods, specifically when the `expires_in` option is not used.
Using a separate cache store instance (`@cache_no_ttl`), these tests ensure that
keys are correctly incremented or decremented and that their TTL remains unset.

Co-authored-by: Benjamin Quorning <benjamin@quorning.net>
Co-authored-by: Jury Razumau <jury.razumau@zendesk.com>
Co-authored-by: Edyta Rozczypała <edyta.rozczypala@zendesk.com>
2023-10-10 19:32:26 +00:00
Rafael Mendonça França fed3125ea1
Merge pull request #49470 from rails/rm-eager-load-model-schema
Load the model schema when running test in eager load context
2023-10-04 05:51:39 -04:00
Rafael Mendonça França 1f0262aa2b
Separate the CI environment from the application CI environment
Right now we are using both to test the Rails applications we generate
and to test Rails itself. Let's keep CI for the app and BUILDKITE to
the framework.
2023-10-04 09:36:51 +00:00
fatkodima 39438318c7 Implement `HashWithIndifferentAccess#to_proc`
Previously, calling `#to_proc` on `HashWithIndifferentAccess` object used inherited `#to_proc`
method from the `Hash` class, which was not able to access values using indifferent keys.

Fixes #48770.
2023-10-03 21:26:08 +03:00
Alex ce321c4539 `NumberHelper`: handle very large numbers
Fixes https://github.com/rails/rails/issues/49461

Co-authored-by: fatkodima <5657035+fatkodima@users.noreply.github.com>
2023-10-03 14:46:06 +10:00
Eugene Kenny 5574a2fcb4 Delegate block in broadcast logger method_missing
When a method called on a broadcast logger is passed a block, it should
be forwarded to all subscribed loggers.
2023-10-02 16:35:01 +01:00
Jean Boussier 02e679ba75 Get rid of the `jruby_skip` test helper
The last test calling it actually passes on latest
JRuby.
2023-10-02 13:01:44 +02:00
Jonathan Hefner bb8ad695f4 Fix AS::MessagePack with ENV["RAILS_MAX_THREADS"]
`ENV` values are strings, so `ENV["RAILS_MAX_THREADS"]` must be parsed
as an int.

Unfortunately, `MessagePack::Factory::Pool::MemberPool` does not expose
a method to check its member count, so the most we can assert is that
roundtripping works as expected.

Fixes #49446.
2023-10-01 15:22:05 -05:00
Rafael Mendonça França db2ef1d250
Merge pull request #49417 from Edouard-chin/ec-logger-fix
Fix the BroadcastLogger being initialized too late:
2023-09-29 15:45:03 -04:00
Bart de Water 95b6fbd00f Stop building AS::Notifications::Event manually
It's possible since Rails 6 (3ea2857943) to let the framework create Event objects, but the guides and docs weren't updated to lead with this example.

Manually instantiating an Event doesn't record CPU time and allocations, I've seen it more than once that people copy-pasting the example code get confused about these stats returning 0. The tests here show that - just like the apps I've worked on - the old pattern keeps getting copy-pasted.
2023-09-29 12:34:23 -04:00
Edouard CHIN 40cb50e06e Fix the BroadcastLogger being initialized too late:
- An oversight of #48615 is that it changes the `Rails.logger` to be
  a broadcast logger after the app is booted. Anything referencing
  `Rails.logger` during the boot process will get a simple logger and
  ultimately resulting in logs not being broadcasted.

  For example `ActionController::Base.logger.info("abc")` would
  just output logs in the `development.log` file, not on STDOUT.

  ----

  The only solution I could think of is to create a BroadcastLogger
  earlier at boot, and add logger to that broadcast when needed (instead
  of modiyfing the `Rails.logger` variable).
2023-09-29 15:42:47 +02:00
Rafael Mendonça França 4c72cc2b04
Merge pull request #48615 from Edouard-chin/ec-logger
Add a public API for broadcasting logs
2023-09-25 17:13:58 -04:00
Rafael Mendonça França 88bb5f2749
Define the method in the right place 2023-09-25 21:04:41 +00:00
Rafael Mendonça França 4e605f5d0f
Fix ruby warning
Remove `.[]` before redefining it.
2023-09-25 20:47:36 +00:00
Edouard CHIN 1fbd812c47
Add a public API for broadcasting logs:
- ## Context

  While working on https://github.com/rails/rails/pull/44695, I
  realised that Broadcasting was still a private API, although it’s
  commonly used. Rafael mentioned that making it public would require
  some refactor because of the original implementation which was hard
  to understand and maintain.

  ### Changing how broadcasting works:

  Broadcasting in a nutshell worked by “transforming” an existing
  logger into a broadcasted one.
  The logger would then be responsible to log and format its own
  messages as well as passing the message along to other logger it
  broadcasts to.

  The problem with this approach was the following:

  - Heavy use of metaprogramming.
  - Accessing the loggers in the broadcast wasn’t possible.
    Removing a logger from the broadcast either.
  - More importantly, modifying the main logger (the one that broadcasts
    logs to the others) wasn’t possible and the main source of
    misunderstanding.

    ```ruby
      logger = Logger.new(STDOUT)
      stderr_logger = Logger.new(STDER))
      logger.extend(AS::Logger.broadcast(stderr_logger))

      logger.level = DEBUG # This modifies the level on all other loggers
      logger.formatter = … # Modified the formatter on all other loggers
    ```

  To keep the contract unchanged on what Rails.logger returns, the new
  BroadcastLogger class implement duck typing with all methods
  that has the vanilla Ruby Logger class.

  It's a simple and boring PORO that keeps an array of all the loggers
  that are part of the broadcast and iterate over whenever a log is
  sent.
  Now, users can access all loggers inside the broadcast and modify
  them on the fly. They can also remove any logger from the broadcast
  at any time.

  ```ruby
  # Before

  stdout_logger = Logger.new(STDOUT)
  stderr_logger = Logger.new(STDER)
  file_logger = Logger.new(“development.log”)
  stdout_logger.extend(AS::Logger.broadcast(stderr_logger))
  stdout_logger.extend(AS::Logger.broadcast(file_logger))

  # After

  broadcast = BroadcastLogger.new(stdout_logger, stderr_logger, file_logger)
  ```

  I also think that now, it should be more clear for users that the
  broadcast sole job is to pass everything to the whole loggers in
  the broadcast. So there should be no surprise that all loggers in
  the broadcast get their level modified when they call
  `broadcast.level = DEBUG` .

  It’s also easier to wrap your head around more complex setup such
  as broadcasting logs to another broadcast:
  `broadcast.broadcast_to(stdout_logger, other_broadcast)`
2023-09-25 20:40:51 +00:00
Rafael Mendonça França 71613d3da9
Merge pull request #45411 from jonathanhefner/add-deep_mergeable
Factor out `deep_merge` into `AS::DeepMergeable`
2023-09-25 16:25:44 -04:00
Hartley McGuire 64184c6f50
Fix Range#overlap? ignoring empty ranges
Previously, #overlap? would incorrectly return true when one of the
ranges is effectively "empty":

```ruby
(2...2).overlap? 1..2 # => true
(1..2).overlap? 2...2 # => true
```

This is fixed in the Ruby 3.3 implementation of Range#overlap?, so this
commit fixes it for Ruby < 3.3 as well.

The tests added are from the Ruby repository and the implementation is
effectively a Ruby version of the fix in C.

Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Co-authored-by: Shouichi Kamiya <shouichi.kamiya@gmail.com>
2023-09-22 19:48:49 -04:00