feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

+702
View File
@@ -0,0 +1,702 @@
//! Checked-source protocol/system acceptance through the actual LLVM runtime archive.
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[path = "dever-tests/tests/support/llvm.rs"]
mod llvm;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[path = "dever-tests/tests/support/llvm_managed.rs"]
mod llvm_managed;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[path = "dever-tests/tests/support/process.rs"]
mod process;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[path = "dever-tests/tests/support/temp.rs"]
mod temp;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
mod native {
use super::{llvm, llvm_managed};
use dever_backend_bridge::{Target, emit_object};
use dever_core::{check, source::SourceMap};
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::time::Duration;
const COMMON: &str = r#"some_h2(value: dever.http.Http2Limits) (answer: dever.http.Http2Limits?) { answer = value }
some_text(value: Text) (answer: Text?) { answer = value }
some_int(value: Int) (answer: Int?) { answer = value }
status(valid: true) (code: Int) { code = 207 }
status(valid: false) (code: Int) { code = 500 }
named(header: dever.http.Header, name: Text) (matches: Bool) { matches = header.name == name }
header_bytes(header: dever.http.Header, previous: List<Bytes>) (values: List<Bytes>) { values = append(previous, header.value) }
collect(event: dever.io.ReadEvent.Chunk(bytes), previous: Bytes) (next: Bytes) { next = dever.bytes.concat(previous, bytes) }
collect(event: dever.io.ReadEvent.Failed(message), previous: Bytes) (next: Bytes) { fail(dever.io.ReadEvent.Failed(message)) }
body(values: AsyncStream<dever.io.ReadEvent>) (bytes: Bytes) { bytes = reduce(collect, values, dever.bytes.from_text("")) }
request() (value: dever.http.Request) {
value = dever.http.Request { method = "POST"
target = "/echo?raw=1"
headers = [dever.http.header("Host", "fixture.test"), dever.http.header("X-Check", "one"), dever.http.header("X-Check", "two")]
body = dever.bytes.from_text("payload") }
}
route(request: dever.http.Request) (response: dever.http.Response) {
values = reduce(header_bytes, filter(named, request.headers, "x-check"), [])
valid = request.method == "POST" and request.target == "/echo?raw=1" and values == [dever.bytes.from_text("one"), dever.bytes.from_text("two")]
response = dever.http.Response { status = status(valid)
headers = [dever.http.header("X-Echo", "first"), dever.http.header("X-Echo", "second")]
body = request.body }
}
good(response: dever.http.Response) (valid: Bool) {
values = reduce(header_bytes, filter(named, response.headers, "x-echo"), [])
valid = response.status == 207 and response.body == dever.bytes.from_text("payload") and values == [dever.bytes.from_text("first"), dever.bytes.from_text("second")]
}
"#;
const HTTP_SEND: &str = r#"public main() (answer: Bool) {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
server = run(dever.http.serve(route, listener, dever.http.default_limits()))
response = dever.http.send("127.0.0.1", port, request(), dever.http.default_limits())
answer = good(response)
stop(server)
dever.net.close_listener(listener)
}
"#;
const HTTP_POOL: &str = r#"public main() (answer: Bool) {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
limits = dever.http.default_limits()
limits.http2 = HTTP2
server = run(SERVE)
client = dever.http.client(ORIGIN + int.to_text(port), TRUST, limits, dever.http.default_pool_limits())
first = dever.http.request(client, request())
first_good = good(first)
second = dever.http.open(client, request())
second_status = second.status
second_body = body(second.body)
input = channel(dever.io.ReadEvent, 2)
send(input, dever.io.ReadEvent.Chunk(dever.bytes.from_text("pay")))
send(input, dever.io.ReadEvent.Chunk(dever.bytes.from_text("load")))
close(input)
third_request = dever.http.StreamRequest { method = "POST"
target = "/echo?raw=1"
headers = request().headers
body = stream(input) }
third = dever.http.open_stream(client, third_request)
third_status = third.status
third_body = body(third.body)
dever.http.close_client(client)
stop(server)
dever.net.close_listener(listener)
answer = first_good and second_status == 207 and second_body == dever.bytes.from_text("payload") and third_status == 207 and third_body == dever.bytes.from_text("payload")
}
"#;
const LIVE: &str = r#"live(request: dever.http.Request, reply: dever.system.HttpReply) () {
LIVE_BODY
}
public main() (answer: Bool) {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
server = run(dever.http.serve_live(live, listener, dever.http.default_limits(), dever.http.default_live_limits()))
response = dever.http.send("127.0.0.1", port, request(), dever.http.default_limits())
answer = LIVE_CHECK
stop(server)
dever.net.close_listener(listener)
}
"#;
const HANDLER_FAILURE: &str = r#"type Failure { error Broken(message: Text, history: List<Text>) }
fault_route(request: dever.http.Request) (response: dever.http.Response) {
response = pick_route(request.target, request)
}
pick_route(target: "/fail", request: dever.http.Request) (response: dever.http.Response) {
dever.task.sleep(1)
fail(Failure.Broken("owned handler fault", ["original", "payload"]))
}
pick_route(target: other, request: dever.http.Request) (response: dever.http.Response) { response = route(request) }
public main() (answer: Bool) {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
server = run(dever.http.serve(fault_route, listener, dever.http.default_limits()))
failed_request = request()
failed_request.target = "/fail"
failed = dever.http.send("127.0.0.1", port, failed_request, dever.http.default_limits())
failed_status = failed.status
response = dever.http.send("127.0.0.1", port, request(), dever.http.default_limits())
answer = failed_status == 500 and good(response)
stop(server)
dever.net.close_listener(listener)
}
"#;
const CONTEXT: &str = r#"type Context { label: Text
tags: List<Text> }
first_text(value: Text) (text: Text) { text = value }
first_text(value: null) (text: Text) { text = "missing" }
context_route(request: dever.http.Request, context: Context) (response: dever.http.Response) {
dever.task.sleep(1)
response = dever.http.Response { status = 200
headers = []
body = dever.bytes.from_text(context.label + first_text(first(context.tags))) }
}
serve_context(listener: dever.system.Listener, context: Context) () {
dever.system.http_serve(context_route, listener, dever.http.default_limits(), context)
}
public main() (answer: Bool) {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
context = Context { label = "initial"
tags = ["-owned"] }
server = run(serve_context(listener, context))
context.label = "changed"
response = dever.http.send("127.0.0.1", port, request(), dever.http.default_limits())
answer = response.status == 200 and response.body == dever.bytes.from_text("initial-owned") and context.label == "changed"
stop(server)
dever.net.close_listener(listener)
}
"#;
const ERRORS: &str = r#"bad_date(value: dever.time.DateResult.Read(date)) (valid: Bool) recover("fixture expects invalid calendar") { valid = false }
bad_date(value: dever.time.DateResult.Failed(message)) (valid: Bool) recover("fixture expects invalid calendar") { valid = message == "invalid calendar Date" }
bad_time(value: dever.time.TimeResult.Read(time)) (valid: Bool) recover("fixture expects invalid clock") { valid = false }
bad_time(value: dever.time.TimeResult.Failed(message)) (valid: Bool) recover("fixture expects invalid clock") { valid = message == "invalid clock Time" }
bad_tls(value: dever.tls.ClientResult.Ready(config)) (valid: Bool) recover("fixture expects invalid CA") { valid = false }
bad_tls(value: dever.tls.ClientResult.Failed(message)) (valid: Bool) recover("fixture expects invalid CA") { valid = message == "TLS PEM contains no certificates" }
bad_token(value: dever.crypto.TokenResult.Ready(secret)) (valid: Bool) recover("fixture expects invalid token length") { valid = false }
bad_token(value: dever.crypto.TokenResult.Failed(message)) (valid: Bool) recover("fixture expects invalid token length") { valid = message == "token length must be between 16 and 1024 bytes" }
public main() (answer: Bool) {
answer = bad_date(result(dever.time.parse_date("2024-02-30"))) and bad_time(result(dever.time.parse_time("25:00:00"))) and bad_tls(result(dever.tls.client(dever.bytes.from_text("")))) and bad_token(result(dever.crypto.token(1)))
}
"#;
const WEBSOCKET: &str = r#"message(state: dever.websocket.ReceiveState.Read(value)) (message: dever.websocket.Message) { message = value }
message(state: dever.websocket.ReceiveState.End) (message: dever.websocket.Message) { message = dever.websocket.Message.Text("unexpected end") }
echo(request: dever.http.Request, reply: dever.system.HttpReply) () {
socket = dever.websocket.accept(reply, dever.websocket.default_limits())
first = message(dever.websocket.receive(socket))
dever.websocket.send(socket, first)
second = message(dever.websocket.receive(socket))
dever.websocket.send(socket, second)
dever.websocket.close(socket, 1000, "done")
}
public main() (answer: Bool) {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
server = run(WS_SERVE)
socket = WS_CONNECT
dever.websocket.send(socket, dever.websocket.Message.Text("你好"))
first = message(dever.websocket.receive(socket))
first_ok = first == dever.websocket.Message.Text("你好")
dever.websocket.send(socket, dever.websocket.Message.Binary(dever.bytes.from_ints([0, 255, 1])))
second = message(dever.websocket.receive(socket))
second_ok = second == dever.websocket.Message.Binary(dever.bytes.from_ints([0, 255, 1]))
close_state = dever.websocket.receive(socket)
ended = is_end(close_state)
stop(server)
dever.net.close_listener(listener)
answer = first_ok and second_ok and ended
}
is_end(state: dever.websocket.ReceiveState.End) (yes: Bool) { yes = true }
is_end(state: dever.websocket.ReceiveState.Read(value)) (yes: Bool) { yes = false }
"#;
const WEBSOCKET_STREAM: &str = r#"push_messages(request: dever.http.Request, reply: dever.system.HttpReply) () {
socket = dever.websocket.accept(reply, dever.websocket.default_limits())
dever.websocket.send(socket, dever.websocket.Message.Text("stream"))
dever.websocket.send(socket, dever.websocket.Message.Binary(dever.bytes.from_ints([0, 255])))
dever.websocket.send(socket, dever.websocket.Message.Ping(dever.bytes.from_ints([4])))
dever.websocket.send(socket, dever.websocket.Message.Pong(dever.bytes.from_ints([5])))
dever.websocket.close(socket, 1000, "done")
}
collect_message(event: dever.websocket.MessageEvent.Read(message), previous: List<dever.websocket.Message>) (next: List<dever.websocket.Message>) { next = append(previous, message) }
collect_message(event: dever.websocket.MessageEvent.Failed(message), previous: List<dever.websocket.Message>) (next: List<dever.websocket.Message>) { fail(dever.websocket.MessageEvent.Failed(message)) }
public main() (answer: Bool) {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
server = run(dever.http.serve_live(push_messages, listener, dever.http.default_limits(), dever.http.default_live_limits()))
socket = dever.websocket.connect("127.0.0.1", port, "/events", dever.websocket.default_limits())
values = dever.websocket.messages(socket)
alias = values
messages = reduce(collect_message, values, [])
remaining = reduce(collect_message, alias, [])
stop(server)
dever.net.close_listener(listener)
answer = messages == [dever.websocket.Message.Text("stream"), dever.websocket.Message.Binary(dever.bytes.from_ints([0, 255])), dever.websocket.Message.Ping(dever.bytes.from_ints([4])), dever.websocket.Message.Pong(dever.bytes.from_ints([5]))] and length(remaining) == 0
}
"#;
const TIME: &str = r#"public main() (answer: Bool) {
value = dever.time.parse_datetime("2024-02-29T01:02:03.004+01:00")
date = dever.time.parse_date("2024-02-29")
time = dever.time.parse_time("01:02:03.004")
delta = dever.time.duration(1000)
later = dever.time.add(value, delta)
previous = dever.time.subtract(later, delta)
difference = dever.time.difference(later, value)
now = dever.time.now()
clock = dever.time.unix_millis()
first = dever.time.monotonic_nanos()
second = dever.time.monotonic_nanos()
answer = dever.time.format_datetime(value) == "2024-02-29T00:02:03.004Z" and dever.time.format_date(date) == "2024-02-29" and dever.time.format_time(time) == "01:02:03.004" and previous == value and difference == delta and text.ends_with(dever.time.format_datetime(now), "Z") and clock > 0 and second >= first
}
"#;
const UUID: &str = r#"type Identifier { value: Uuid }
to_text(value: null) (text: Text) { text = "none" }
to_text(value: Uuid) (text: Text) { text = dever.system.uuid_to_text(value) }
public main() (answer: Bool) {
value = dever.system.uuid_parse("550E8400-E29B-41D4-A716-446655440000")
missing = dever.system.uuid_parse("invalid")
identifier = Identifier { value = "550e8400-e29b-41d4-a716-446655440000" }
expected = Identifier { value = "550E8400-E29B-41D4-A716-446655440000" }
answer = to_text(value) == "550e8400-e29b-41d4-a716-446655440000" and to_text(missing) == "none" and identifier.value == expected.value
}
"#;
const CRYPTO: &str = r#"public main() (answer: Bool) {
key = dever.crypto.token(16)
alias = key
bytes = dever.bytes.from_text("abc")
digest = dever.crypto.sha256(bytes)
first = dever.crypto.hmac_sha256(key, bytes)
second = dever.crypto.hmac_sha256(alias, bytes)
expected = dever.bytes.from_ints([186,120,22,191,143,1,207,234,65,65,64,222,93,174,34,35,176,3,97,163,150,23,122,156,180,16,255,97,242,0,21,173])
answer = digest == expected and dever.bytes.length(first) == 32 and dever.crypto.constant_time_eq(first, second) and not dever.crypto.constant_time_eq(first, dever.bytes.from_text("different"))
}
"#;
const PASSWORD: &str = r#"public main() (answer: Bool) {
key = dever.crypto.token(16)
wrong = dever.crypto.token(16)
encoded = blocking(dever.crypto.password_hash(key))
verified = blocking(dever.crypto.password_verify(key, encoded))
rejected = blocking(dever.crypto.password_verify(wrong, encoded))
answer = verified and not rejected and text.starts_with(encoded, "$argon2id$v=19$")
}
"#;
const OUTPUT: &str = r#"public main() (answer: Bool) {
dever.io.println("原生输出")
fields = {"component" = "fixture"
"quoted" = "line\n\"value\""}
dever.log.debug("ready", fields)
dever.log.info("ready", fields)
dever.log.warn("ready", fields)
dever.log.error("ready", fields)
answer = true
}
"#;
fn source(body: &str) -> String {
format!("{COMMON}\n{body}")
}
fn pool(http2: bool, tls: bool) -> String {
let serve = if tls {
"dever.http.serve_tls(route, listener, limits, dever.tls.server(CERT, KEY))"
} else {
"dever.http.serve(route, listener, limits)"
};
certificates(
&HTTP_POOL
.replace(
"HTTP2",
if http2 {
"some_h2(dever.http.default_http2_limits())"
} else {
"null"
},
)
.replace("SERVE", serve)
.replace(
"ORIGIN",
if tls {
"\"https://localhost:\""
} else {
"\"http://127.0.0.1:\""
},
)
.replace(
"TRUST",
if tls {
"dever.tls.client(ROOT)"
} else {
"dever.tls.system()"
},
),
)
}
fn certificates(body: &str) -> String {
body.replace(
"CERT",
&format!(
"dever.bytes.from_text({:?})",
include_str!("dever-tests/fixtures/tls/server.pem")
),
)
.replace(
"KEY",
&format!(
"dever.bytes.from_text({:?})",
include_str!("dever-tests/fixtures/tls/server-key.pem")
),
)
.replace(
"ROOT",
&format!(
"dever.bytes.from_text({:?})",
include_str!("dever-tests/fixtures/tls/root.pem")
),
)
}
fn live(body: &str, check: &str) -> String {
LIVE.replace("LIVE_BODY", body).replace("LIVE_CHECK", check)
}
fn websocket(tls: bool, url: bool) -> String {
let serve = if tls {
"dever.http.serve_live_tls(echo, listener, dever.http.default_limits(), dever.http.default_live_limits(), dever.tls.server(CERT, KEY))"
} else {
"dever.http.serve_live(echo, listener, dever.http.default_limits(), dever.http.default_live_limits())"
};
let connect = if tls {
"dever.websocket.open(\"wss://localhost:\" + int.to_text(port) + \"/echo\", dever.tls.client(ROOT), dever.websocket.default_limits())"
} else if url {
"dever.websocket.open(\"ws://127.0.0.1:\" + int.to_text(port) + \"/echo\", dever.tls.system(), dever.websocket.default_limits())"
} else {
"dever.websocket.connect(\"127.0.0.1\", port, \"/echo\", dever.websocket.default_limits())"
};
certificates(
&WEBSOCKET
.replace("WS_SERVE", serve)
.replace("WS_CONNECT", connect),
)
}
fn cases() -> Vec<(&'static str, String)> {
vec![
("http_send", HTTP_SEND.into()),
("http_pool", pool(false, false)),
("http2_pool", pool(true, false)),
("tls_pool", pool(false, true)),
("tls_http2_pool", pool(true, true)),
(
"live_respond",
live(
"dever.http.respond(reply, route(request))",
"good(response)",
),
),
(
"live_chunks",
live(
"dever.http.start(reply, 207, [])\n dever.http.write(reply, dever.bytes.from_text(\"pay\"))\n dever.task.sleep(1)\n dever.http.write(reply, dever.bytes.from_text(\"load\"))\n dever.http.finish(reply)",
"response.status == 207 and response.body == dever.bytes.from_text(\"payload\")",
),
),
(
"sse",
live(
"dever.sse.start(reply, [])\n dever.sse.send(reply, dever.sse.Event { event = \"update\"\n data = \"first\\nsecond\\n\"\n id = some_text(\"42\")\n retry_ms = some_int(123) })\n dever.http.finish(reply)",
"response.status == 200 and response.body == dever.bytes.from_text(\"event: update\\nid: 42\\nretry: 123\\ndata: first\\ndata: second\\ndata: \\n\\n\")",
),
),
("handler_failure", HANDLER_FAILURE.into()),
("context", CONTEXT.into()),
("ws_connect", websocket(false, false)),
("ws_open", websocket(false, true)),
("wss_open", websocket(true, true)),
("ws_messages", WEBSOCKET_STREAM.into()),
("time", TIME.into()),
("uuid", UUID.into()),
("crypto", CRYPTO.into()),
("password", PASSWORD.into()),
("output", OUTPUT.into()),
("errors", ERRORS.into()),
(
"arguments",
"public main() (answer: Bool) { answer = length(dever.process.arguments()) == 0 }"
.into(),
),
]
}
#[test]
fn protocol_system_sources_pass_the_existing_checker() {
for (name, body) in cases() {
let mut sources = SourceMap::default();
sources.add("main.dever", source(&body));
check(&sources).unwrap_or_else(|errors| {
panic!(
"{name}: {}",
errors
.iter()
.map(|error| error.render(&sources))
.collect::<String>()
)
});
}
}
#[test]
fn protocol_system_sources_emit_objects_for_six_targets() {
for (name, body) in cases() {
let ir = llvm::lower(&source(&body));
for target in [
Target::LinuxX86_64,
Target::LinuxAarch64,
Target::MacosX86_64,
Target::MacosAarch64,
Target::WindowsX86_64,
Target::WindowsAarch64,
] {
let object = emit_object(&ir, target)
.unwrap_or_else(|error| panic!("{name}/{target:?}: {error}"));
assert!(!object.is_empty(), "{name}/{target:?}");
}
}
}
fn run_case(name: &str) {
let body = cases()
.into_iter()
.find(|(candidate, _)| *candidate == name)
.unwrap()
.1;
llvm_managed::boolean(&source(&body));
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn single_http_request_preserves_headers_body_and_status() {
run_case("http_send");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn pooled_http_requests_and_stream_upload_download() {
run_case("http_pool");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn pooled_http2_requests_and_stream_upload_download() {
run_case("http2_pool");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn tls_verifies_local_certificate_and_streams_http() {
run_case("tls_pool");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn tls_negotiates_http2_and_streams_upload_download() {
run_case("tls_http2_pool");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn live_reply_respond_preserves_response() {
run_case("live_respond");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn live_reply_start_write_finish_preserves_chunks() {
run_case("live_chunks");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn sse_preserves_nullable_metadata_and_multiline_data() {
run_case("sse");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn owned_handler_failure_is_a_500_then_service_continues() {
run_case("handler_failure");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn static_suspending_handler_clones_owned_context_before_initial_suspend() {
run_case("context");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn websocket_connect_echoes_text_binary_and_natural_end() {
run_case("ws_connect");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn websocket_url_open_echoes_text_binary_and_natural_end() {
run_case("ws_open");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn secure_websocket_uses_local_tls_trust() {
run_case("wss_open");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback"]
fn websocket_message_stream_keeps_all_typed_variants_and_closes_aliases() {
run_case("ws_messages");
}
#[test]
#[ignore = "requires explicit runtime-abi archive"]
fn calendar_duration_and_clocks_keep_runtime_semantics() {
run_case("time");
}
#[test]
#[ignore = "requires explicit runtime-abi archive"]
fn uuid_parse_null_and_canonical_text() {
run_case("uuid");
}
#[test]
#[ignore = "requires explicit runtime-abi archive"]
fn crypto_secret_alias_sha256_hmac_and_comparison() {
run_case("crypto");
}
#[test]
#[ignore = "requires explicit runtime-abi archive"]
fn recoverable_system_errors_keep_the_original_messages() {
run_case("errors");
}
#[test]
#[ignore = "requires explicit runtime-abi archive and bounded crypto workers"]
fn password_hash_verify_uses_the_existing_blocking_boundary() {
llvm_managed::boolean_bounded(&source(PASSWORD), 2, Duration::from_secs(45), &[]);
}
#[test]
#[ignore = "requires explicit runtime-abi archive"]
fn process_arguments_exclude_executable_and_keep_unicode() {
llvm_managed::boolean_bounded(
"public main() (answer: Bool) { answer = dever.process.arguments() == [\"first\", \"中文\"] }",
64,
Duration::from_secs(5),
&["first", "中文"],
);
}
#[test]
#[ignore = "requires explicit runtime-abi archive"]
fn stdout_and_structured_logs_are_flushed_before_native_return() {
let output =
llvm_managed::boolean_bounded(&source(OUTPUT), 64, Duration::from_secs(5), &[]);
assert_eq!(
String::from_utf8(output.stdout).unwrap(),
"原生输出\n".repeat(65)
);
let record = |level: &str| {
format!(
"{{\"level\":\"{level}\",\"message\":\"ready\",\"fields\":{{\"component\":\"fixture\",\"quoted\":\"line\\n\\\"value\\\"\"}}}}\n"
)
};
let expected = ["debug", "info", "warn", "error"]
.map(record)
.concat()
.repeat(65);
assert_eq!(String::from_utf8(output.stderr).unwrap(), expected);
}
#[test]
#[ignore = "requires explicit runtime-abi archive and independent owned loopback peer"]
fn http_client_matches_independent_chunked_wire_and_repeated_headers() {
let listener = TcpListener::bind(("127.0.0.1", 0)).unwrap();
listener.set_nonblocking(true).unwrap();
let port = listener.local_addr().unwrap().port();
let peer = std::thread::spawn(move || {
let deadline = std::time::Instant::now() + Duration::from_secs(20);
for _ in 0..65 {
let mut socket = accept_before(&listener, deadline);
socket
.set_read_timeout(Some(Duration::from_secs(2)))
.unwrap();
socket
.set_write_timeout(Some(Duration::from_secs(2)))
.unwrap();
let expected =
b"POST /echo HTTP/1.1\r\nhost: example.test\r\ncontent-length: 1\r\n\r\nx";
let mut request = vec![0; expected.len()];
socket.read_exact(&mut request).unwrap();
assert_eq!(request, expected);
for chunk in [
b"HTTP/1.1 201 Created\r\nTransfer-Encoding: chunked\r\nSet-Cookie: a=1\r\n"
.as_slice(),
b"Set-Cookie: b=2\r\n\r\n1\r\na\r\n",
b"2\r\nbc\r\n0\r\n\r\n",
] {
socket.write_all(chunk).unwrap();
}
}
});
let source = source(&format!(
r#"public main() (answer: Bool) {{
request = dever.http.Request {{ method = "POST"
target = "/echo"
headers = [dever.http.header("Host", "example.test")]
body = dever.bytes.from_text("x") }}
response = dever.http.send("127.0.0.1", {port}, request, dever.http.default_limits())
values = reduce(header_bytes, filter(named, response.headers, "set-cookie"), [])
answer = response.status == 201 and response.body == dever.bytes.from_text("abc") and values == [dever.bytes.from_text("a=1"), dever.bytes.from_text("b=2")]
}}
"#
));
// Always join our peer, including when source lowering or execution fails.
let execution = std::panic::catch_unwind(|| llvm_managed::boolean(&source));
let peer_result = peer.join();
if let Err(failure) = execution {
std::panic::resume_unwind(failure);
}
peer_result.unwrap();
}
fn accept_before(listener: &TcpListener, deadline: std::time::Instant) -> TcpStream {
loop {
match listener.accept() {
Ok((socket, _)) => return socket,
Err(error)
if error.kind() == std::io::ErrorKind::WouldBlock
&& std::time::Instant::now() < deadline =>
{
std::thread::sleep(Duration::from_millis(2))
}
Err(error) => panic!("owned HTTP peer accept failed: {error}"),
}
}
}
#[test]
#[ignore = "requires explicit runtime-abi archive and owned loopback listener"]
fn invalid_server_limits_are_an_uncaptured_original_runtime_fault() {
llvm_managed::runtime_fault(
&source(
r#"public main() (answer: Bool) {
listener = dever.net.listen("127.0.0.1", 0)
limits = dever.http.default_limits()
limits.header_bytes = 1
dever.http.serve(route, listener, limits)
answer = false
}
"#,
),
"HTTP header_bytes must be at least 8192",
);
}
}