Skip to content

Commit d4983a9

Browse files
Merge pull request rails#48450 from jonathanhefner/cache-compression-tests
Refactor cache compression tests
2 parents ff3c8de + dc4f325 commit d4983a9

File tree

7 files changed

+132
-164
lines changed

7 files changed

+132
-164
lines changed

activesupport/test/cache/behaviors.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
require_relative "behaviors/cache_store_behavior"
88
require_relative "behaviors/cache_store_version_behavior"
99
require_relative "behaviors/cache_store_coder_behavior"
10+
require_relative "behaviors/cache_store_compression_behavior"
1011
require_relative "behaviors/cache_store_format_version_behavior"
1112
require_relative "behaviors/connection_pool_behavior"
1213
require_relative "behaviors/encoded_key_cache_behavior"

activesupport/test/cache/behaviors/cache_store_behavior.rb

Lines changed: 0 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -266,105 +266,6 @@ def test_fetch_multi_uses_write_multi_entries_store_provider_interface
266266
end
267267
end
268268

269-
# Use strings that are guaranteed to compress well, so we can easily tell if
270-
# the compression kicked in or not.
271-
SMALL_STRING = "0" * 100
272-
LARGE_STRING = "0" * 2.kilobytes
273-
274-
SMALL_OBJECT = { data: SMALL_STRING }
275-
LARGE_OBJECT = { data: LARGE_STRING }
276-
277-
def test_nil_with_default_compression_settings
278-
assert_uncompressed(nil)
279-
end
280-
281-
def test_nil_with_compress_true
282-
assert_uncompressed(nil, compress: true)
283-
end
284-
285-
def test_nil_with_compress_false
286-
assert_uncompressed(nil, compress: false)
287-
end
288-
289-
def test_nil_with_compress_low_compress_threshold
290-
assert_uncompressed(nil, compress: true, compress_threshold: 20)
291-
end
292-
293-
def test_small_string_with_default_compression_settings
294-
assert_uncompressed(SMALL_STRING)
295-
end
296-
297-
def test_small_string_with_compress_true
298-
assert_uncompressed(SMALL_STRING, compress: true)
299-
end
300-
301-
def test_small_string_with_compress_false
302-
assert_uncompressed(SMALL_STRING, compress: false)
303-
end
304-
305-
def test_small_string_with_low_compress_threshold
306-
assert_compressed(SMALL_STRING, compress: true, compress_threshold: 1)
307-
end
308-
309-
def test_small_object_with_default_compression_settings
310-
assert_uncompressed(SMALL_OBJECT)
311-
end
312-
313-
def test_small_object_with_compress_true
314-
assert_uncompressed(SMALL_OBJECT, compress: true)
315-
end
316-
317-
def test_small_object_with_compress_false
318-
assert_uncompressed(SMALL_OBJECT, compress: false)
319-
end
320-
321-
def test_small_object_with_low_compress_threshold
322-
assert_compressed(SMALL_OBJECT, compress: true, compress_threshold: 1)
323-
end
324-
325-
def test_large_string_with_compress_true
326-
assert_compressed(LARGE_STRING, compress: true)
327-
end
328-
329-
def test_large_string_with_compress_false
330-
assert_uncompressed(LARGE_STRING, compress: false)
331-
end
332-
333-
def test_large_string_with_high_compress_threshold
334-
assert_uncompressed(LARGE_STRING, compress: true, compress_threshold: 1.megabyte)
335-
end
336-
337-
def test_large_object_with_compress_true
338-
assert_compressed(LARGE_OBJECT, compress: true)
339-
end
340-
341-
def test_large_object_with_compress_false
342-
assert_uncompressed(LARGE_OBJECT, compress: false)
343-
end
344-
345-
def test_large_object_with_high_compress_threshold
346-
assert_uncompressed(LARGE_OBJECT, compress: true, compress_threshold: 1.megabyte)
347-
end
348-
349-
def test_incompressible_data
350-
assert_uncompressed(nil, compress: true, compress_threshold: 30)
351-
assert_uncompressed(true, compress: true, compress_threshold: 30)
352-
assert_uncompressed(false, compress: true, compress_threshold: 30)
353-
assert_uncompressed(0, compress: true, compress_threshold: 30)
354-
assert_uncompressed(1.2345, compress: true, compress_threshold: 30)
355-
assert_uncompressed("", compress: true, compress_threshold: 30)
356-
357-
incompressible = nil
358-
359-
# generate an incompressible string
360-
loop do
361-
incompressible = Random.bytes(1.kilobyte)
362-
break if incompressible.bytesize < Zlib::Deflate.deflate(incompressible).bytesize
363-
end
364-
365-
assert_uncompressed(incompressible, compress: true, compress_threshold: 1)
366-
end
367-
368269
def test_cache_key
369270
key = SecureRandom.uuid
370271
klass = Class.new do
@@ -801,47 +702,6 @@ def test_cache_miss_instrumentation
801702
end
802703

803704
private
804-
def assert_compressed(value, **options)
805-
assert_compression(true, value, **options)
806-
end
807-
808-
def assert_uncompressed(value, **options)
809-
assert_compression(false, value, **options)
810-
end
811-
812-
def assert_compression(should_compress, value, **options)
813-
actual = "actual" + SecureRandom.uuid
814-
uncompressed = "uncompressed" + SecureRandom.uuid
815-
816-
freeze_time do
817-
@cache.write(actual, value, options)
818-
@cache.write(uncompressed, value, options.merge(compress: false))
819-
end
820-
821-
if value.nil?
822-
assert_nil @cache.read(actual)
823-
assert_nil @cache.read(uncompressed)
824-
else
825-
assert_equal value, @cache.read(actual)
826-
assert_equal value, @cache.read(uncompressed)
827-
end
828-
829-
actual_entry = @cache.send(:read_entry, @cache.send(:normalize_key, actual, {}), **{})
830-
uncompressed_entry = @cache.send(:read_entry, @cache.send(:normalize_key, uncompressed, {}), **{})
831-
832-
actual_payload = @cache.send(:serialize_entry, actual_entry, **@cache.send(:merged_options, options))
833-
uncompressed_payload = @cache.send(:serialize_entry, uncompressed_entry, compress: false)
834-
835-
actual_size = actual_payload.bytesize
836-
uncompressed_size = uncompressed_payload.bytesize
837-
838-
if should_compress
839-
assert_operator actual_size, :<, uncompressed_size, "value should be compressed"
840-
else
841-
assert_equal uncompressed_size, actual_size, "value should not be compressed"
842-
end
843-
end
844-
845705
def with_raise_on_invalid_cache_expiration_time(new_value, &block)
846706
old_value = ActiveSupport::Cache::Store.raise_on_invalid_cache_expiration_time
847707
ActiveSupport::Cache::Store.raise_on_invalid_cache_expiration_time = new_value
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# frozen_string_literal: true
2+
3+
require "active_support/core_ext/numeric/bytes"
4+
5+
module CacheStoreCompressionBehavior
6+
extend ActiveSupport::Concern
7+
8+
included do
9+
test "compression by default" do
10+
@cache = lookup_store
11+
12+
assert_uncompressed SMALL_STRING
13+
assert_uncompressed SMALL_OBJECT
14+
if compression_always_disabled_by_default?
15+
assert_uncompressed LARGE_STRING
16+
assert_uncompressed LARGE_OBJECT
17+
else
18+
assert_compressed LARGE_STRING
19+
assert_compressed LARGE_OBJECT
20+
end
21+
end
22+
23+
test "compression can be disabled" do
24+
@cache = lookup_store(compress: false)
25+
26+
assert_uncompressed SMALL_STRING
27+
assert_uncompressed SMALL_OBJECT
28+
assert_uncompressed LARGE_STRING
29+
assert_uncompressed LARGE_OBJECT
30+
end
31+
32+
test ":compress method option overrides initializer option" do
33+
@cache = lookup_store(compress: true)
34+
35+
assert_uncompressed SMALL_STRING, compress: false
36+
assert_uncompressed SMALL_OBJECT, compress: false
37+
assert_uncompressed LARGE_STRING, compress: false
38+
assert_uncompressed LARGE_OBJECT, compress: false
39+
40+
@cache = lookup_store(compress: false)
41+
42+
assert_uncompressed SMALL_STRING, compress: true
43+
assert_uncompressed SMALL_OBJECT, compress: true
44+
assert_compressed LARGE_STRING, compress: true
45+
assert_compressed LARGE_OBJECT, compress: true
46+
end
47+
48+
test "low :compress_threshold triggers compression" do
49+
@cache = lookup_store(compress: true, compress_threshold: 1)
50+
51+
assert_compressed SMALL_STRING
52+
assert_compressed SMALL_OBJECT
53+
assert_compressed LARGE_STRING
54+
assert_compressed LARGE_OBJECT
55+
end
56+
57+
test "high :compress_threshold inhibits compression" do
58+
@cache = lookup_store(compress: true, compress_threshold: 1.megabyte)
59+
60+
assert_uncompressed SMALL_STRING
61+
assert_uncompressed SMALL_OBJECT
62+
assert_uncompressed LARGE_STRING
63+
assert_uncompressed LARGE_OBJECT
64+
end
65+
66+
test ":compress_threshold method option overrides initializer option" do
67+
@cache = lookup_store(compress: true, compress_threshold: 1)
68+
69+
assert_uncompressed SMALL_STRING, compress_threshold: 1.megabyte
70+
assert_uncompressed SMALL_OBJECT, compress_threshold: 1.megabyte
71+
assert_uncompressed LARGE_STRING, compress_threshold: 1.megabyte
72+
assert_uncompressed LARGE_OBJECT, compress_threshold: 1.megabyte
73+
74+
@cache = lookup_store(compress: true, compress_threshold: 1.megabyte)
75+
76+
assert_compressed SMALL_STRING, compress_threshold: 1
77+
assert_compressed SMALL_OBJECT, compress_threshold: 1
78+
assert_compressed LARGE_STRING, compress_threshold: 1
79+
assert_compressed LARGE_OBJECT, compress_threshold: 1
80+
end
81+
82+
test "compression ignores nil" do
83+
assert_uncompressed nil
84+
assert_uncompressed nil, compress: true, compress_threshold: 1
85+
end
86+
87+
test "compression ignores incompressible data" do
88+
assert_uncompressed "", compress: true, compress_threshold: 1
89+
assert_uncompressed [*0..127].pack("C*"), compress: true, compress_threshold: 1
90+
end
91+
end
92+
93+
private
94+
# Use strings that are guaranteed to compress well, so we can easily tell if
95+
# the compression kicked in or not.
96+
SMALL_STRING = "0" * 100
97+
LARGE_STRING = "0" * 2.kilobytes
98+
99+
SMALL_OBJECT = { data: SMALL_STRING }
100+
LARGE_OBJECT = { data: LARGE_STRING }
101+
102+
def assert_compressed(value, **options)
103+
assert_operator compute_entry_size_reduction(value, **options), :>, 0
104+
end
105+
106+
def assert_uncompressed(value, **options)
107+
assert_equal 0, compute_entry_size_reduction(value, **options)
108+
end
109+
110+
def compute_entry_size_reduction(value, **options)
111+
entry = ActiveSupport::Cache::Entry.new(value)
112+
113+
uncompressed = @cache.send(:serialize_entry, entry, **options, compress: false)
114+
actual = @cache.send(:serialize_entry, entry, **options)
115+
116+
uncompressed.bytesize - actual.bytesize
117+
end
118+
119+
def compression_always_disabled_by_default?
120+
false
121+
end
122+
end

activesupport/test/cache/stores/file_store_test.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def teardown
3232
include CacheStoreBehavior
3333
include CacheStoreVersionBehavior
3434
include CacheStoreCoderBehavior
35+
include CacheStoreCompressionBehavior
3536
include CacheStoreFormatVersionBehavior
3637
include CacheDeleteMatchedBehavior
3738
include CacheIncrementDecrementBehavior

activesupport/test/cache/stores/mem_cache_store_test.rb

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def after_teardown
7777
include CacheStoreBehavior
7878
include CacheStoreVersionBehavior
7979
include CacheStoreCoderBehavior
80+
include CacheStoreCompressionBehavior
8081
include CacheStoreFormatVersionBehavior
8182
include LocalCacheBehavior
8283
include CacheIncrementDecrementBehavior
@@ -327,14 +328,6 @@ def test_falls_back_to_localhost_if_no_address_provided_and_memcache_servers_def
327328
end
328329
end
329330

330-
def test_large_string_with_default_compression_settings
331-
assert_compressed(LARGE_STRING)
332-
end
333-
334-
def test_large_object_with_default_compression_settings
335-
assert_compressed(LARGE_OBJECT)
336-
end
337-
338331
def test_can_load_raw_values_from_dalli_store
339332
key = "test-with-value-the-way-the-dalli-store-did"
340333

activesupport/test/cache/stores/memory_store_test.rb

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,12 @@ def lookup_store(options = {})
1616
include CacheStoreBehavior
1717
include CacheStoreVersionBehavior
1818
include CacheStoreCoderBehavior
19+
include CacheStoreCompressionBehavior
1920
include CacheDeleteMatchedBehavior
2021
include CacheIncrementDecrementBehavior
2122
include CacheInstrumentationBehavior
2223
include CacheLoggingBehavior
2324

24-
def test_large_string_with_default_compression_settings
25-
assert_uncompressed(LARGE_STRING)
26-
end
27-
28-
def test_large_object_with_default_compression_settings
29-
assert_uncompressed(LARGE_OBJECT)
30-
end
31-
3225
def test_increment_preserves_expiry
3326
@cache = lookup_store
3427
@cache.write("counter", 1, raw: true, expires_in: 30.seconds)
@@ -58,6 +51,11 @@ def test_cleanup_instrumentation
5851
assert_equal size, events[0].payload[:size]
5952
assert_equal @cache.class.name, events[0].payload[:store]
6053
end
54+
55+
private
56+
def compression_always_disabled_by_default?
57+
true
58+
end
6159
end
6260

6361
class MemoryStorePruningTest < ActiveSupport::TestCase

activesupport/test/cache/stores/redis_cache_store_test.rb

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ class RedisCacheStoreCommonBehaviorTest < StoreTest
159159
include CacheStoreBehavior
160160
include CacheStoreVersionBehavior
161161
include CacheStoreCoderBehavior
162+
include CacheStoreCompressionBehavior
162163
include CacheStoreFormatVersionBehavior
163164
include LocalCacheBehavior
164165
include CacheIncrementDecrementBehavior
@@ -233,14 +234,6 @@ def test_decrement_expires_in
233234
assert_equal false, @cache.exist?("foo")
234235
end
235236
end
236-
237-
def test_large_string_with_default_compression_settings
238-
assert_compressed(LARGE_STRING)
239-
end
240-
241-
def test_large_object_with_default_compression_settings
242-
assert_compressed(LARGE_OBJECT)
243-
end
244237
end
245238

246239
class ConnectionPoolBehaviorTest < StoreTest

0 commit comments

Comments
 (0)