@@ -41,28 +41,109 @@ public async Task Validate_Cache_Cannot_Be_Removed_Or_Set_To_Null()
41
41
( await memoryCache . GetAsyncPublic ( options ) ) . ShouldBe ( doc ) ;
42
42
}
43
43
44
+ /// <summary>
45
+ /// Executes multiple scenarios to verify that caching works correctly with Query strings and DocumentIds.
46
+ /// </summary>
47
+ /// <param name="cacheQuery">The Query string used when setting the cache. Can be null.</param>
48
+ /// <param name="cacheDocumentId">The DocumentId used when setting the cache. Can be null.</param>
49
+ /// <param name="retrieveQuery">The Query string used when retrieving from the cache. Can be null.</param>
50
+ /// <param name="retrieveDocumentId">The DocumentId used when retrieving from the cache. Can be null.</param>
51
+ /// <param name="expectCached">Indicates whether the retrieval is expected to find the cached document.</param>
52
+ [ Theory ]
53
+ [ InlineData ( "query1" , null , "query1" , null , true ) ] // Cache by Query, retrieve by same Query
54
+ [ InlineData ( "query1" , null , "query2" , null , false ) ] // Cache by Query, retrieve by different Query
55
+ [ InlineData ( null , "doc1" , null , "doc1" , true ) ] // Cache by DocumentId, retrieve by same DocumentId
56
+ [ InlineData ( null , "doc1" , null , "doc2" , false ) ] // Cache by DocumentId, retrieve by different DocumentId
57
+ [ InlineData ( "query1" , null , null , null , false ) ] // Cache by Query, retrieve without Query or DocumentId
58
+ [ InlineData ( "query1" , "doc1" , "query1" , null , false ) ] // Cache by both, retrieve with only Query
59
+ [ InlineData ( "query1" , "doc1" , null , "doc1" , true ) ] // Cache by both, retrieve with only DocumentId (typical scenario)
60
+ [ InlineData ( null , null , "query1" , null , false ) ] // Cache by neither, retrieve with only Query
61
+ [ InlineData ( null , null , null , "doc1" , false ) ] // Cache by neither, retrieve with only DocumentId
62
+ [ InlineData ( null , null , null , null , false ) ] // Cache by neither, retrieve with neither
63
+ // note: the following scenarios, retrieving by both, will throw an error in ExecuteAsync, but are provided here for completeness
64
+ [ InlineData ( "query1" , "doc1" , "query1" , "doc1" , true ) ] // Cache by both, retrieve by both
65
+ [ InlineData ( "query1" , "doc1" , "query1" , "doc2" , false ) ] // Cache by both, retrieve with different DocumentId
66
+ [ InlineData ( "query1" , "doc1" , "query2" , "doc1" , true ) ] // Cache by both, retrieve with different Query
67
+ [ InlineData ( "query1" , "doc1" , "query2" , "doc2" , false ) ] // Cache by both, retrieve with different Query and DocumentId
68
+ [ InlineData ( null , "doc1" , "query1" , "doc1" , true ) ] // Cache by DocumentId, retrieve with Query and same DocumentId
69
+ public async Task GetAsync_And_SetAsync_Should_Handle_Query_And_DocumentId_Correctly (
70
+ string ? cacheQuery ,
71
+ string ? cacheDocumentId ,
72
+ string ? retrieveQuery ,
73
+ string ? retrieveDocumentId ,
74
+ bool expectCached )
75
+ {
76
+ // Arrange
77
+ var document = new GraphQLDocument ( new ( ) ) ;
78
+ var cacheOptions = new ExecutionOptions
79
+ {
80
+ Query = cacheQuery ,
81
+ DocumentId = cacheDocumentId
82
+ } ;
83
+ var retrieveOptions = new ExecutionOptions
84
+ {
85
+ Query = retrieveQuery ,
86
+ DocumentId = retrieveDocumentId
87
+ } ;
88
+ var memoryCache = new MyMemoryDocumentCache ( ) ;
89
+
90
+ // Act
91
+ var initialDocument = await memoryCache . GetAsyncPublic ( retrieveOptions ) ;
92
+
93
+ if ( cacheQuery != null || cacheDocumentId != null )
94
+ {
95
+ await memoryCache . SetAsyncPublic ( cacheOptions , document ) ;
96
+ }
97
+
98
+ var cachedDocument = await memoryCache . GetAsyncPublic ( retrieveOptions ) ;
99
+
100
+ // Assert
101
+ initialDocument . ShouldBeNull ( ) ;
102
+ if ( expectCached )
103
+ {
104
+ cachedDocument . ShouldBe ( document ) ;
105
+ }
106
+ else
107
+ {
108
+ cachedDocument . ShouldBeNull ( ) ;
109
+ }
110
+ }
111
+
44
112
[ Theory ]
45
113
// no query set
46
- [ InlineData ( false , false , false , false , true , true , false ) ]
114
+ [ InlineData ( false , false , false , false , false , true , true , false ) ]
47
115
// doc already set
48
- [ InlineData ( false , true , false , false , true , true , false ) ]
49
- [ InlineData ( true , true , false , false , true , true , false ) ]
116
+ [ InlineData ( false , false , true , false , false , true , true , false ) ]
117
+ [ InlineData ( true , false , true , false , false , true , true , false ) ]
118
+ [ InlineData ( false , true , true , false , false , true , true , false ) ]
119
+ [ InlineData ( true , true , true , false , false , false , false , false ) ]
50
120
// typical path with cache miss
51
- [ InlineData ( true , false , true , false , true , true , true ) ] // passed validation
52
- [ InlineData ( true , false , true , false , false , true , false ) ] // failed validation
53
- [ InlineData ( true , false , true , false , true , false , false ) ] // didn't set document (should not be possible)
54
- [ InlineData ( true , false , true , false , false , false , false ) ] // failed parse
121
+ [ InlineData ( true , false , false , true , false , true , true , true ) ] // passed validation
122
+ [ InlineData ( true , false , false , true , false , false , true , false ) ] // failed validation
123
+ [ InlineData ( true , false , false , true , false , true , false , false ) ] // didn't set document (should not be possible)
124
+ [ InlineData ( true , false , false , true , false , false , false , false ) ] // failed parse
125
+ [ InlineData ( false , true , false , true , false , true , true , true ) ] // passed validation
126
+ [ InlineData ( false , true , false , true , false , false , true , false ) ] // failed validation
127
+ [ InlineData ( false , true , false , true , false , true , false , false ) ] // didn't set document (should not be possible)
128
+ [ InlineData ( false , true , false , true , false , false , false , false ) ] // failed parse
55
129
// typical path with cache hit; should never call SetAsync
56
- [ InlineData ( true , false , true , true , true , true , false ) ]
57
- [ InlineData ( true , false , true , true , false , true , false ) ]
58
- [ InlineData ( true , false , true , true , true , false , false ) ]
59
- [ InlineData ( true , false , true , true , false , false , false ) ]
60
- public async Task ExecuteAsync ( bool querySet , bool docSet , bool getCalled , bool getReturned , bool executed , bool exectuedSetDocument , bool setCalled )
130
+ [ InlineData ( true , false , false , true , true , true , true , false ) ]
131
+ [ InlineData ( true , false , false , true , true , false , true , false ) ]
132
+ [ InlineData ( true , false , false , true , true , true , false , false ) ]
133
+ [ InlineData ( true , false , false , true , true , false , false , false ) ]
134
+ [ InlineData ( false , true , false , true , true , true , true , false ) ]
135
+ [ InlineData ( false , true , false , true , true , false , true , false ) ]
136
+ [ InlineData ( false , true , false , true , true , true , false , false ) ]
137
+ [ InlineData ( false , true , false , true , true , false , false , false ) ]
138
+ // query and documentId set; should return error
139
+ [ InlineData ( true , true , false , false , false , false , false , false ) ]
140
+ public async Task ExecuteAsync ( bool querySet , bool documentIdSet , bool docSet , bool getCalled , bool getReturned , bool executed , bool exectuedSetDocument , bool setCalled )
61
141
{
62
142
var mockDocument = new GraphQLDocument ( new ( ) ) ;
63
143
var options = new ExecutionOptions
64
144
{
65
145
Query = querySet ? "Some Query" : null ,
146
+ DocumentId = documentIdSet ? "Some Document Id" : null ,
66
147
Document = docSet ? mockDocument : null ,
67
148
} ;
68
149
@@ -86,19 +167,29 @@ public async Task ExecuteAsync(bool querySet, bool docSet, bool getCalled, bool
86
167
return default ;
87
168
} ) ;
88
169
89
- var result = new ExecutionResult ( )
170
+ if ( querySet && documentIdSet && ! docSet )
90
171
{
91
- Executed = executed ,
92
- Document = exectuedSetDocument ? mockDocument : null ,
93
- } ;
94
-
95
- var ret = await memoryDocumentCacheMock . Object . ExecuteAsync ( options , ( opts ) =>
172
+ var errResult = await memoryDocumentCacheMock . Object . ExecuteAsync ( options , ( opts ) => throw new InvalidOperationException ( ) ) ;
173
+ errResult . Errors . ShouldNotBeNull ( ) ;
174
+ errResult . Errors . Count . ShouldBe ( 1 ) ;
175
+ errResult . Errors [ 0 ] . ShouldBeAssignableTo < PersistedDocuments . InvalidRequestError > ( ) ;
176
+ }
177
+ else
96
178
{
97
- opts . ShouldBe ( options ) ;
98
- return Task . FromResult ( result ) ;
99
- } ) ;
179
+ var result = new ExecutionResult ( )
180
+ {
181
+ Executed = executed ,
182
+ Document = exectuedSetDocument ? mockDocument : null ,
183
+ } ;
184
+
185
+ var ret = await memoryDocumentCacheMock . Object . ExecuteAsync ( options , ( opts ) =>
186
+ {
187
+ opts . ShouldBe ( options ) ;
188
+ return Task . FromResult ( result ) ;
189
+ } ) ;
100
190
101
- ret . ShouldBe ( result ) ;
191
+ ret . ShouldBe ( result ) ;
192
+ }
102
193
103
194
memoryDocumentCacheMock . Protected ( ) . Verify ( "GetAsync" , getCalled ? Times . Once ( ) : Times . Never ( ) , ItExpr . IsAny < ExecutionOptions > ( ) ) ;
104
195
memoryDocumentCacheMock . Protected ( ) . Verify ( "SetAsync" , setCalled ? Times . Once ( ) : Times . Never ( ) , ItExpr . IsAny < ExecutionOptions > ( ) , ItExpr . IsAny < GraphQLDocument > ( ) ) ;
0 commit comments