11module CompilerService.Caches
22
33open FSharp.Compiler .Caches
4-
54open Xunit
6- open FSharp.Test
5+ open FSharp.Test . Assert
76open System.Threading .Tasks
87open System.Diagnostics
98
10- let assertTrue msg b = Assert.True( b, msg)
11-
129#if DEBUG
1310let shouldNeverTimeout = 15_000
1411#else
@@ -19,118 +16,115 @@ let shouldNeverTimeout = 200_000
1916[<Fact>]
2017let ``Create and dispose many`` () =
2118 let caches =
22- [
23- for _ in 1 .. 100 do
24- Cache.Create< string, int>( CacheOptions.Default, observeMetrics = true )
25- ]
19+ [ for _ in 1 .. 100 do
20+ Cache.Create< string, int>( CacheOptions.Default, observeMetrics = true ) ]
2621
27- for c in caches do c.Dispose()
22+ for c in caches do
23+ c.Dispose()
2824
2925[<Fact>]
3026let ``Create and dispose many named`` () =
3127 let caches =
32- [
33- for i in 1 .. 100 do
34- Cache.Create< string, int>( CacheOptions.Default, name = $" testCache{i}" , observeMetrics = true )
35- ]
28+ [ for i in 1 .. 100 do
29+ Cache.Create< string, int>( CacheOptions.Default, name = $" testCache{i}" , observeMetrics = true ) ]
3630
37- for c in caches do c.Dispose()
31+ for c in caches do
32+ c.Dispose()
3833
3934[<Fact>]
4035let ``Basic add and retrieve`` () =
4136 use cache = Cache.Create< string, int>( CacheOptions.Default, observeMetrics = true )
42-
43- cache.TryAdd( " key1" , 1 ) |> assertTrue " failed to add key1 "
44- cache.TryAdd( " key2" , 2 ) |> assertTrue " failed to add key2 "
45-
37+
38+ cache.TryAdd( " key1" , 1 ) |> shouldBeTrue
39+ cache.TryAdd( " key2" , 2 ) |> shouldBeTrue
40+
4641 let mutable value = 0
47- Assert.True( cache.TryGetValue( " key1" , & value), " Should retrieve key1" )
48- Assert.Equal( 1 , value)
49- Assert.True( cache.TryGetValue( " key2" , & value), " Should retrieve key2" )
50- Assert.Equal( 2 , value)
51- Assert.False( cache.TryGetValue( " key3" , & value), " Should not retrieve non-existent key3" )
42+
43+ cache.TryGetValue( " key1" , & value) |> shouldBeTrue
44+ value |> shouldEqual 1
45+
46+ cache.TryGetValue( " key2" , & value) |> shouldBeTrue
47+ value |> shouldEqual 2
48+
49+ cache.TryGetValue( " key3" , & value) |> shouldBeFalse
5250
5351[<Fact>]
5452let ``Eviction of least recently used`` () =
5553 use cache = Cache.Create< string, int>({ TotalCapacity = 2 ; HeadroomPercentage = 0 }, observeMetrics = true )
56-
57- cache.TryAdd( " key1" , 1 ) |> assertTrue " failed to add key1"
58- cache.TryAdd( " key2" , 2 ) |> assertTrue " failed to add key2"
59-
60- // Make key1 recently used by accessing it
54+
55+ cache.TryAdd( " key1" , 1 ) |> shouldBeTrue
56+ cache.TryAdd( " key2" , 2 ) |> shouldBeTrue
57+
6158 let mutable value = 0
62- cache.TryGetValue( " key1" , & value) |> assertTrue " failed to access key1 "
59+ cache.TryGetValue( " key1" , & value) |> shouldBeTrue
6360
6461 let evictionResult = TaskCompletionSource()
65-
6662 cache.Evicted.Add evictionResult.SetResult
6763 cache.EvictionFailed.Add ( fun _ -> evictionResult.SetException( Xunit.Sdk.FailException.ForFailure " eviction failed" ))
6864
69- // Add a third item, which should schedule key2 for eviction
70- cache.TryAdd( " key3" , 3 ) |> assertTrue " failed to add key3"
71-
72- // Wait for eviction to complete using the event
73- evictionResult.Task.Wait shouldNeverTimeout |> assertTrue " eviction did not complete in time"
74-
75- Assert.False( cache.TryGetValue( " key2" , & value), " key2 should have been evicted" )
76- Assert.True( cache.TryGetValue( " key1" , & value), " key1 should still be in cache" )
77- Assert.Equal( 1 , value)
78- Assert.True( cache.TryGetValue( " key3" , & value), " key3 should be in cache" )
79- Assert.Equal( 3 , value)
65+ cache.TryAdd( " key3" , 3 ) |> shouldBeTrue
66+ evictionResult.Task.Wait shouldNeverTimeout |> shouldBeTrue
67+
68+ cache.TryGetValue( " key2" , & value) |> shouldBeFalse
69+
70+ cache.TryGetValue( " key1" , & value) |> shouldBeTrue
71+ value |> shouldEqual 1
72+
73+ cache.TryGetValue( " key3" , & value) |> shouldBeTrue
74+ value |> shouldEqual 3
8075
8176[<Fact>]
8277let ``Stress test evictions`` () =
8378 let cacheSize = 100
8479 let iterations = 10_000
8580 let name = " Stress test evictions"
81+
8682 use cache = Cache.Create< string, int>({ TotalCapacity = cacheSize; HeadroomPercentage = 0 }, name = name, observeMetrics = true )
8783
8884 let evictionsCompleted = new TaskCompletionSource< unit>()
8985 let expectedEvictions = iterations - cacheSize
9086
9187 cache.Evicted.Add <| fun () ->
92- if CacheMetrics.GetTotals( name).[ " evictions" ] = expectedEvictions then evictionsCompleted.SetResult()
88+ if CacheMetrics.GetTotals( name).[ " evictions" ] = expectedEvictions then
89+ evictionsCompleted.SetResult()
9390
94- // Should not fail, but if it does, we want to know
9591 cache.EvictionFailed.Add <| fun _ ->
9692 evictionsCompleted.SetException( Xunit.Sdk.FailException.ForFailure " eviction failed" )
9793
9894 for i in 1 .. iterations do
99- cache.TryAdd( $" key{i}" , i) |> assertTrue ( $ " failed to add key{i} " )
95+ cache.TryAdd( $" key{i}" , i) |> shouldBeTrue
10096
101- // Wait for all expected evictions to complete
102- evictionsCompleted.Task.Wait shouldNeverTimeout |> assertTrue " evictions did not complete in time"
97+ evictionsCompleted.Task.Wait shouldNeverTimeout |> shouldBeTrue
10398
10499 let mutable value = 0
105- Assert.False( cache.TryGetValue( $" key{iterations - cacheSize}" , & value), " An old key should have been evicted" )
106- Assert.True( cache.TryGetValue( $" key{iterations - cacheSize + 1}" , & value), " The first of the newest keys should be in cache" )
107- Assert.Equal( iterations - cacheSize + 1 , value)
108- Assert.True( cache.TryGetValue( $" key{iterations}" , & value), " The last key should be in cache" )
109- Assert.Equal( iterations, value)
100+
101+ cache.TryGetValue( $" key{iterations - cacheSize}" , & value) |> shouldBeFalse
102+
103+ cache.TryGetValue( $" key{iterations - cacheSize + 1}" , & value) |> shouldBeTrue
104+ value |> shouldEqual ( iterations - cacheSize + 1 )
105+
106+ cache.TryGetValue( $" key{iterations}" , & value) |> shouldBeTrue
107+ value |> shouldEqual iterations
110108
111109[<Fact>]
112110let ``Metrics can be retrieved`` () =
113111 use cache = Cache.Create< string, int>({ TotalCapacity = 2 ; HeadroomPercentage = 0 }, name = " test_metrics" , observeMetrics = true )
114-
115- cache.TryAdd( " key1" , 1 ) |> assertTrue " failed to add key1"
116- cache.TryAdd( " key2" , 2 ) |> assertTrue " failed to add key2"
117-
118- // Make key1 recently used by accessing it
112+
113+ cache.TryAdd( " key1" , 1 ) |> shouldBeTrue
114+ cache.TryAdd( " key2" , 2 ) |> shouldBeTrue
115+
119116 let mutable value = 0
120- cache.TryGetValue( " key1" , & value) |> assertTrue " failed to access key1 "
117+ cache.TryGetValue( " key1" , & value) |> shouldBeTrue
121118
122119 let evictionCompleted = TaskCompletionSource()
123120 cache.Evicted.Add( fun _ -> evictionCompleted.SetResult())
124121 cache.EvictionFailed.Add( fun _ -> evictionCompleted.SetException( Xunit.Sdk.FailException.ForFailure " eviction failed" ))
125-
126- // Add a third item, which should schedule key2 for eviction
127- cache.TryAdd( " key3" , 3 ) |> assertTrue " failed to add key3"
128-
129- // Wait for eviction to complete
130- evictionCompleted.Task.Wait shouldNeverTimeout |> assertTrue " eviction did not complete in time"
122+
123+ cache.TryAdd( " key3" , 3 ) |> shouldBeTrue
124+ evictionCompleted.Task.Wait shouldNeverTimeout |> shouldBeTrue
131125
132126 let stats = CacheMetrics.GetStats " test_metrics"
133127 let totals = CacheMetrics.GetTotals " test_metrics"
134128
135- Assert.Equal ( 1.0 , stats[ " hit-ratio" ])
136- Assert.Equal ( 1 L , totals[ " evictions" ])
129+ stats. [" hit-ratio" ] |> shouldEqual 1.0
130+ totals. [" evictions" ] |> shouldEqual 1 L
0 commit comments