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