Skip to content

Commit

Permalink
feat(config): add snm_test_utils as a dev dependency and refactor tests
Browse files Browse the repository at this point in the history
This commit introduces the `snm_test_utils` crate as a new development
dependency to facilitate testing within the `snm_config` and `snm_npmrc`
modules. As a result, several test cases have been refactored to utilize
this new utility, which simplifies the setup and teardown processes for
environment variables and test contexts.

The following changes were made:
- Updated Cargo.toml files to include `snm_test_utils`.
- Refactored test contexts to replace manual environment variable handling
  with the new `SnmTestContext` utility.
- Eliminated redundant code related to environment setup in tests to improve
  readability and maintainability.

These changes streamline the testing process and promote code reusability across
different tests, leading to an overall improvement in test quality.

BREAKING CHANGE: The removal of the manual environment variable management
code could affect other areas that relied on the previous test setup
strategy, necessitating an update to any related tests or modules.
  • Loading branch information
ityuany committed Feb 2, 2025
1 parent 0be5f45 commit 22e6b7e
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 165 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ members = [
"crates/snm_shim",
"crates/dev-tools",
"e2e",
"demo",
"demo", "crates/snm_test_utils",
]

resolver = "2"
Expand Down Expand Up @@ -63,6 +63,8 @@ backoff = { version = "0.4"}
## 进度条
indicatif = "0.17.8"

tempfile = "3.16.0"


which = "7.0.1"

Expand Down
4 changes: 4 additions & 0 deletions crates/snm_config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ snm_npmrc = { path = "../snm_npmrc" }
snm_utils = { path = "../snm_utils" }
test-context = { workspace = true }
tokio = { workspace = true, features = ["macros"] }


[dev-dependencies]
snm_test_utils = { path = "../snm_test_utils" }
125 changes: 54 additions & 71 deletions crates/snm_config/src/env_snm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ use serde::Deserialize;

#[derive(Debug, Default, Deserialize, PartialEq, Eq, Clone)]
pub struct EnvSnmConfig {
pub lang: Option<String>,

pub home_dir: Option<String>,

pub restricted_list: Option<String>,
Expand Down Expand Up @@ -35,83 +33,68 @@ impl EnvSnmConfig {

#[cfg(test)]
mod tests {
use std::env;

use test_context::{test_context, AsyncTestContext};
use snm_test_utils::SnmTestContext;
use test_context::test_context;

use super::*;

pub const SNM_PREFIX: &str = "ENV_SNM_CONFIG_SNM";

struct EnvTestContext {}

impl AsyncTestContext for EnvTestContext {
fn teardown(self) -> impl std::future::Future<Output = ()> + Send {
async {
env::remove_var(format!("{}_LANG", SNM_PREFIX));
env::remove_var(format!("{}_HOME_DIR", SNM_PREFIX));
env::remove_var(format!("{}_RESTRICTED_LIST", SNM_PREFIX));
env::remove_var(format!("{}_NODE_DIST_URL", SNM_PREFIX));
env::remove_var(format!("{}_NODE_GITHUB_RESOURCE_HOST", SNM_PREFIX));
env::remove_var(format!("{}_NODE_WHITE_LIST", SNM_PREFIX));
env::remove_var(format!("{}_DOWNLOAD_TIMEOUT_SECS", SNM_PREFIX));
env::remove_var(format!("{}_NPM_REGISTRY", SNM_PREFIX));
env::remove_var(format!("{}_STRICT", SNM_PREFIX));
}
}

fn setup() -> impl std::future::Future<Output = Self> + Send {
async {
let home = dirs::home_dir().unwrap();
env::set_var(format!("{}_LANG", SNM_PREFIX), "en");
env::set_var(
format!("{}_HOME_DIR", SNM_PREFIX),
home.to_string_lossy().to_string(),
);
env::set_var(format!("{}_RESTRICTED_LIST", SNM_PREFIX), "install");
env::set_var(
format!("{}_NODE_DIST_URL", SNM_PREFIX),
"https://nodejs.org/dist",
);
env::set_var(
format!("{}_NODE_GITHUB_RESOURCE_HOST", SNM_PREFIX),
"https://raw.githubusercontent.com",
);
env::set_var(format!("{}_NODE_WHITE_LIST", SNM_PREFIX), "1.1.0,1.2.0");
env::set_var(format!("{}_DOWNLOAD_TIMEOUT_SECS", SNM_PREFIX), "60");
env::set_var(
format!("{}_NPM_REGISTRY", SNM_PREFIX),
"https://test.npmjs.org",
);
env::set_var(format!("{}_STRICT", SNM_PREFIX), "true");
Self {}
}
}
}

#[test_context(EnvTestContext)]
#[test_context(SnmTestContext)]
#[tokio::test]
async fn should_parse_env_snm_config(_ctx: &mut EnvTestContext) -> anyhow::Result<()> {
let config = EnvSnmConfig::parse(SNM_PREFIX).unwrap();
let home = dirs::home_dir().unwrap();
assert_eq!(config.lang, Some("en".to_string()));
assert_eq!(config.home_dir, Some(home.to_string_lossy().to_string()));
assert_eq!(config.restricted_list, Some("install".to_string()));
assert_eq!(
config.node_dist_url,
Some("https://nodejs.org/dist".to_string())
);
async fn should_parse_env_snm_config(ctx: &mut SnmTestContext) -> anyhow::Result<()> {
let home_dir = ctx.temp_dir().to_string_lossy().to_string();
let restricted_list = "install";
let node_dist_url = "https://nodejs.org/dist";
let node_github_resource_host = "https://raw.githubusercontent.com";
let node_white_list = "1.1.0,1.2.0";
let download_timeout_secs = 60;
let npm_registry = "https://test.npmjs.org";
let strict = true;

let envs = [
(format!("{}_HOME_DIR", ctx.id()), home_dir.clone()),
(
format!("{}_RESTRICTED_LIST", ctx.id()),
restricted_list.to_string(),
),
(
format!("{}_NODE_DIST_URL", ctx.id()),
node_dist_url.to_string(),
),
(
format!("{}_NODE_GITHUB_RESOURCE_HOST", ctx.id()),
node_github_resource_host.to_string(),
),
(
format!("{}_NODE_WHITE_LIST", ctx.id()),
node_white_list.to_string(),
),
(
format!("{}_DOWNLOAD_TIMEOUT_SECS", ctx.id()),
download_timeout_secs.to_string(),
),
(
format!("{}_NPM_REGISTRY", ctx.id()),
npm_registry.to_string(),
),
(format!("{}_STRICT", ctx.id()), strict.to_string()),
];

ctx.vars(&envs);

let config = EnvSnmConfig::parse(ctx.id())?;

assert_eq!(config.home_dir, Some(home_dir.clone()));
assert_eq!(config.restricted_list, Some(restricted_list.to_string()));
assert_eq!(config.node_dist_url, Some(node_dist_url.to_string()));
assert_eq!(
config.node_github_resource_host,
Some("https://raw.githubusercontent.com".to_string())
);
assert_eq!(config.node_white_list, Some("1.1.0,1.2.0".to_string()));
assert_eq!(config.download_timeout_secs, Some(60));
assert_eq!(
config.npm_registry,
Some("https://test.npmjs.org".to_string())
Some(node_github_resource_host.to_string())
);
assert_eq!(config.strict, Some(true));
assert_eq!(config.node_white_list, Some(node_white_list.to_string()));
assert_eq!(config.download_timeout_secs, Some(download_timeout_secs));
assert_eq!(config.npm_registry, Some(npm_registry.to_string()));
assert_eq!(config.strict, Some(strict));

Ok(())
}
Expand Down
71 changes: 22 additions & 49 deletions crates/snm_config/src/snm_config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::{
env,
fmt::Display,
fs,
path::{Path, PathBuf},
Expand All @@ -10,8 +9,6 @@ use snm_npmrc::NpmrcReader;

use crate::env_snm_config::EnvSnmConfig;

const SNM_HOME_DIR_KEY: &str = "SNM_HOME_DIR";

#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Serialize)]
pub struct SnmConfig {
pub node_bin_dir: PathBuf,
Expand All @@ -23,7 +20,6 @@ pub struct SnmConfig {
pub download_timeout_secs: u64,
pub npm_registry: String,
pub workspace: PathBuf,
pub lang: String,
pub restricted_list: Vec<String>,
pub strict: bool,
}
Expand All @@ -38,26 +34,20 @@ impl Display for SnmConfig {
}

impl SnmConfig {
fn get_home_dir() -> anyhow::Result<PathBuf> {
match env::var(SNM_HOME_DIR_KEY) {
Ok(dir) => {
if dir.is_empty() {
return dirs::home_dir().ok_or(anyhow::anyhow!("Get home dir error"));
}
Ok(PathBuf::from(dir))
}
Err(_) => dirs::home_dir().ok_or(anyhow::anyhow!("Get home dir error")),
}
}

pub fn from<P: AsRef<Path>>(prefix: &str, workspace: P) -> anyhow::Result<Self> {
let config = EnvSnmConfig::parse(prefix)?;

let npm_registry = config
.npm_registry
.unwrap_or_else(|| NpmrcReader::from(&workspace).read_registry_with_default());

let base_dir = Self::get_home_dir()?.join(".snm");
let home_dir = dirs::home_dir().ok_or(anyhow::anyhow!("Get home dir error"))?;

let base_dir = config
.home_dir
.map(PathBuf::from)
.unwrap_or(home_dir)
.join(".snm");

let node_bin_dir = base_dir.join(String::from("node_bin"));
let download_dir = base_dir.join(String::from("downloads"));
Expand Down Expand Up @@ -92,7 +82,6 @@ impl SnmConfig {
workspace: workspace.as_ref().to_path_buf(),
node_bin_dir: node_bin_dir,
download_dir: download_dir,
lang: config.lang.unwrap_or("en".to_string()),
node_modules_dir: node_modules_dir,
node_dist_url: node_dist_url,
node_github_resource_host: node_github_resource_host,
Expand All @@ -106,43 +95,27 @@ impl SnmConfig {

#[cfg(test)]
mod tests {
use test_context::{test_context, AsyncTestContext};
use snm_test_utils::SnmTestContext;
use test_context::test_context;

use super::*;

struct EnvTestContext {}

impl AsyncTestContext for EnvTestContext {
fn teardown(self) -> impl std::future::Future<Output = ()> + Send {
async {
env::remove_var(SNM_HOME_DIR_KEY);
}
}

fn setup() -> impl std::future::Future<Output = Self> + Send {
async {
let home = dirs::home_dir().unwrap();
env::set_var(SNM_HOME_DIR_KEY, home.to_string_lossy().to_string());
Self {}
}
}
}

#[test_context(EnvTestContext)]
#[test_context(SnmTestContext)]
#[tokio::test]
async fn should_parse_snm_config(_ctx: &mut EnvTestContext) -> anyhow::Result<()> {
let config = SnmConfig::from("SNM1", ".")?;
async fn should_parse_snm_config(ctx: &mut SnmTestContext) -> anyhow::Result<()> {
ctx.vars(&[(
format!("{}_HOME_DIR", ctx.id()),
ctx.temp_dir().to_string_lossy().to_string(),
)]);

let home = dirs::home_dir().unwrap();
let config = SnmConfig::from(ctx.id(), ctx.temp_dir())?;

// let e = env::var(SNM_HOME_DIR_KEY)?;

// println!("config: {:?}", config);
// println!("e: {:?}", e);

assert_eq!(config.node_bin_dir, home.join(".snm/node_bin"));
assert_eq!(config.download_dir, home.join(".snm/downloads"));
assert_eq!(config.node_modules_dir, home.join(".snm/node_modules"));
assert_eq!(config.node_bin_dir, ctx.temp_dir().join(".snm/node_bin"));
assert_eq!(config.download_dir, ctx.temp_dir().join(".snm/downloads"));
assert_eq!(
config.node_modules_dir,
ctx.temp_dir().join(".snm/node_modules")
);
assert_eq!(config.node_dist_url, "https://nodejs.org/dist");
assert_eq!(
config.node_github_resource_host,
Expand Down
5 changes: 4 additions & 1 deletion crates/snm_npmrc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ config = { workspace = true }
dirs = { workspace = true }
test-context = { workspace = true }
tokio = { workspace = true, features = ["macros","test-util"] }
anyhow = { workspace = true }
anyhow = { workspace = true }

[dev-dependencies]
snm_test_utils = { path = "../snm_test_utils" }
48 changes: 7 additions & 41 deletions crates/snm_npmrc/tests/lib.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,8 @@
use std::{
collections::HashMap,
env::{self, current_dir},
path::PathBuf,
};
use std::{env::current_dir, path::PathBuf};

use snm_npmrc::NpmrcReader;
use test_context::{test_context, AsyncTestContext};

struct NpmrcTestContext {
// temp_dir: tempfile::TempDir,
env_vars: HashMap<String, String>,
}

impl AsyncTestContext for NpmrcTestContext {
async fn setup() -> Self {
// let temp_dir = tempfile::tempdir().unwrap();
Self {
// temp_dir,
env_vars: HashMap::new(),
}
}

async fn teardown(self) {
// 清理所有设置的环境变量
for (key, _) in self.env_vars {
env::remove_var(key);
}
}
}

impl NpmrcTestContext {
fn vars(&mut self, envs: &[(String, String)]) {
for (key, value) in envs {
self.env_vars.insert(key.to_string(), value.to_string());
env::set_var(key, value);
}
}
}
use snm_test_utils::SnmTestContext;
use test_context::test_context;

fn build_path(current: &PathBuf, parts: &[&str]) -> String {
parts
Expand All @@ -46,9 +12,9 @@ fn build_path(current: &PathBuf, parts: &[&str]) -> String {
.to_string()
}

#[test_context(NpmrcTestContext)]
#[test_context(SnmTestContext)]
#[tokio::test]
async fn should_read_custom_npm_registry(ctx: &mut NpmrcTestContext) -> anyhow::Result<()> {
async fn should_read_custom_npm_registry(ctx: &mut SnmTestContext) -> anyhow::Result<()> {
let current = current_dir()?;

let prefix_unix = build_path(&current, &["tests", "fixtures", "global", "unix"]);
Expand All @@ -70,9 +36,9 @@ async fn should_read_custom_npm_registry(ctx: &mut NpmrcTestContext) -> anyhow::
Ok(())
}

#[test_context(NpmrcTestContext)]
#[test_context(SnmTestContext)]
#[tokio::test]
async fn should_read_global_npm_cache(ctx: &mut NpmrcTestContext) -> anyhow::Result<()> {
async fn should_read_global_npm_cache(ctx: &mut SnmTestContext) -> anyhow::Result<()> {
let current = current_dir()?;

let prefix_unix = build_path(&current, &["tests", "fixtures", "global", "unix"]);
Expand Down
9 changes: 9 additions & 0 deletions crates/snm_test_utils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "snm_test_utils"
version = "0.1.0"
edition = "2024"

[dependencies]
tempfile = { workspace = true }
test-context = { workspace = true }
uuid = { workspace = true, features = ["v4"] }
Loading

0 comments on commit 22e6b7e

Please sign in to comment.