...

Source file src/github.com/99designs/gqlgen/graphql/handler/extension/apq_test.go

Documentation: github.com/99designs/gqlgen/graphql/handler/extension

     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  }
   169  

View as plain text