github.com/99designs/gqlgen@v0.17.45/complexity/complexity_test.go (about) 1 package complexity 2 3 import ( 4 "math" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 "github.com/vektah/gqlparser/v2" 9 "github.com/vektah/gqlparser/v2/ast" 10 11 "github.com/99designs/gqlgen/graphql" 12 ) 13 14 var schema = gqlparser.MustLoadSchema( 15 &ast.Source{ 16 Name: "test.graphql", 17 Input: ` 18 interface NameInterface { 19 name: String 20 } 21 22 type Item implements NameInterface { 23 scalar: String 24 name: String 25 list(size: Int = 10): [Item] 26 } 27 28 type ExpensiveItem implements NameInterface { 29 name: String 30 } 31 32 type Named { 33 name: String 34 } 35 36 union NameUnion = Item | Named 37 38 type Query { 39 scalar: String 40 object: Item 41 interface: NameInterface 42 union: NameUnion 43 customObject: Item 44 list(size: Int = 10): [Item] 45 } 46 `, 47 }, 48 ) 49 50 func requireComplexity(t *testing.T, source string, complexity int) { 51 t.Helper() 52 query := gqlparser.MustLoadQuery(schema, source) 53 54 es := &graphql.ExecutableSchemaMock{ 55 ComplexityFunc: func(typeName, field string, childComplexity int, args map[string]interface{}) (int, bool) { 56 switch typeName + "." + field { 57 case "ExpensiveItem.name": 58 return 5, true 59 case "Query.list", "Item.list": 60 return int(args["size"].(int64)) * childComplexity, true 61 case "Query.customObject": 62 return 1, true 63 } 64 return 0, false 65 }, 66 SchemaFunc: func() *ast.Schema { 67 return schema 68 }, 69 } 70 71 actualComplexity := Calculate(es, query.Operations[0], nil) 72 require.Equal(t, complexity, actualComplexity) 73 } 74 75 func TestCalculate(t *testing.T) { 76 t.Run("uses default cost", func(t *testing.T) { 77 const query = ` 78 { 79 scalar 80 } 81 ` 82 requireComplexity(t, query, 1) 83 }) 84 85 t.Run("adds together fields", func(t *testing.T) { 86 const query = ` 87 { 88 scalar1: scalar 89 scalar2: scalar 90 } 91 ` 92 requireComplexity(t, query, 2) 93 }) 94 95 t.Run("a level of nesting adds complexity", func(t *testing.T) { 96 const query = ` 97 { 98 object { 99 scalar 100 } 101 } 102 ` 103 requireComplexity(t, query, 2) 104 }) 105 106 t.Run("adds together children", func(t *testing.T) { 107 const query = ` 108 { 109 scalar 110 object { 111 scalar 112 } 113 } 114 ` 115 requireComplexity(t, query, 3) 116 }) 117 118 t.Run("adds inline fragments", func(t *testing.T) { 119 const query = ` 120 { 121 ... { 122 scalar 123 } 124 } 125 ` 126 requireComplexity(t, query, 1) 127 }) 128 129 t.Run("adds fragments", func(t *testing.T) { 130 const query = ` 131 { 132 ... Fragment 133 } 134 135 fragment Fragment on Query { 136 scalar 137 } 138 ` 139 requireComplexity(t, query, 1) 140 }) 141 142 t.Run("uses custom complexity", func(t *testing.T) { 143 const query = ` 144 { 145 list { 146 scalar 147 } 148 } 149 ` 150 requireComplexity(t, query, 10) 151 }) 152 153 t.Run("ignores negative custom complexity values", func(t *testing.T) { 154 const query = ` 155 { 156 list(size: -100) { 157 scalar 158 } 159 } 160 ` 161 requireComplexity(t, query, 2) 162 }) 163 164 t.Run("custom complexity must be >= child complexity", func(t *testing.T) { 165 const query = ` 166 { 167 customObject { 168 list(size: 100) { 169 scalar 170 } 171 } 172 } 173 ` 174 requireComplexity(t, query, 101) 175 }) 176 177 t.Run("interfaces take max concrete cost", func(t *testing.T) { 178 const query = ` 179 { 180 interface { 181 name 182 } 183 } 184 ` 185 requireComplexity(t, query, 6) 186 }) 187 188 t.Run("guards against integer overflow", func(t *testing.T) { 189 if maxInt == math.MaxInt32 { 190 // this test is written assuming 64-bit ints 191 t.Skip() 192 } 193 const query = ` 194 { 195 list1: list(size: 2147483647) { 196 list(size: 2147483647) { 197 list(size: 2) { 198 scalar 199 } 200 } 201 } 202 # total cost so far: 2*0x7fffffff*0x7fffffff 203 # = 0x7ffffffe00000002 204 # Adding the same again should cause overflow 205 list2: list(size: 2147483647) { 206 list(size: 2147483647) { 207 list(size: 2) { 208 scalar 209 } 210 } 211 } 212 } 213 ` 214 requireComplexity(t, query, math.MaxInt64) 215 }) 216 }