Skip to content

Commit

Permalink
task: add initial API integration tests (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt authored Aug 27, 2020
1 parent f9f2f9e commit c1f7167
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ jobs:
run: ./scripts/build
- name: Run tests
run: ./scripts/check
env:
REINFER_CLI_TEST_ORG: ${{ secrets.REINFER_CLI_TEST_ORG }}
REINFER_CLI_TEST_TOKEN: ${{ secrets.REINFER_CLI_TEST_TOKEN }}
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# next

# v0.4.0

## Added
Expand Down
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ readme = "README.md"
authors = ["reinfer Ltd. <[email protected]>"]
license = "Apache-2.0"
edition = "2018"
autotests = false

[[bin]]
name = "re"
path = "src/main.rs"

[[test]]
name = "tests"

[dependencies]
chrono = "0.4.11"
colored = "1.9.3"
Expand All @@ -30,3 +34,6 @@ serde_json = "1.0.55"
structopt = { version = "0.3.15", default-features = false }

reinfer-client = { version = "0.4.0", path = "../api" }

[dev-dependencies]
uuid = { version = "0.8.1", features = ["v4"] }
104 changes: 104 additions & 0 deletions cli/tests/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use lazy_static::lazy_static;
use reinfer_client::User;
use std::{
env,
ffi::OsStr,
io::Write,
path::PathBuf,
process::{Command, Stdio},
};

pub struct TestCli {
cli_path: PathBuf,
}

impl TestCli {
pub fn get() -> &'static Self {
lazy_static! {
static ref TEST_CLI: TestCli = {
let cli_path = std::env::current_exe()
.ok()
.and_then(|p| Some(p.parent()?.parent()?.join("re")))
.expect("Could not resolve CLI executable from test executable");

TestCli { cli_path }
};
};

&TEST_CLI
}

pub fn organisation() -> &'static str {
lazy_static! {
static ref ORGANISATION: String = {
if let Ok(org) = env::var("REINFER_CLI_TEST_ORG") {
org
} else {
// For convenience default to username being the same as the organisation
let user_output = TestCli::get().run(&["get", "current-user", "--output=json"]);
let user: User = serde_json::from_str(user_output.trim()).unwrap();
user.username.0
}
};
};

&ORGANISATION
}

pub fn command(&self) -> Command {
let mut command = Command::new(&self.cli_path);

if let Some(endpoint) = env::var_os("REINFER_CLI_TEST_ENDPOINT") {
command.arg("--endpoint").arg(endpoint);
}

if let Some(token) = env::var_os("REINFER_CLI_TEST_TOKEN") {
command.arg("--token").arg(token);
}

command
}

pub fn run(&self, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> String {
self.output(self.command().args(args))
}

pub fn run_with_stdin(
&self,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
stdin: &[u8],
) -> String {
let mut process = self
.command()
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
process.stdin.as_mut().unwrap().write(stdin).unwrap();
let output = process.wait_with_output().unwrap();

if !output.status.success() {
panic!(
"failed to run command:\n{}",
String::from_utf8_lossy(&output.stderr)
);
}

String::from_utf8(output.stdout).unwrap()
}

pub fn output(&self, command: &mut Command) -> String {
let output = command.output().unwrap();

if !output.status.success() {
panic!(
"failed to run command:\n{}",
String::from_utf8_lossy(&output.stderr)
);
}

String::from_utf8(output.stdout).unwrap()
}
}
2 changes: 2 additions & 0 deletions cli/tests/samples/basic.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"comment":{"id":"1","timestamp":"2018-10-25T00:00:00Z","messages":[{"body":{"text":"Comment 1."}}]}}
{"comment":{"id":"2","timestamp":"2018-10-25T00:00:00Z","messages":[{"body":{"text":"Comment 2"}}]}}
20 changes: 20 additions & 0 deletions cli/tests/test_comments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::{TestCli, TestSource};

const SAMPLE_BASIC: &str = include_str!("./samples/basic.jsonl");

#[test]
fn test_upload_comments() {
let cli = TestCli::get();
let source = TestSource::new();

let output = cli.run_with_stdin(
&[
"create",
"comments",
"--allow-duplicates",
&format!("--source={}", source.identifier()),
],
SAMPLE_BASIC.as_bytes(),
);
assert!(output.is_empty());
}
116 changes: 116 additions & 0 deletions cli/tests/test_sources.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use crate::common::TestCli;
use reinfer_client::Source;
use uuid::Uuid;

pub struct TestSource {
full_name: String,
sep_index: usize,
}

impl TestSource {
pub fn new() -> Self {
let cli = TestCli::get();
let user = TestCli::organisation();
let full_name = format!("{}/test-source-{}", user, Uuid::new_v4());
let sep_index = user.len();

let output = cli.run(&["create", "source", &full_name]);
assert!(output.is_empty());

Self {
full_name,
sep_index,
}
}

pub fn new_args(args: &[&str]) -> Self {
let cli = TestCli::get();
let user = TestCli::organisation();
let full_name = format!("{}/test-source-{}", user, Uuid::new_v4());
let sep_index = user.len();

let output = cli.run(["create", "source", &full_name].iter().chain(args));
assert!(output.is_empty());

Self {
full_name,
sep_index,
}
}

pub fn identifier(&self) -> &str {
&self.full_name
}

pub fn owner(&self) -> &str {
&self.full_name[..self.sep_index]
}

pub fn name(&self) -> &str {
&self.full_name[self.sep_index + 1..]
}
}

impl Drop for TestSource {
fn drop(&mut self) {
let output = TestCli::get().run(&["delete", "source", self.identifier()]);
assert!(output.is_empty());
}
}

#[test]
fn test_test_source() {
let cli = TestCli::get();
let source = TestSource::new();

let identifier = source.identifier().to_owned();

let output = cli.run(&["get", "sources"]);
assert!(output.contains(&identifier));

drop(source);

// RAII TestSource; should automatically clean up the temporary source on drop.
let output = cli.run(&["get", "sources"]);
assert!(!output.contains(&identifier));
}

#[test]
fn test_list_multiple_sources() {
let cli = TestCli::get();
let source1 = TestSource::new();
let source2 = TestSource::new();

let output = cli.run(&["get", "sources"]);
assert!(output.contains(source1.identifier()));
assert!(output.contains(source2.identifier()));

let output = cli.run(&["get", "sources", source1.identifier()]);
assert!(output.contains(source1.identifier()));
assert!(!output.contains(source2.identifier()));

let output = cli.run(&["get", "sources", source2.identifier()]);
assert!(!output.contains(source1.identifier()));
assert!(output.contains(source2.identifier()));
}

#[test]
fn test_create_source_custom() {
let cli = TestCli::get();
let source = TestSource::new_args(&[
"--title=some title",
"--description=some description",
"--language=de",
"--should-translate=true",
]);

let output = cli.run(&["get", "sources", source.identifier(), "--output=json"]);
let source_info: Source = serde_json::from_str(&output).unwrap();

assert_eq!(&source_info.owner.0, source.owner());
assert_eq!(&source_info.name.0, source.name());
assert_eq!(source_info.title, "some title");
assert_eq!(source_info.description, "some description");
assert_eq!(source_info.language, "de");
assert_eq!(source_info.should_translate, true);
}
7 changes: 7 additions & 0 deletions cli/tests/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod common;

mod test_comments;
mod test_sources;

use common::TestCli;
use test_sources::TestSource;

0 comments on commit c1f7167

Please sign in to comment.