Files
sure/test/models/setting_test.rb
T
ed6b8b752a fix(hosting): consistent provider-block visibility + fix Twelve Data toggle bug (#3333)
* fix(hosting): consistent provider-block visibility + fix Twelve Data toggle bug (#3089)

T-Invest was the only provider block always rendered regardless of its
checkbox state; now it follows the same pattern as every other provider
(shown when tinkoff_invest or moex_public is enabled, since T-Invest also
serves as a brand-logo fallback for MOEX-priced securities).

Also fixes a related functional bug: unchecking every securities provider
tried to clear the legacy securities_provider setting by assigning nil,
but rails-settings-cached treats nil as "delete override", which silently
reverted the field to its own default ("twelve_data") — re-enabling Twelve
Data right after the user disabled it. Assigning "" instead persists the
cleared state.

Twelve Data and Yahoo Finance settings blocks can still be shown purely
because they're the selected FX/exchange-rate provider even when unchecked
for securities pricing; added an info notice explaining that instead of
leaving it unexplained.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(hosting): address review feedback on #3333

- Drop the FX-only notice for Twelve Data/Yahoo Finance per feedback —
  the block staying visible while unchecked (because it's still the FX
  provider) doesn't need extra UI explanation.
- Fix Codex finding: T-Invest settings must stay visible/manageable
  whenever a token is already configured, not just when tinkoff_invest
  or moex_public is checked. Security::Provided#import_brand_logo calls
  the T-Invest provider unconditionally for every non-crypto security
  once a token exists, regardless of price provider — hiding the field
  in that case would leave an active credential impossible to see,
  rotate, or clear through the UI. Reworded the notice to reflect the
  real, provider-independent reason instead of the narrower "MOEX only"
  framing.
- Fix CodeRabbit finding: setting_test.rb's default-fallback test now
  isolates against SECURITIES_PROVIDER(S) env vars, and the
  explicit-clear test captures and restores the pre-test values instead
  of hardcoding a restore target.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* No overexplaining in code

---------

Co-authored-by: Gerald <248542187+gfr-free@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
2026-09-02 19:48:32 +02:00

160 lines
5.2 KiB
Ruby

require "test_helper"
class SettingTest < ActiveSupport::TestCase
setup do
# Clear settings before each test
Setting.openai_uri_base = nil
Setting.openai_model = nil
end
teardown do
# Clean up dynamic fields after each test
Setting.where("var LIKE ?", "dynamic:%").destroy_all
end
test "validate_openai_config! passes when both uri base and model are set" do
assert_nothing_raised do
Setting.validate_openai_config!(uri_base: "https://api.example.com", model: "gpt-4")
end
end
test "validate_openai_config! passes when neither uri base nor model are set" do
assert_nothing_raised do
Setting.validate_openai_config!(uri_base: "", model: "")
end
end
test "validate_openai_config! passes when uri base is blank and model is set" do
assert_nothing_raised do
Setting.validate_openai_config!(uri_base: "", model: "gpt-4")
end
end
test "validate_openai_config! raises error when uri base is set but model is blank" do
error = assert_raises(Setting::ValidationError) do
Setting.validate_openai_config!(uri_base: "https://api.example.com", model: "")
end
assert_match(/OpenAI model is required/, error.message)
end
test "validate_openai_config! uses current settings when parameters are nil" do
Setting.openai_uri_base = "https://api.example.com"
Setting.openai_model = "gpt-4"
assert_nothing_raised do
Setting.validate_openai_config!(uri_base: nil, model: nil)
end
end
test "validate_openai_config! raises error when current uri base is set but new model is blank" do
Setting.openai_uri_base = "https://api.example.com"
Setting.openai_model = "gpt-4"
error = assert_raises(Setting::ValidationError) do
Setting.validate_openai_config!(uri_base: nil, model: "")
end
assert_match(/OpenAI model is required/, error.message)
end
test "validate_openai_config! passes when new uri base is blank and current model exists" do
Setting.openai_uri_base = "https://api.example.com"
Setting.openai_model = "gpt-4"
assert_nothing_raised do
Setting.validate_openai_config!(uri_base: "", model: nil)
end
end
# Dynamic field tests
test "can set and get dynamic fields" do
Setting["custom_key"] = "custom_value"
assert_equal "custom_value", Setting["custom_key"]
end
test "can set and get multiple dynamic fields independently" do
Setting["key1"] = "value1"
Setting["key2"] = "value2"
Setting["key3"] = "value3"
assert_equal "value1", Setting["key1"]
assert_equal "value2", Setting["key2"]
assert_equal "value3", Setting["key3"]
end
test "setting nil value deletes dynamic field" do
Setting["temp_key"] = "temp_value"
assert_equal "temp_value", Setting["temp_key"]
Setting["temp_key"] = nil
assert_nil Setting["temp_key"]
end
test "can delete dynamic field" do
Setting["delete_key"] = "delete_value"
assert_equal "delete_value", Setting["delete_key"]
value = Setting.delete("delete_key")
assert_equal "delete_value", value
assert_nil Setting["delete_key"]
end
test "key? returns true for existing dynamic field" do
Setting["exists_key"] = "exists_value"
assert Setting.key?("exists_key")
end
test "key? returns false for non-existing dynamic field" do
assert_not Setting.key?("nonexistent_key")
end
test "dynamic_keys returns all dynamic field keys" do
Setting["dynamic1"] = "value1"
Setting["dynamic2"] = "value2"
keys = Setting.dynamic_keys
assert_includes keys, "dynamic1"
assert_includes keys, "dynamic2"
end
test "declared fields take precedence over dynamic fields" do
# Try to set a declared field using bracket notation
Setting["openai_model"] = "custom-model"
assert_equal "custom-model", Setting["openai_model"]
assert_equal "custom-model", Setting.openai_model
end
test "cannot delete declared fields" do
Setting.openai_model = "test-model"
result = Setting.delete("openai_model")
assert_nil result
assert_equal "test-model", Setting.openai_model
end
test "enabled_securities_providers falls back to twelve_data when nothing is configured" do
with_env_overrides("SECURITIES_PROVIDERS" => nil, "SECURITIES_PROVIDER" => nil) do
assert_equal [ "twelve_data" ], Setting.enabled_securities_providers
end
end
test "enabled_securities_providers returns an empty list when explicitly cleared, not the legacy default" do
original_providers = Setting.securities_providers
original_provider = Setting.securities_provider
Setting.securities_providers = ""
Setting.securities_provider = ""
assert_equal [], Setting.enabled_securities_providers
ensure
# Restore whatever was there before this test, not a hardcoded value —
# and restore via assignment (not nil) either way, since
# rails-settings-cached's cache layer doesn't reliably invalidate on
# delete within a single test process, so a later test can still read
# back the just-deleted blank override instead of falling through to
# the field's default.
Setting.securities_providers = original_providers.presence || ""
Setting.securities_provider = original_provider.presence || "twelve_data"
end
end