History, more test coverage improvements, and refactorings. (#3217)

Improvements overall to Nu. Also among the changes here, we can also be more confident towards incorporating `3041`. End to end tests for checking envs properly exported to externals is not added here (since it's in the other PR)

A few things added in this PR (probably forgetting some too)

* no writes happen to history during test runs.
* environment syncing end to end coverage added.
* clean up / refactorings few areas.
* testing API for finer control (can write tests passing more than one pipeline)
* can pass environment variables in tests that nu will inherit when running.

* No longer needed.

* no longer under a module. No need to use super.
This commit is contained in:
Andrés N. Robalino
2021-03-27 00:08:03 -05:00
committed by GitHub
parent b243b3ee1d
commit 8fc8fc89aa
31 changed files with 483 additions and 241 deletions

View File

@ -1,48 +1,66 @@
use super::nu_process::*;
use super::EnvironmentVariable;
use std::ffi::OsString;
use std::fmt;
#[derive(Default, Debug)]
pub struct Director {
pub cwd: Option<OsString>,
pub environment_vars: Vec<EnvironmentVariable>,
pub config: Option<OsString>,
pub pipeline: Option<String>,
pub pipeline: Option<Vec<String>>,
pub executable: Option<NuProcess>,
}
impl Director {
pub fn cococo(&self, arg: &str) -> Self {
let mut process = NuProcess::default();
let mut process = NuProcess {
environment_vars: self.environment_vars.clone(),
..Default::default()
};
process.args(&["--testbin", "cococo", arg]);
Director {
config: self.config.clone(),
executable: Some(process),
environment_vars: self.environment_vars.clone(),
..Default::default()
}
}
pub fn and_then(&mut self, commands: &str) -> &mut Self {
let commands = commands.to_string();
if let Some(ref mut pipeline) = self.pipeline {
pipeline.push(commands);
} else {
self.pipeline = Some(vec![commands]);
}
self
}
pub fn pipeline(&self, commands: &str) -> Self {
let mut director = Director {
pipeline: if commands.is_empty() {
None
} else {
Some(format!(
"
{}
exit",
commands
))
Some(vec![commands.to_string()])
},
..Default::default()
};
let mut process = NuProcess::default();
let mut process = NuProcess {
environment_vars: self.environment_vars.clone(),
..Default::default()
};
if let Some(working_directory) = &self.cwd {
process.cwd(working_directory);
}
process.arg("--skip-plugins");
process.arg("--no-history");
if let Some(config_file) = self.config.as_ref() {
process.args(&[
"--config-file",
@ -64,7 +82,7 @@ impl Director {
}
impl Executable for Director {
fn execute(&self) -> NuResult {
fn execute(&mut self) -> NuResult {
use std::io::Write;
use std::process::Stdio;
@ -81,13 +99,16 @@ impl Executable for Director {
Err(why) => panic!("Can't run test {}", why.to_string()),
};
if let Some(pipeline) = &self.pipeline {
process
.stdin
.as_mut()
.expect("couldn't open stdin")
.write_all(pipeline.as_bytes())
.expect("couldn't write to stdin");
if let Some(pipelines) = &self.pipeline {
let child = process.stdin.as_mut().expect("Failed to open stdin");
for pipeline in pipelines.iter() {
child
.write_all(format!("{}\n", pipeline).as_bytes())
.expect("Could not write to");
}
child.write_all(b"exit\n").expect("Could not write to");
}
process

View File

@ -1,12 +1,12 @@
use crate::fs::executable_path;
use std::collections::HashMap;
use super::EnvironmentVariable;
use crate::fs::{binaries as test_bins_path, executable_path};
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::path::Path;
use std::process::{Command, ExitStatus};
pub trait Executable {
fn execute(&self) -> NuResult;
fn execute(&mut self) -> NuResult;
}
#[derive(Clone, Debug)]
@ -36,7 +36,7 @@ pub struct NuError {
#[derive(Clone, Debug)]
pub struct NuProcess {
pub arguments: Vec<OsString>,
pub environment_vars: HashMap<String, Option<OsString>>,
pub environment_vars: Vec<EnvironmentVariable>,
pub cwd: Option<OsString>,
}
@ -56,7 +56,7 @@ impl Default for NuProcess {
fn default() -> Self {
Self {
arguments: vec![],
environment_vars: HashMap::default(),
environment_vars: Vec::default(),
cwd: None,
}
}
@ -90,6 +90,21 @@ impl NuProcess {
command.current_dir(cwd);
}
command.env_clear();
let paths = vec![test_bins_path()];
let paths_joined = match std::env::join_paths(paths.iter()) {
Ok(all) => all,
Err(_) => panic!("Couldn't join paths for PATH var."),
};
command.env("PATH", paths_joined);
for env_var in &self.environment_vars {
command.env(&env_var.name, &env_var.value);
}
for arg in &self.arguments {
command.arg(arg);
}

View File

@ -7,11 +7,27 @@ use std::path::{Path, PathBuf};
use std::str;
use tempfile::{tempdir, TempDir};
#[derive(Default, Clone, Debug)]
pub struct EnvironmentVariable {
pub name: String,
pub value: String,
}
impl EnvironmentVariable {
fn new(name: &str, value: &str) -> Self {
Self {
name: name.to_string(),
value: value.to_string(),
}
}
}
pub struct Playground<'a> {
root: TempDir,
tests: String,
cwd: PathBuf,
config: PathBuf,
environment_vars: Vec<EnvironmentVariable>,
dirs: &'a Dirs,
}
@ -71,6 +87,7 @@ impl<'a> Playground<'a> {
tests: topic.to_string(),
cwd: nuplay_dir,
config: fixtures.join("playground/config/default.toml"),
environment_vars: Vec::default(),
dirs: &Dirs::default(),
};
@ -108,6 +125,12 @@ impl<'a> Playground<'a> {
self
}
pub fn with_env(&mut self, name: &str, value: &str) -> &mut Self {
self.environment_vars
.push(EnvironmentVariable::new(name, value));
self
}
pub fn get_config(&self) -> &str {
self.config.to_str().expect("could not convert path.")
}
@ -116,6 +139,7 @@ impl<'a> Playground<'a> {
Director {
cwd: Some(self.dirs.test().into()),
config: Some(self.config.clone().into()),
environment_vars: self.environment_vars.clone(),
..Default::default()
}
}