304 lines
7.5 KiB
Go
304 lines
7.5 KiB
Go
package integration_tests
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
"encoding/json"
|
||
"testing"
|
||
|
||
"github.com/dosco/super-graph/core"
|
||
"github.com/stretchr/testify/assert"
|
||
"github.com/stretchr/testify/require"
|
||
)
|
||
|
||
func SetupSchema(t *testing.T, db *sql.DB) {
|
||
|
||
_, err := db.Exec(`
|
||
CREATE TABLE users (
|
||
id integer PRIMARY KEY,
|
||
full_name text
|
||
)`)
|
||
require.NoError(t, err)
|
||
|
||
_, err = db.Exec(`CREATE TABLE product (
|
||
id integer PRIMARY KEY,
|
||
name text,
|
||
weight float
|
||
)`)
|
||
require.NoError(t, err)
|
||
|
||
_, err = db.Exec(`CREATE TABLE line_item (
|
||
id integer PRIMARY KEY,
|
||
product integer REFERENCES product(id),
|
||
quantity integer,
|
||
price float
|
||
)`)
|
||
require.NoError(t, err)
|
||
}
|
||
|
||
func DropSchema(t *testing.T, db *sql.DB) {
|
||
|
||
_, err := db.Exec(`DROP TABLE IF EXISTS line_item`)
|
||
require.NoError(t, err)
|
||
|
||
_, err = db.Exec(`DROP TABLE IF EXISTS product`)
|
||
require.NoError(t, err)
|
||
|
||
_, err = db.Exec(`DROP TABLE IF EXISTS users`)
|
||
require.NoError(t, err)
|
||
}
|
||
|
||
func TestSuperGraph(t *testing.T, db *sql.DB, before func(t *testing.T)) {
|
||
config := core.Config{}
|
||
config.UseAllowList = false
|
||
config.AllowListFile = "./allow.list"
|
||
config.RolesQuery = `SELECT * FROM users WHERE id = $user_id`
|
||
|
||
config.Roles = []core.Role{
|
||
core.Role{
|
||
Name: "anon",
|
||
Tables: []core.RoleTable{
|
||
core.RoleTable{Name: "users", Query: core.Query{Limit: 100}},
|
||
core.RoleTable{Name: "product", Query: core.Query{Limit: 100}},
|
||
core.RoleTable{Name: "line_item", Query: core.Query{Limit: 100}},
|
||
},
|
||
},
|
||
}
|
||
|
||
sg, err := core.NewSuperGraph(&config, db)
|
||
require.NoError(t, err)
|
||
ctx := context.Background()
|
||
|
||
t.Run("seed fixtures", func(t *testing.T) {
|
||
before(t)
|
||
res, err := sg.GraphQL(ctx,
|
||
`mutation { products (insert: $products) { id } }`,
|
||
json.RawMessage(`{"products":[
|
||
{"id":1, "name":"Charmin Ultra Soft", "weight": 0.5},
|
||
{"id":2, "name":"Hand Sanitizer", "weight": 0.2},
|
||
{"id":3, "name":"Case of Corona", "weight": 1.2}
|
||
]}`))
|
||
require.NoError(t, err, res.SQL())
|
||
require.Equal(t, `{"products": [{"id": 1}, {"id": 2}, {"id": 3}]}`, string(res.Data))
|
||
|
||
res, err = sg.GraphQL(ctx,
|
||
`mutation { line_items (insert: $line_items) { id } }`,
|
||
json.RawMessage(`{"line_items":[
|
||
{"id":5001, "product":1, "price":6.95, "quantity":10},
|
||
{"id":5002, "product":2, "price":10.99, "quantity":2}
|
||
]}`))
|
||
require.NoError(t, err, res.SQL())
|
||
require.Equal(t, `{"line_items": [{"id": 5001}, {"id": 5002}]}`, string(res.Data))
|
||
})
|
||
|
||
t.Run("get line item", func(t *testing.T) {
|
||
before(t)
|
||
res, err := sg.GraphQL(ctx,
|
||
`query { line_item(id:$id) { id, price, quantity } }`,
|
||
json.RawMessage(`{"id":5001}`))
|
||
require.NoError(t, err, res.SQL())
|
||
require.Equal(t, `{"line_item": {"id": 5001, "price": 6.95, "quantity": 10}}`, string(res.Data))
|
||
})
|
||
|
||
t.Run("get line items", func(t *testing.T) {
|
||
before(t)
|
||
res, err := sg.GraphQL(ctx,
|
||
`query { line_items { id, price, quantity } }`,
|
||
json.RawMessage(`{}`))
|
||
require.NoError(t, err, res.SQL())
|
||
require.Equal(t, `{"line_items": [{"id": 5001, "price": 6.95, "quantity": 10}, {"id": 5002, "price": 10.99, "quantity": 2}]}`, string(res.Data))
|
||
})
|
||
|
||
t.Run("update line item", func(t *testing.T) {
|
||
before(t)
|
||
res, err := sg.GraphQL(ctx,
|
||
`mutation { line_item(update:$update, id:$id) { id } }`,
|
||
json.RawMessage(`{"id":5001, "update":{"quantity":20}}`))
|
||
require.NoError(t, err, res.SQL())
|
||
require.Equal(t, `{"line_item": {"id": 5001}}`, string(res.Data))
|
||
|
||
res, err = sg.GraphQL(ctx,
|
||
`query { line_item(id:$id) { id, price, quantity } }`,
|
||
json.RawMessage(`{"id":5001}`))
|
||
require.NoError(t, err, res.SQL())
|
||
require.Equal(t, `{"line_item": {"id": 5001, "price": 6.95, "quantity": 20}}`, string(res.Data))
|
||
})
|
||
|
||
t.Run("delete line item", func(t *testing.T) {
|
||
before(t)
|
||
res, err := sg.GraphQL(ctx,
|
||
`mutation { line_item(delete:true, id:$id) { id } }`,
|
||
json.RawMessage(`{"id":5002}`))
|
||
require.NoError(t, err, res.SQL())
|
||
require.Equal(t, `{"line_item": {"id": 5002}}`, string(res.Data))
|
||
|
||
res, err = sg.GraphQL(ctx,
|
||
`query { line_items { id, price, quantity } }`,
|
||
json.RawMessage(`{}`))
|
||
require.NoError(t, err, res.SQL())
|
||
require.Equal(t, `{"line_items": [{"id": 5001, "price": 6.95, "quantity": 20}]}`, string(res.Data))
|
||
})
|
||
|
||
t.Run("nested insert", func(t *testing.T) {
|
||
before(t)
|
||
res, err := sg.GraphQL(ctx,
|
||
`mutation { line_items (insert: $line_item) { id, product { name } } }`,
|
||
json.RawMessage(`{"line_item":
|
||
{"id":5003, "product": { "connect": { "id": 1} }, "price":10.95, "quantity":15}
|
||
}`))
|
||
require.NoError(t, err, res.SQL())
|
||
require.Equal(t, `{"line_items": [{"id": 5003, "product": {"name": "Charmin Ultra Soft"}}]}`, string(res.Data))
|
||
})
|
||
|
||
t.Run("schema introspection", func(t *testing.T) {
|
||
before(t)
|
||
// fmt.Println(sg.Engine.Schema.String())
|
||
assert.Equal(t, `type Mutation {
|
||
line_item(id:Int!, insert:line_itemInput, inserts:[line_itemInput!]!, update:line_itemInput, updates:[line_itemInput!]!):line_itemOutput
|
||
product(id:Int!, insert:productInput, inserts:[productInput!]!, update:productInput, updates:[productInput!]!):productOutput
|
||
user(id:Int!, insert:userInput, inserts:[userInput!]!, update:userInput, updates:[userInput!]!):userOutput
|
||
}
|
||
type Query {
|
||
line_item(id:Int!):line_itemOutput
|
||
line_items(id:Int!):[line_itemOutput!]!
|
||
product(id:Int!):productOutput
|
||
products(id:Int!):[productOutput!]!
|
||
user(id:Int!):userOutput
|
||
users(id:Int!):[userOutput!]!
|
||
}
|
||
input line_itemInput {
|
||
id:Int!
|
||
price:Float
|
||
product:Int
|
||
quantity:Int
|
||
}
|
||
type line_itemOutput {
|
||
id:Int!
|
||
price:Float
|
||
product:Int
|
||
quantity:Int
|
||
}
|
||
input productInput {
|
||
id:Int!
|
||
name:String
|
||
weight:Float
|
||
}
|
||
type productOutput {
|
||
id:Int!
|
||
name:String
|
||
weight:Float
|
||
}
|
||
input userInput {
|
||
full_name:String
|
||
id:Int!
|
||
}
|
||
type userOutput {
|
||
full_name:String
|
||
id:Int!
|
||
}
|
||
schema {
|
||
mutation: Mutation
|
||
query: Query
|
||
}
|
||
`, sg.Engine.Schema.String())
|
||
})
|
||
|
||
res, err := sg.GraphQL(ctx,introspectionQuery, json.RawMessage(``))
|
||
assert.NoError(t, err)
|
||
assert.Contains(t, string(res.Data),
|
||
`{"queryType":{"name":"Query"},"mutationType":{"name":"Mutation"},"subscriptionType":null,"types":`)
|
||
assert.Contains(t, string(res.Data),
|
||
`{"kind":"OBJECT","name":"Mutation","description":null,"fields":[{"name":"line_item","description":null`)
|
||
}
|
||
|
||
const introspectionQuery = `
|
||
query {
|
||
__schema {
|
||
queryType { name }
|
||
mutationType { name }
|
||
subscriptionType { name }
|
||
types {
|
||
...FullType
|
||
}
|
||
directives {
|
||
name
|
||
description
|
||
locations
|
||
args {
|
||
...InputValue
|
||
}
|
||
}
|
||
}
|
||
}
|
||
fragment FullType on __Type {
|
||
kind
|
||
name
|
||
description
|
||
fields(includeDeprecated: true) {
|
||
name
|
||
description
|
||
args {
|
||
...InputValue
|
||
}
|
||
type {
|
||
...TypeRef
|
||
}
|
||
isDeprecated
|
||
deprecationReason
|
||
}
|
||
inputFields {
|
||
...InputValue
|
||
}
|
||
interfaces {
|
||
...TypeRef
|
||
}
|
||
enumValues(includeDeprecated: true) {
|
||
name
|
||
description
|
||
isDeprecated
|
||
deprecationReason
|
||
}
|
||
possibleTypes {
|
||
...TypeRef
|
||
}
|
||
}
|
||
fragment InputValue on __InputValue {
|
||
name
|
||
description
|
||
type { ...TypeRef }
|
||
defaultValue
|
||
}
|
||
fragment TypeRef on __Type {
|
||
kind
|
||
name
|
||
ofType {
|
||
kind
|
||
name
|
||
ofType {
|
||
kind
|
||
name
|
||
ofType {
|
||
kind
|
||
name
|
||
ofType {
|
||
kind
|
||
name
|
||
ofType {
|
||
kind
|
||
name
|
||
ofType {
|
||
kind
|
||
name
|
||
ofType {
|
||
kind
|
||
name
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
`
|