github.com/99designs/gqlgen@v0.17.45/graphql/handler/extension/apq_test.go (about) 1 package extension_test 2 3 import ( 4 "context" 5 "net/http" 6 "testing" 7 8 "github.com/stretchr/testify/require" 9 10 "github.com/99designs/gqlgen/graphql" 11 "github.com/99designs/gqlgen/graphql/handler/extension" 12 "github.com/99designs/gqlgen/graphql/handler/testserver" 13 "github.com/99designs/gqlgen/graphql/handler/transport" 14 ) 15 16 func TestAPQIntegration(t *testing.T) { 17 h := testserver.New() 18 h.Use(&extension.AutomaticPersistedQuery{Cache: graphql.MapCache{}}) 19 h.AddTransport(&transport.POST{}) 20 21 var stats *extension.ApqStats 22 h.AroundResponses(func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response { 23 stats = extension.GetApqStats(ctx) 24 return next(ctx) 25 }) 26 27 resp := doRequest(h, "POST", "/graphql", `{"query":"{ name }","extensions":{"persistedQuery":{"version":1,"sha256Hash":"30166fc3298853f22709fce1e4a00e98f1b6a3160eaaaf9cb3b7db6a16073b07"}}}`) 28 require.Equal(t, http.StatusOK, resp.Code, resp.Body.String()) 29 require.Equal(t, `{"data":{"name":"test"}}`, resp.Body.String()) 30 31 require.NotNil(t, stats) 32 require.True(t, stats.SentQuery) 33 require.Equal(t, "30166fc3298853f22709fce1e4a00e98f1b6a3160eaaaf9cb3b7db6a16073b07", stats.Hash) 34 } 35 36 func TestAPQ(t *testing.T) { 37 const query = "{ me { name } }" 38 const hash = "b8d9506e34c83b0e53c2aa463624fcea354713bc38f95276e6f0bd893ffb5b88" 39 40 t.Run("with query and no hash", func(t *testing.T) { 41 ctx := newOC() 42 params := &graphql.RawParams{ 43 Query: "original query", 44 } 45 err := extension.AutomaticPersistedQuery{graphql.MapCache{}}.MutateOperationParameters(ctx, params) 46 require.Nil(t, err) 47 48 require.Equal(t, "original query", params.Query) 49 }) 50 51 t.Run("with hash miss and no query", func(t *testing.T) { 52 ctx := newOC() 53 params := &graphql.RawParams{ 54 Extensions: map[string]interface{}{ 55 "persistedQuery": map[string]interface{}{ 56 "sha256Hash": hash, 57 "version": 1, 58 }, 59 }, 60 } 61 62 err := extension.AutomaticPersistedQuery{graphql.MapCache{}}.MutateOperationParameters(ctx, params) 63 require.Equal(t, err.Message, "PersistedQueryNotFound") 64 }) 65 66 t.Run("with hash miss and query", func(t *testing.T) { 67 ctx := newOC() 68 params := &graphql.RawParams{ 69 Query: query, 70 Extensions: map[string]interface{}{ 71 "persistedQuery": map[string]interface{}{ 72 "sha256Hash": hash, 73 "version": 1, 74 }, 75 }, 76 } 77 cache := graphql.MapCache{} 78 err := extension.AutomaticPersistedQuery{cache}.MutateOperationParameters(ctx, params) 79 require.Nil(t, err) 80 81 require.Equal(t, "{ me { name } }", params.Query) 82 require.Equal(t, "{ me { name } }", cache[hash]) 83 }) 84 85 t.Run("with hash miss and query", func(t *testing.T) { 86 ctx := newOC() 87 params := &graphql.RawParams{ 88 Query: query, 89 Extensions: map[string]interface{}{ 90 "persistedQuery": map[string]interface{}{ 91 "sha256Hash": hash, 92 "version": 1, 93 }, 94 }, 95 } 96 cache := graphql.MapCache{} 97 err := extension.AutomaticPersistedQuery{cache}.MutateOperationParameters(ctx, params) 98 require.Nil(t, err) 99 100 require.Equal(t, "{ me { name } }", params.Query) 101 require.Equal(t, "{ me { name } }", cache[hash]) 102 }) 103 104 t.Run("with hash hit and no query", func(t *testing.T) { 105 ctx := newOC() 106 params := &graphql.RawParams{ 107 Extensions: map[string]interface{}{ 108 "persistedQuery": map[string]interface{}{ 109 "sha256Hash": hash, 110 "version": 1, 111 }, 112 }, 113 } 114 cache := graphql.MapCache{ 115 hash: query, 116 } 117 err := extension.AutomaticPersistedQuery{cache}.MutateOperationParameters(ctx, params) 118 require.Nil(t, err) 119 120 require.Equal(t, "{ me { name } }", params.Query) 121 }) 122 123 t.Run("with malformed extension payload", func(t *testing.T) { 124 ctx := newOC() 125 params := &graphql.RawParams{ 126 Extensions: map[string]interface{}{ 127 "persistedQuery": "asdf", 128 }, 129 } 130 131 err := extension.AutomaticPersistedQuery{graphql.MapCache{}}.MutateOperationParameters(ctx, params) 132 require.Equal(t, err.Message, "invalid APQ extension data") 133 }) 134 135 t.Run("with invalid extension version", func(t *testing.T) { 136 ctx := newOC() 137 params := &graphql.RawParams{ 138 Extensions: map[string]interface{}{ 139 "persistedQuery": map[string]interface{}{ 140 "version": 2, 141 }, 142 }, 143 } 144 err := extension.AutomaticPersistedQuery{graphql.MapCache{}}.MutateOperationParameters(ctx, params) 145 require.Equal(t, err.Message, "unsupported APQ version") 146 }) 147 148 t.Run("with hash mismatch", func(t *testing.T) { 149 ctx := newOC() 150 params := &graphql.RawParams{ 151 Query: query, 152 Extensions: map[string]interface{}{ 153 "persistedQuery": map[string]interface{}{ 154 "sha256Hash": "badhash", 155 "version": 1, 156 }, 157 }, 158 } 159 160 err := extension.AutomaticPersistedQuery{graphql.MapCache{}}.MutateOperationParameters(ctx, params) 161 require.Equal(t, err.Message, "provided APQ hash does not match query") 162 }) 163 } 164 165 func newOC() context.Context { 166 oc := &graphql.OperationContext{} 167 return graphql.WithOperationContext(context.Background(), oc) 168 }