Skip to content

Commit

Permalink
Merge pull request #3837 from wasmerio/registry-localhost
Browse files Browse the repository at this point in the history
Cleaned up the GraphQL endpoint logic and added tests
  • Loading branch information
Michael Bryan authored May 2, 2023
2 parents 1568bf9 + 7026859 commit 292780d
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 54 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ test-integration-cli: build-wasmer build-capi package-capi-headless package dist
# Before running this in the CI, we need to set up link.tar.gz and /cache/wasmer-[target].tar.gz
test-integration-cli-ci:
rustup target add wasm32-wasi
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner -p wasmer-integration-tests-cli -- --nocapture --test-threads=1
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner -p wasmer-integration-tests-cli -- --test-threads=1

test-integration-ios:
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner -p wasmer-integration-tests-ios
Expand Down
148 changes: 101 additions & 47 deletions lib/registry/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use url::Url;

pub static GLOBAL_CONFIG_DATABASE_FILE_NAME: &str = "wasmer.sqlite";

Expand Down Expand Up @@ -65,22 +66,37 @@ pub struct Registry {
}

pub fn format_graphql(registry: &str) -> String {
let mut registry = registry.to_string();
if registry.contains("wapm.dev") {
registry = "https://registry.wapm.dev/graphql".to_string();
} else if registry.contains("wapm.io") {
registry = "https://registry.wapm.io/graphql".to_string();
if let Ok(mut url) = Url::parse(registry) {
// Looks like we've got a valid URL. Let's try to use it as-is.
if url.has_host() {
if url.path() == "/" {
// make sure we convert http://registry.wapm.io/ to
// http://registry.wapm.io/graphql
url.set_path("/graphql");
}

return url.to_string();
}
}
if !registry.starts_with("https://") {
registry = format!("https://{registry}");

if !registry.contains("://") && !registry.contains('/') {
return endpoint_from_domain_name(registry);
}
if registry.ends_with("/graphql") {
registry
} else if registry.ends_with('/') {
format!("{}graphql", registry)
} else {
format!("{}/graphql", registry)

// looks like we've received something we can't deal with. Just pass it
// through as-is and hopefully it'll either work or the end user can figure
// it out
registry.to_string()
}

/// By convention, something like `"wapm.io"` should be converted to
/// `"https://registry.wapm.io/graphql"`.
fn endpoint_from_domain_name(domain_name: &str) -> String {
if domain_name.contains("localhost") {
return format!("http://{domain_name}/graphql");
}

format!("https://registry.{domain_name}/graphql")
}

fn test_if_registry_present(registry: &str) -> Result<(), String> {
Expand All @@ -95,40 +111,6 @@ pub enum UpdateRegistry {
LeaveAsIs,
}

#[test]
fn test_registries_switch_token() {
let mut registries = MultiRegistry::default();

registries.set_current_registry("https://registry.wapm.dev");
assert_eq!(
registries.get_current_registry(),
"https://registry.wapm.dev/graphql".to_string()
);
registries.set_login_token_for_registry(
"https://registry.wapm.io",
"token1",
UpdateRegistry::LeaveAsIs,
);
assert_eq!(
registries.get_current_registry(),
"https://registry.wapm.dev/graphql".to_string()
);
assert_eq!(
registries.get_login_token_for_registry(&registries.get_current_registry()),
None
);
registries.set_current_registry("https://registry.wapm.io");
assert_eq!(
registries.get_login_token_for_registry(&registries.get_current_registry()),
Some("token1".to_string())
);
registries.clear_current_registry_token();
assert_eq!(
registries.get_login_token_for_registry(&registries.get_current_registry()),
None
);
}

impl MultiRegistry {
/// Gets the current (active) registry URL
pub fn clear_current_registry_token(&mut self) {
Expand Down Expand Up @@ -264,3 +246,75 @@ impl WasmerConfig {
wasmer_dir.join(GLOBAL_CONFIG_DATABASE_FILE_NAME)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_registries_switch_token() {
let mut registries = MultiRegistry::default();

registries.set_current_registry("https://registry.wapm.dev");
assert_eq!(
registries.get_current_registry(),
"https://registry.wapm.dev/graphql".to_string()
);
registries.set_login_token_for_registry(
"https://registry.wapm.io",
"token1",
UpdateRegistry::LeaveAsIs,
);
assert_eq!(
registries.get_current_registry(),
"https://registry.wapm.dev/graphql".to_string()
);
assert_eq!(
registries.get_login_token_for_registry(&registries.get_current_registry()),
None
);
registries.set_current_registry("https://registry.wapm.io");
assert_eq!(
registries.get_login_token_for_registry(&registries.get_current_registry()),
Some("token1".to_string())
);
registries.clear_current_registry_token();
assert_eq!(
registries.get_login_token_for_registry(&registries.get_current_registry()),
None
);
}

#[test]
fn format_registry_urls() {
let inputs = [
// Domain names work
("wapm.io", "https://registry.wapm.io/graphql"),
("wapm.dev", "https://registry.wapm.dev/graphql"),
// Plain URLs
(
"https://registry.wapm.dev/graphql",
"https://registry.wapm.dev/graphql",
),
(
"https://registry.wapm.dev/something/else",
"https://registry.wapm.dev/something/else",
),
// We don't automatically prepend the domain name with
// "registry", but we will make sure "/" gets turned into "/graphql"
("https://wapm.dev/", "https://wapm.dev/graphql"),
("https://wapm.dev", "https://wapm.dev/graphql"),
// local development
(
"http://localhost:8000/graphql",
"http://localhost:8000/graphql",
),
("localhost:8000", "http://localhost:8000/graphql"),
];

for (input, expected) in inputs {
let url = format_graphql(input);
assert_eq!(url, expected);
}
}
}
66 changes: 60 additions & 6 deletions tests/integration/cli/tests/run_unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! Note that you will need to manually compile the `wasmer` CLI in release mode
//! before running any of these tests.
use std::{
io::Read,
io::{ErrorKind, Read},
process::Stdio,
time::{Duration, Instant},
};
Expand All @@ -15,13 +15,14 @@ use tempfile::TempDir;
use wasmer_integration_tests_cli::get_wasmer_path;

const RUST_LOG: &str = "info,wasmer_wasi::runners=debug,virtual_fs::trace_fs=trace";
const HTTP_GET_TIMEOUT: Duration = Duration::from_secs(5);

fn wasmer_run_unstable() -> std::process::Command {
let mut cmd = std::process::Command::new("cargo");
cmd.arg("run")
.arg("--quiet")
.arg("--package=wasmer-cli")
.arg("--features=singlepass")
.arg("--features=singlepass,cranelift")
.arg("--")
.arg("run-unstable");
cmd.env("RUST_LOG", RUST_LOG);
Expand Down Expand Up @@ -128,7 +129,10 @@ mod webc_on_disk {
let mut cmd = wasmer_run_unstable();
cmd.arg(format!("--addr=127.0.0.1:{port}"))
.arg(fixtures::static_server());
let child = JoinableChild::spawn(cmd);

// Let's run the command and wait until the server has started
let mut child = JoinableChild::spawn(cmd);
child.wait_for_stdout("WCGI Server running");

// make the request
let body = http_get(format!("http://127.0.0.1:{port}/")).unwrap();
Expand Down Expand Up @@ -162,7 +166,10 @@ mod webc_on_disk {
cmd.arg(format!("--addr=127.0.0.1:{port}"))
.arg(format!("--mapdir=/path/to:{}", temp.path().display()))
.arg(fixtures::static_server());
let child = JoinableChild::spawn(cmd);

// Let's run the command and wait until the server has started
let mut child = JoinableChild::spawn(cmd);
child.wait_for_stdout("WCGI Server running");

let body = http_get(format!("http://127.0.0.1:{port}/path/to/file.txt")).unwrap();
assert!(body.contains("Hello, World!"), "{body}");
Expand Down Expand Up @@ -371,6 +378,28 @@ impl JoinableChild {
JoinableChild(Some(child))
}

/// Keep reading lines from the child's stdout until a line containing the
/// desired text is found.
fn wait_for_stdout(&mut self, text: &str) -> String {
let stderr = self
.0
.as_mut()
.and_then(|child| child.stdout.as_mut())
.unwrap();

let mut all_output = String::new();

loop {
let line = read_line(stderr).unwrap();
let found = line.contains(text);
all_output.push_str(&line);

if found {
return all_output;
}
}
}

/// Kill the underlying [`std::process::Child`] and get an [`Assert`] we
/// can use to check it.
fn join(mut self) -> Assert {
Expand All @@ -380,6 +409,24 @@ impl JoinableChild {
}
}

fn read_line(reader: &mut dyn Read) -> Result<String, std::io::Error> {
let mut line = Vec::new();

while !line.ends_with(&[b'\n']) {
let mut buffer = [0_u8];
match reader.read_exact(&mut buffer) {
Ok(_) => {
line.push(buffer[0]);
}
Err(e) if e.kind() == ErrorKind::UnexpectedEof => break,
Err(e) => return Err(e),
}
}

let line = String::from_utf8(line).map_err(|e| std::io::Error::new(ErrorKind::Other, e))?;
Ok(line)
}

impl Drop for JoinableChild {
fn drop(&mut self) {
if let Some(mut child) = self.0.take() {
Expand All @@ -395,6 +442,14 @@ impl Drop for JoinableChild {
}
}

if let Some(mut stdout) = child.stdout.take() {
let mut buffer = String::new();
if stdout.read_to_string(&mut buffer).is_ok() {
eprintln!("---- STDOUT ----");
eprintln!("{buffer}");
}
}

if !std::thread::panicking() {
panic!("Child was dropped before being joined");
}
Expand All @@ -406,12 +461,11 @@ impl Drop for JoinableChild {
/// a timeout) if there are any connection errors.
fn http_get(url: impl IntoUrl) -> Result<String, reqwest::Error> {
let start = Instant::now();
let timeout = Duration::from_secs(5);
let url = url.into_url().unwrap();

let client = Client::new();

while start.elapsed() < timeout {
while start.elapsed() < HTTP_GET_TIMEOUT {
match client.get(url.clone()).send() {
Ok(response) => {
return response.error_for_status()?.text();
Expand Down

0 comments on commit 292780d

Please sign in to comment.