essential-rest-server 0.4.0

A REST server that wraps Essential server and exposes it's functionality
Documentation
use std::fmt::Display;

use essential_server_types::{CheckSolution, QueryStateReads};
use essential_types::{predicate::Predicate, PredicateAddress};
use test_utils::{empty::Empty, sign_contract_with_random_keypair, solution_with_predicate};
use tokio::process::Command;
use utils::{setup, TestServer};

mod utils;

#[tokio::test]
async fn test_readme_curl() {
    let readme = tokio::fs::read_to_string(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))
        .await
        .unwrap();

    let TestServer {
        url, shutdown, jh, ..
    } = setup().await;

    let port = url.port().unwrap();

    let commands: Vec<_> = readme
        .split("```bash")
        .skip(1)
        .filter_map(|s| s.split("```").next())
        .filter(|s| s.trim().starts_with("curl"))
        .map(|s| s.trim())
        .map(|s| {
            let mut s = s.to_string();
            s = s.replace(
                "Content-Type: application/json",
                "Content-Type:application/json",
            );
            s = s.replace('\'', "\"");

            s.split(' ')
                .map(|s| s.trim_start_matches('"').trim_end_matches('"'))
                .map(|s| s.trim())
                .filter(|s| !s.is_empty() && *s != "\\")
                .map(|s| s.to_string())
                .collect::<Vec<_>>()
        })
        .map(|mut s| {
            if let Some(a) = s.iter_mut().find(|s| s.starts_with("http://localhost:")) {
                if let Some(p) = a.split(':').nth(2).and_then(|s| s.split('/').next()) {
                    *a = a.replace(p, &port.to_string());
                }
            }
            s
        })
        .collect();

    for c in &commands {
        let mut command = Command::new("curl");
        let mut stream = false;
        for arg in c.iter().skip(1) {
            if arg == "-N" {
                stream = true;
            }
            command.arg(arg);
        }
        if stream {
            continue;
        }
        let output = command.output().await.unwrap();
        let s = String::from_utf8_lossy(&output.stdout);
        assert!(!s.contains("failed") && !s.contains("Failed"));
        assert!(output.status.success());
    }

    shutdown.send(()).unwrap();
    jh.await.unwrap().unwrap();
}

#[test]
#[ignore = "Just a utility, not really a test"]
fn create_readme_inputs() {
    let predicate = Predicate::empty();
    let signed = sign_contract_with_random_keypair(vec![predicate]);
    let address = PredicateAddress {
        contract: essential_hash::contract_addr::from_contract(&signed.contract),
        predicate: essential_hash::content_addr(&signed.contract[0]),
    };
    let solution = solution_with_predicate(address.clone());
    fn ser<T: serde::Serialize>(t: T) {
        println!("{}", serde_json::to_string(&t).unwrap());
    }
    fn p(s: impl Display) {
        println!("{}", s);
    }
    p("deploy contract");
    ser(&signed);

    p("get contract");
    p(&address.contract);

    p("get predicate");
    p(&address.contract);
    p(&address.predicate);

    p("submit solution");
    ser(&solution);

    p("query state");
    p(&address.contract);
    p(hex::encode_upper(vec![0]));

    p("solution outcome");
    p(essential_hash::content_addr(&solution));

    p("check solution");
    ser(&solution);

    p("check solution with contracts");
    ser(CheckSolution {
        solution: solution.clone(),
        contracts: vec![signed.contract.clone()],
    });

    p("query-state-reads");
    let query = QueryStateReads::from_solution(
        solution.clone(),
        0,
        &signed.contract[0],
        Default::default(),
    );
    ser(query);
}