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 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
# frozen_string_literal: true
require "spec_helper"
describe GraphQL::Analysis::AST::MaxQueryComplexity do
let(:schema) { Class.new(Dummy::Schema) }
let(:query_string) {%|
{
a: cheese(id: 1) { id }
b: cheese(id: 1) { id }
c: cheese(id: 1) { id }
d: cheese(id: 1) { id }
e: cheese(id: 1) { id }
}
|}
let(:query) { GraphQL::Query.new(schema, query_string, variables: {}, max_complexity: max_complexity) }
let(:result) {
GraphQL::Analysis::AST.analyze_query(query, [GraphQL::Analysis::AST::MaxQueryComplexity]).first
}
describe "when a query goes over max complexity" do
let(:max_complexity) { 9 }
it "returns an error" do
assert_equal GraphQL::AnalysisError, result.class
assert_equal "Query has complexity of 10, which exceeds max complexity of 9", result.message
end
end
describe "when there is no max complexity" do
let(:max_complexity) { nil }
it "doesn't error" do
assert_nil result
end
end
describe "when the query is less than the max complexity" do
let(:max_complexity) { 99 }
it "doesn't error" do
assert_nil result
end
end
describe "when max_complexity is decreased at query-level" do
before do
schema.max_complexity(100)
end
let(:max_complexity) { 7 }
it "is applied" do
assert_equal GraphQL::AnalysisError, result.class
assert_equal "Query has complexity of 10, which exceeds max complexity of 7", result.message
end
end
describe "when max_complexity is increased at query-level" do
before do
schema.max_complexity(1)
end
let(:max_complexity) { 10 }
it "doesn't error" do
assert_nil result
end
end
describe "when max_complexity is nil at query-level" do
let(:max_complexity) { nil }
before do
schema.max_complexity(1)
end
it "is applied" do
assert_nil result
end
end
describe "when used with the max_depth plugin" do
let(:schema) do
Class.new(GraphQL::Schema) do
query Dummy::DairyAppQuery
max_depth 3
max_complexity 1
end
end
let(:query_string) {%|
{
a: cheese(id: 1) { ...cheeseFields }
b: cheese(id: 1) { ...cheeseFields }
c: cheese(id: 1) { ...cheeseFields }
d: cheese(id: 1) { ...cheeseFields }
e: cheese(id: 1) { ...cheeseFields }
}
fragment cheeseFields on Cheese { id }
|}
let(:result) { schema.execute(query_string) }
it "returns a complexity error" do
assert_equal "Query has complexity of 10, which exceeds max complexity of 1", result["errors"].first["message"]
end
end
describe "across a multiplex" do
before do
schema.analysis_engine = GraphQL::Analysis::AST
end
let(:queries) {
5.times.map { |n|
GraphQL::Query.new(schema, "{ cheese(id: #{n}) { id } }", variables: {})
}
}
let(:max_complexity) { 9 }
let(:multiplex) { GraphQL::Execution::Multiplex.new(schema: schema, queries: queries, context: {}, max_complexity: max_complexity) }
let(:analyze_multiplex) {
GraphQL::Analysis::AST.analyze_multiplex(multiplex, [GraphQL::Analysis::AST::MaxQueryComplexity])
}
it "returns errors for all queries" do
analyze_multiplex
err_msg = "Query has complexity of 10, which exceeds max complexity of 9"
queries.each do |query|
assert_equal err_msg, query.analysis_errors[0].message
end
end
describe "with a local override" do
let(:max_complexity) { 10 }
it "uses the override" do
analyze_multiplex
queries.each do |query|
assert query.analysis_errors.empty?
end
end
end
end
describe "when an argument is unauthorized by type" do
class AuthorizedTypeSchema < GraphQL::Schema
class Thing < GraphQL::Schema::Object
def self.authorized?(obj, ctx)
!!ctx[:authorized] && super
end
field :name, String
end
class Query < GraphQL::Schema::Object
field :things, Thing.connection_type do
argument :thing_id, ID, loads: Thing
end
def things(thing:)
[thing]
end
end
query(Query)
def self.resolve_type(abs_type, object, ctx)
Thing
end
def self.object_from_id(id, ctx)
{ name: "Loaded thing #{id}" }
end
def self.unauthorized_object(err)
raise GraphQL::ExecutionError, "Unauthorized Object: #{err.object[:name].inspect}"
end
default_max_page_size 30
max_complexity 10
end
it "when the arg is unauthorized, returns an authorization error, not a complexity error" do
query_str = "{ things(thingId: \"123\", first: 1) { nodes { name } } }"
res = AuthorizedTypeSchema.execute(query_str, context: { authorized: true })
assert_equal "Loaded thing 123", res["data"]["things"]["nodes"].first["name"]
res2 = AuthorizedTypeSchema.execute(query_str)
assert_equal ["Unauthorized Object: \"Loaded thing 123\""], res2["errors"].map { |e| e["message"] }
end
end
end
|