-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
ApolloPersistedQuerySupportTest.groovy
172 lines (140 loc) · 6.73 KB
/
ApolloPersistedQuerySupportTest.groovy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package graphql.execution.preparsed.persisted
import graphql.ExecutionInput
import graphql.execution.preparsed.PreparsedDocumentEntry
import graphql.parser.Parser
import spock.lang.Specification
import java.util.function.Function
import static graphql.execution.preparsed.persisted.PersistedQuerySupport.PERSISTED_QUERY_MARKER
import static graphql.language.AstPrinter.printAstCompact
class ApolloPersistedQuerySupportTest extends Specification {
def hashOne = "761cd68b4afb3a824091884dd6cb759b5d068102c293af5a0bc2023bbf8fdb9f"
def hashTwo = "6e0a57aac0c8280588155e6d93436ad313e4c441b4e356703bdc297e32123d8f"
def knownQueries = [
(hashOne): "query { oneTwoThree }",
(hashTwo): "query { fourFiveSix }",
badHash : "query { fourFiveSix }"
]
// this cache will do a lookup, make the call back on miss and otherwise return cached values. And it
// tracks call counts for assertions
class CacheImplementation implements PersistedQueryCache {
def map = [:]
def keyCount = [:]
def parseCount = [:]
@Override
PreparsedDocumentEntry getPersistedQueryDocument(Object persistedQueryId, ExecutionInput executionInput, PersistedQueryCacheMiss onCacheMiss) throws PersistedQueryNotFound {
keyCount.compute(persistedQueryId, { k, v -> v == null ? 1 : v + 1 })
PreparsedDocumentEntry entry = map.get(persistedQueryId) as PreparsedDocumentEntry
if (entry != null) {
return entry
}
parseCount.compute(persistedQueryId, { k, v -> v == null ? 1 : v + 1 })
def queryText = knownQueries.get(persistedQueryId)
// if its outside our know bounds then throw because we dont have one
if (queryText == null) {
throw new PersistedQueryNotFound(persistedQueryId)
}
def newDocEntry = onCacheMiss.apply(queryText)
map.put(persistedQueryId, newDocEntry)
return newDocEntry
}
}
Function<ExecutionInput, PreparsedDocumentEntry> engineParser = {
ExecutionInput ei ->
def doc = new Parser().parseDocument(ei.getQuery())
return new PreparsedDocumentEntry(doc)
}
def mkEI(String hash, String query) {
ExecutionInput.newExecutionInput().query(query).extensions([persistedQuery: [sha256Hash: hash]]).build()
}
def "will call the callback on cache miss and then not after initial caching"() {
CacheImplementation persistedQueryCache = new CacheImplementation()
def apolloSupport = new ApolloPersistedQuerySupport(persistedQueryCache)
when:
def ei = mkEI(hashOne, PERSISTED_QUERY_MARKER)
def documentEntry = apolloSupport.getDocument(ei, engineParser)
def doc = documentEntry.getDocument()
then:
printAstCompact(doc) == "{oneTwoThree}"
persistedQueryCache.keyCount[hashOne] == 1
persistedQueryCache.parseCount[hashOne] == 1
when:
ei = mkEI(hashOne, PERSISTED_QUERY_MARKER)
documentEntry = apolloSupport.getDocument(ei, engineParser)
doc = documentEntry.getDocument()
then:
printAstCompact(doc) == "{oneTwoThree}"
persistedQueryCache.keyCount[hashOne] == 2
persistedQueryCache.parseCount[hashOne] == 1 // only compiled once cause we had it
}
def "will act as a normal query if there and no hash id present"() {
CacheImplementation persistedQueryCache = new CacheImplementation()
def apolloSupport = new ApolloPersistedQuerySupport(persistedQueryCache)
when:
def ei = ExecutionInput.newExecutionInput("query { normal }").build()
def documentEntry = apolloSupport.getDocument(ei, engineParser)
def doc = documentEntry.getDocument()
then:
printAstCompact(doc) == "{normal}"
persistedQueryCache.keyCount.size() == 0
persistedQueryCache.parseCount.size() == 0
}
def "will use query hash in preference to query text"() {
CacheImplementation persistedQueryCache = new CacheImplementation()
def apolloSupport = new ApolloPersistedQuerySupport(persistedQueryCache)
when:
def ei = mkEI(hashOne, "{normal}")
def documentEntry = apolloSupport.getDocument(ei, engineParser)
def doc = documentEntry.getDocument()
then:
printAstCompact(doc) == "{oneTwoThree}"
persistedQueryCache.keyCount[hashOne] == 1
persistedQueryCache.parseCount[hashOne] == 1
}
def "will have error if we dont return any query text on cache miss"() {
CacheImplementation persistedQueryCache = new CacheImplementation()
def apolloSupport = new ApolloPersistedQuerySupport(persistedQueryCache)
when:
def ei = mkEI("nonExistedHash", PERSISTED_QUERY_MARKER)
def documentEntry = apolloSupport.getDocument(ei, engineParser)
then:
documentEntry.getDocument() == null
def gqlError = documentEntry.getErrors()[0]
gqlError.getMessage() == "PersistedQueryNotFound"
gqlError.getErrorType().toString() == "PersistedQueryNotFound"
gqlError.getExtensions()["persistedQueryId"] == "nonExistedHash"
}
def "InMemoryPersistedQueryCache implementation works as expected with this class"() {
InMemoryPersistedQueryCache persistedQueryCache = new InMemoryPersistedQueryCache(knownQueries)
def apolloSupport = new ApolloPersistedQuerySupport(persistedQueryCache)
when:
def ei = mkEI(hashOne, PERSISTED_QUERY_MARKER)
def documentEntry = apolloSupport.getDocument(ei, engineParser)
def doc = documentEntry.getDocument()
then:
printAstCompact(doc) == "{oneTwoThree}"
when:
ei = mkEI(hashTwo, PERSISTED_QUERY_MARKER)
documentEntry = apolloSupport.getDocument(ei, engineParser)
doc = documentEntry.getDocument()
then:
printAstCompact(doc) == "{fourFiveSix}"
when:
ei = mkEI("nonExistent", PERSISTED_QUERY_MARKER)
documentEntry = apolloSupport.getDocument(ei, engineParser)
then:
documentEntry.hasErrors()
}
def "will have error if the calculated sha hash of the query does not match the persistedQueryId"() {
def cache = new CacheImplementation()
def apolloSupport = new ApolloPersistedQuerySupport(cache)
when:
def ei = mkEI("badHash", PERSISTED_QUERY_MARKER)
def docEntry = apolloSupport.getDocument(ei, engineParser)
then:
docEntry.getDocument() == null
def error = docEntry.getErrors()[0]
error.message == "PersistedQueryIdInvalid"
error.errorType.toString() == "PersistedQueryIdInvalid"
error.getExtensions()["persistedQueryId"] == "badHash"
}
}