mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
c32bc92f9c
Add end-to-end tests checking that every GraphQL endpoint is properly working and returning the expected result
351 lines
7.4 KiB
Python
Executable File
351 lines
7.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# This file is distributed under the MIT License. See LICENSE.md for details.
|
|
#
|
|
|
|
import io
|
|
import os
|
|
from random import randint
|
|
from subprocess import Popen
|
|
from time import sleep
|
|
from typing import Generator
|
|
from urllib.error import URLError
|
|
from urllib.request import urlopen
|
|
|
|
from gql import Client, gql
|
|
from gql.transport.requests import RequestsHTTPTransport
|
|
from pytest import Config, fixture, mark
|
|
|
|
|
|
def print_fd(fd: int):
|
|
os.lseek(fd, 0, io.SEEK_SET)
|
|
out_read = os.fdopen(fd, "r")
|
|
print(out_read.read())
|
|
|
|
|
|
def check_server_up(port: int):
|
|
for _ in range(10):
|
|
try:
|
|
req = urlopen(f"http://127.0.0.1:{port}/", timeout=1.0)
|
|
if req.code == 200:
|
|
return
|
|
sleep(1.0)
|
|
except (URLError, TimeoutError):
|
|
sleep(1.0)
|
|
raise ValueError()
|
|
|
|
|
|
@fixture
|
|
def client(pytestconfig: Config, request) -> Generator[Client, None, None]:
|
|
port = randint(20000, 65000)
|
|
root = pytestconfig.getoption("root")
|
|
|
|
out_fd = os.memfd_create("flask_debug", 0)
|
|
out = os.fdopen(out_fd, "w")
|
|
|
|
process = Popen(
|
|
[f"{root}/bin/revng", "daemon", "-p", str(port)], stdout=out, stderr=out, text=True
|
|
)
|
|
|
|
try:
|
|
check_server_up(port)
|
|
except ValueError as e:
|
|
print_fd(out_fd)
|
|
raise e
|
|
|
|
binary = pytestconfig.getoption("binary")
|
|
transport = RequestsHTTPTransport(f"http://127.0.0.1:{port}/graphql")
|
|
gql_client = Client(transport=transport, fetch_schema_from_transport=True)
|
|
|
|
upload_q = gql(
|
|
"""
|
|
mutation upload($file: Upload!) {
|
|
upload_file(file: $file, container: "input")
|
|
}
|
|
"""
|
|
)
|
|
with open(binary, "rb") as binary_file:
|
|
gql_client.execute(upload_q, variable_values={"file": binary_file}, upload_files=True)
|
|
yield gql_client
|
|
|
|
process.terminate()
|
|
process.wait()
|
|
|
|
if request.node.rep_call.failed:
|
|
print_fd(out_fd)
|
|
|
|
|
|
def test_info(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
info {
|
|
kinds {
|
|
name
|
|
rank
|
|
parent
|
|
}
|
|
ranks {
|
|
name
|
|
depth
|
|
parent
|
|
}
|
|
steps {
|
|
name
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
|
|
result = client.execute(q)
|
|
|
|
binary_kind = next(k for k in result["info"]["kinds"] if k["name"] == "Binary")
|
|
isolated_kind = next(k for k in result["info"]["kinds"] if k["name"] == "IsolatedRoot")
|
|
assert binary_kind["rank"] == "root"
|
|
assert binary_kind["parent"] is None
|
|
assert isolated_kind["rank"] == "root"
|
|
assert isolated_kind["parent"] == "Root"
|
|
|
|
root_rank = next(r for r in result["info"]["ranks"] if r["name"] == "root")
|
|
function_rank = next(r for r in result["info"]["ranks"] if r["name"] == "function")
|
|
assert root_rank["depth"] == 0
|
|
assert root_rank["parent"] is None
|
|
assert function_rank["depth"] == 1
|
|
assert function_rank["parent"] == "root"
|
|
|
|
step_names = [s["name"] for s in result["info"]["steps"]]
|
|
assert "begin" in step_names
|
|
|
|
|
|
def test_lift(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
root {
|
|
lift
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
|
|
result = client.execute(q)
|
|
|
|
assert result["root"]["lift"] is not None
|
|
|
|
|
|
@mark.xfail(raises=Exception)
|
|
def test_lift_ready_fail(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
root {
|
|
lift(only_if_ready: true)
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
client.execute(q)
|
|
|
|
|
|
@mark.xfail(raises=Exception)
|
|
def test_invalid_step(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
step(name: "this_step_does_not_exist") {
|
|
name
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
client.execute(q)
|
|
|
|
|
|
def test_valid_steps(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
begin: step(name: "begin") {
|
|
name
|
|
parent
|
|
}
|
|
lift: step(name: "Lift") {
|
|
name
|
|
parent
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
result = client.execute(q)
|
|
|
|
assert result["begin"]["name"] == "begin"
|
|
assert result["begin"]["parent"] is None
|
|
|
|
assert result["lift"]["name"] == "Lift"
|
|
assert result["lift"]["parent"] == "begin"
|
|
|
|
|
|
def test_begin_has_containers(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
step(name: "begin") {
|
|
containers {
|
|
name
|
|
mime
|
|
}
|
|
}
|
|
container(name: "input", step: "begin") {
|
|
name
|
|
mime
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
result = client.execute(q)
|
|
|
|
container_names = [c["name"] for c in result["step"]["containers"]]
|
|
input_container = next(c for c in result["step"]["containers"] if c["name"] == "input")
|
|
assert "module.ll" in container_names
|
|
assert "input" in container_names
|
|
assert input_container["mime"] is not None
|
|
assert input_container["mime"] == result["container"]["mime"]
|
|
|
|
|
|
def test_get_model(client):
|
|
client.execute(gql("{root{lift}}"))
|
|
|
|
q = gql(
|
|
"""
|
|
{
|
|
info {
|
|
model
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
result = client.execute(q)
|
|
|
|
assert result["info"]["model"] is not None
|
|
|
|
|
|
def test_targets_from_step(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
begin: step(name: "begin") {
|
|
containers {
|
|
name
|
|
targets {
|
|
serialized
|
|
kind
|
|
ready
|
|
exact
|
|
}
|
|
}
|
|
}
|
|
|
|
lift: step(name: "Lift") {
|
|
containers {
|
|
name
|
|
targets {
|
|
kind
|
|
ready
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
result = client.execute(q)
|
|
|
|
binary_target = next(
|
|
t
|
|
for t in next(c for c in result["begin"]["containers"] if c["name"] == "input")["targets"]
|
|
if t["kind"] == "Binary"
|
|
)
|
|
lift_target = next(
|
|
t
|
|
for t in next(c for c in result["lift"]["containers"] if c["name"] == "module.ll")[
|
|
"targets"
|
|
]
|
|
if t["kind"] == "Root"
|
|
)
|
|
assert binary_target["ready"]
|
|
assert binary_target["exact"]
|
|
assert not lift_target["ready"]
|
|
|
|
|
|
def test_targets(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
targets(pathspec: "") {
|
|
name
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
result = client.execute(q)
|
|
|
|
names = [s["name"] for s in result["targets"]]
|
|
assert "begin" in names
|
|
|
|
|
|
def test_produce(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
produce(step: "Lift", container: "module.ll", target_list: ":Root")
|
|
}
|
|
"""
|
|
)
|
|
result = client.execute(q)
|
|
|
|
assert "produce" in result, result["produce"] != ""
|
|
|
|
|
|
def test_produce_artifact(client):
|
|
q = gql(
|
|
"""
|
|
{
|
|
produce_artifacts(step: "Lift")
|
|
}
|
|
"""
|
|
)
|
|
result = client.execute(q)
|
|
|
|
assert "produce_artifacts" in result, result["produce_artifacts"] != ""
|
|
|
|
|
|
def test_function_endpoint(client):
|
|
client.execute(gql("{ root { lift } }"))
|
|
|
|
q = gql(
|
|
"""
|
|
{
|
|
container(name: "module.ll", step: "Isolate") {
|
|
targets {
|
|
serialized
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
result = client.execute(q)
|
|
|
|
first_function = next(t for t in result["container"]["targets"] if t["serialized"] != "")
|
|
q = gql(
|
|
"""
|
|
query function($param1: String!) {
|
|
function(param1: $param1) {
|
|
isolate
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
result = client.execute(q, {"param1": first_function["serialized"]})
|
|
|
|
assert result["function"]["isolate"] is not None
|