palkan / anyway_config

Configuration library for Ruby gems and applications
MIT License
778 stars 52 forks source link

AnywayConfig object seems to be cached unexpectedly #137

Closed Try431 closed 1 year ago

Try431 commented 1 year ago

What did you do?

I used with_env in an rspec test to set an environment variable to "false" within a specific context block

What did you expect to happen?

I expected that my AnywayConfig object I created would reflect the changes to the underlying environment variable and be reset accordingly for future tests.

What actually happened?

It didn't - instead, it looks like the value is being cached, unless I use .new

Additional context

Below is the output of some puts before, during, and after a with_env call, where I'm printing out my Anyway object (TestConfig.allow_data_creation)

"Env var: true"
"Anyway config attr before: true"

# within `with_env`, note that the environment variable is getting set to false as expected but 
# the Anyway config object never changes
"Env var: false"
"Anyway config within with_env: true"

"Env var: true"
"Anyway config attr after: true"

_Note that the same behavior happens if there is no value of the environment variable beforehand (I have the attr_config value set to true by default)_

"Env var: nil"
"Anyway config attr before: true"

"Env var: false"
"Anyway config within with_env: true"

"Env var: nil"
"Anyway config attr after: true"

However, if I change the puts to print out TestConfig.new.allow_data_creation each time:

"Env var: true"
"Anyway config attr before: true"

"Env var: false"
"Anyway config within with_env: false"

"Env var: true"
"Anyway config attr after: true"

and for good measure, with no pre-set value of the env var as above:

"Env var: nil"
"Anyway config attr before: true"

"Env var: false"
"Anyway config within with_env: false"

"Env var: nil"
"Anyway config attr after: true"

I discovered this because I found that the logic I had written that was depending on TestConfig.allow_data_creation to do or not do certain things was being cached, and so if the test that had the with_env ran first, all subsequent tests would have TestConfig.allow_data_creation set as false, instead of resetting back to true as I expected. Changing the logic to use TestConfig.new.allow_data_creation solved this issue.

I don't know if this is expected behavior or a bug, but figured I should bring it up here. Thanks!

Environment

Ruby Version: ruby 3.1.4p223 (2023-03-30 revision 957bb7cb81) [x86_64-linux]

Framework Version (Rails, whatever): Rails 6.1.7.6

Anyway Config Version: 2.3.1

palkan commented 1 year ago

... all subsequent tests would have TestConfig.allow_data_creation set as false, instead of resetting back to true as I expected... Changing the logic to use TestConfig.new.allow_data_creation solved this issue.

That's an expected behaviour. I guess, you're using ApplicationConfig class created via our Rails generator, which implements a singleton pattern. The instance is being cached within the class, it's loaded once for the whole lifetime of the application process.

So, in this case, you also need to reset the singleton state to test that (you can add .reset method to nullify @instance, for example) or use TestConfig.new in config unit tests. Ideally, you shouldn't setup configuration sources (with_env) in integration/functional tests, you should only care of the values stores in the TestConfig (and here you can use mocks/stubs, for example).