test(es): Make execution tests faster (#4789)

This commit is contained in:
Donny/강동윤 2022-05-25 15:23:35 +09:00 committed by GitHub
parent f2d79b8495
commit 38a866a900
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 204 additions and 91 deletions

View File

@ -377,21 +377,30 @@ jobs:
run: |
jest -v && mocha --version
- name: Configure execution cache
shell: bash
run: |
mkdir -p .swc-exec-cache
echo "SWC_ECMA_TESTING_CACHE_DIR=$(pwd)/.swc-exec-cache" >> $GITHUB_ENV
- name: Cache execution results
uses: actions/cache@v3
with:
path: |
.swc-exec-cache
key: swc-exec-cache-${{ runner.os }}-${{ matrix.settings.crate }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
swc-exec-cache-${{ runner.os }}-${{ matrix.settings.crate }}
- name: Run cargo test
run: |
jest -v && mocha --version
cargo test --color always -p ${{ matrix.settings.crate }}
- name: Run cargo test (all features)
if: matrix.settings.crate == 'swc_ecma_parser' || matrix.settings.crate == 'swc_ecma_loader'
if: matrix.settings.crate == 'swc_ecma_parser' || matrix.settings.crate == 'swc_ecma_loader' || matrix.settings.crate == 'swc_ecma_transforms'
run: |
cargo test --color always -p ${{ matrix.settings.crate }} --all-features
- name: Run cargo test (swc_ecma_transforms)
if: matrix.settings.crate == 'swc_ecma_transforms'
run: |
cargo test --color always -p swc_ecma_transforms --all-features
- name: Install cargo-hack
uses: baptiste0928/cargo-install@v1.1.0
if: matrix.settings.os == 'ubuntu-latest' && matrix.settings.check

17
Cargo.lock generated
View File

@ -2991,6 +2991,7 @@ dependencies = [
"swc_ecma_minifier",
"swc_ecma_parser",
"swc_ecma_preset_env",
"swc_ecma_testing",
"swc_ecma_transforms",
"swc_ecma_transforms_base",
"swc_ecma_transforms_compat",
@ -3437,6 +3438,7 @@ dependencies = [
"swc_ecma_ast",
"swc_ecma_codegen",
"swc_ecma_parser",
"swc_ecma_testing",
"swc_ecma_transforms_base",
"swc_ecma_transforms_optimization",
"swc_ecma_utils",
@ -3529,6 +3531,20 @@ dependencies = [
"syn",
]
[[package]]
name = "swc_ecma_testing"
version = "0.1.0"
dependencies = [
"anyhow",
"hex",
"sha-1",
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"swc_ecma_codegen",
"testing",
]
[[package]]
name = "swc_ecma_transforms"
version = "0.154.0"
@ -3753,6 +3769,7 @@ dependencies = [
"swc_ecma_ast",
"swc_ecma_codegen",
"swc_ecma_parser",
"swc_ecma_testing",
"swc_ecma_transforms_base",
"swc_ecma_utils",
"swc_ecma_visit",

View File

@ -37,6 +37,7 @@ once_cell = "1.10.0"
parking_lot = "0.12.0"
pathdiff = "0.2.0"
regex = "1"
rustc-hash = "1.1.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sourcemap = "6"
@ -81,7 +82,6 @@ swc_plugin_runner = { version = "0.55.0", path = "../swc_plugin_runner", optiona
swc_timer = { version = "0.6.0", path = "../swc_timer" }
swc_visit = { version = "0.3.0", path = "../swc_visit" }
tracing = "0.1.32"
rustc-hash = "1.1.0"
[dependencies.napi-derive]
default-features = false
@ -102,6 +102,7 @@ rayon = "1.5.1"
swc_ecma_lints = { version = "0.41.0", path = "../swc_ecma_lints", features = [
"non_critical_lints",
] }
swc_ecma_testing = { version = "0.1.0", path = "../swc_ecma_testing" }
swc_node_base = { version = "0.5.0", path = "../swc_node_base" }
testing = { version = "0.20.0", path = "../testing" }
walkdir = "2"

View File

@ -1,7 +1,6 @@
use std::{
fs::{create_dir_all, rename},
path::{Component, Path, PathBuf},
process::Command,
sync::Arc,
};
@ -13,6 +12,7 @@ use swc::{
use swc_common::{errors::ColorConfig, SourceMap};
use swc_ecma_ast::EsVersion;
use swc_ecma_parser::{EsConfig, Syntax, TsConfig};
use swc_ecma_testing::{exec_node_js, JsExecOptions};
use testing::assert_eq;
use tracing::{span, Level};
@ -294,27 +294,14 @@ enum NodeModuleType {
}
fn stdout_of(code: &str, module_type: NodeModuleType) -> Result<String, Error> {
let module_type = match module_type {
NodeModuleType::CommonJs => "--input-type=commonjs",
NodeModuleType::Module => "--input-type=module",
};
let actual_output = Command::new("node")
.arg(module_type)
.arg("-e")
.arg(&code)
.output()
.context("failed to execute output of minifier")?;
let s = exec_node_js(
code,
JsExecOptions {
cache: true,
module: matches!(module_type, NodeModuleType::Module),
},
)?;
if !actual_output.status.success() {
bail!(
"failed to execute:\n{}\n{}\n{}",
code,
String::from_utf8_lossy(&actual_output.stdout),
String::from_utf8_lossy(&actual_output.stderr)
)
}
let s = String::from_utf8_lossy(&actual_output.stdout).to_string();
if s.trim().is_empty() {
bail!("empty stdout");
}

View File

@ -54,6 +54,7 @@ ansi_term = "0.12.1"
anyhow = "1"
criterion = "0.3.5"
pretty_assertions = "1.1"
swc_ecma_testing = { version = "0.1.0", path = "../swc_ecma_testing" }
swc_node_base = { version = "0.5.0", path = "../swc_node_base" }
testing = { version = "0.20.0", path = "../testing" }
walkdir = "2"

View File

@ -8,12 +8,11 @@ use std::{
fs::read_to_string,
panic::catch_unwind,
path::{Path, PathBuf},
process::Command,
time::Instant,
};
use ansi_term::Color;
use anyhow::{bail, Context, Error};
use anyhow::Error;
use once_cell::sync::Lazy;
use serde::Deserialize;
use swc_common::{
@ -36,6 +35,7 @@ use swc_ecma_parser::{
lexer::{input::SourceFileInput, Lexer},
EsConfig, Parser, Syntax,
};
use swc_ecma_testing::{exec_node_js, JsExecOptions};
use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver};
use swc_ecma_utils::drop_span;
use swc_ecma_visit::{FoldWith, Visit, VisitMut, VisitMutWith, VisitWith};
@ -256,27 +256,19 @@ fn run(
}
fn stdout_of(code: &str) -> Result<String, Error> {
let actual_output = Command::new("node")
.arg("-e")
.arg(&format!(
exec_node_js(
&format!(
"
{}
{}",
{}
{}",
include_str!("./terser_exec_base.js"),
code
))
.output()
.context("failed to execute output of minifier")?;
if !actual_output.status.success() {
bail!(
"failed to execute:\n{}\n{}",
String::from_utf8_lossy(&actual_output.stdout),
String::from_utf8_lossy(&actual_output.stderr)
)
}
Ok(String::from_utf8_lossy(&actual_output.stdout).to_string())
),
JsExecOptions {
cache: true,
module: false,
},
)
}
fn find_config(dir: &Path) -> String {

View File

@ -2,10 +2,8 @@
extern crate swc_node_base;
use std::process::Command;
use ansi_term::Color;
use anyhow::{bail, Context, Error};
use anyhow::Error;
use serde::Deserialize;
use swc_common::{
comments::SingleThreadedComments, errors::Handler, sync::Lrc, FileName, Mark, SourceMap,
@ -23,6 +21,7 @@ use swc_ecma_minifier::{
},
};
use swc_ecma_parser::{parse_file_as_module, EsConfig, Syntax};
use swc_ecma_testing::{exec_node_js, JsExecOptions};
use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver};
use swc_ecma_visit::{FoldWith, VisitMutWith};
use testing::DebugUsingDisplay;
@ -46,21 +45,13 @@ fn parse_compressor_config(cm: Lrc<SourceMap>, s: &str) -> (bool, CompressOption
}
fn stdout_of(code: &str) -> Result<String, Error> {
let actual_output = Command::new("node")
.arg("-e")
.arg(&code)
.output()
.context("failed to execute output of minifier")?;
if !actual_output.status.success() {
bail!(
"failed to execute:\n{}\n{}",
String::from_utf8_lossy(&actual_output.stdout),
String::from_utf8_lossy(&actual_output.stderr)
)
}
let stdout = String::from_utf8_lossy(&actual_output.stdout).to_string();
let stdout = exec_node_js(
code,
JsExecOptions {
cache: true,
module: false,
},
)?;
info!("Stdout: {}", stdout);

View File

@ -0,0 +1,22 @@
[package]
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
description = "Testing utilities for ecmascript"
documentation = "https://rustdoc.swc.rs/swc_ecma_testing/"
edition = "2021"
license = "Apache-2.0"
name = "swc_ecma_testing"
repository = "https://github.com/swc-project/swc.git"
version = "0.1.0"
[lib]
bench = false
[dependencies]
anyhow = "1"
hex = "0.4"
sha-1 = "0.10"
swc_atoms = { version = "0.2.11", path = "../swc_atoms" }
swc_common = { version = "0.18.7", path = "../swc_common" }
swc_ecma_ast = { version = "0.78.1", path = "../swc_ecma_ast" }
swc_ecma_codegen = { version = "0.108.5", path = "../swc_ecma_codegen" }
testing = { version = "0.20.0", path = "../testing" }

View File

@ -0,0 +1,98 @@
use std::{env, fs, path::PathBuf, process::Command};
use anyhow::{bail, Context, Result};
use sha1::{Digest, Sha1};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct JsExecOptions {
/// Cache the result of the execution.
///
/// If `true`, the result of the execution will be cached.
/// Cache is not removed and it will be reused if the source code is
/// identical.
///
/// Note that this cache is stored in cargo target directory and will be
/// removed by `cargo clean`.
///
/// You can change the cache directory name by setting the
/// `SWC_ECMA_TESTING_CACHE_DIR`
pub cache: bool,
/// If true, `--input-type=module` will be added.
pub module: bool,
}
fn cargo_manifest_dir() -> PathBuf {
env::var("CARGO_MANIFEST_DIR").unwrap().into()
}
fn cargo_cache_root() -> PathBuf {
env::var("SWC_ECMA_TESTING_CACHE_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| {
env::var("TARGET").map(PathBuf::from).unwrap_or_else(|_| {
let mut target_dir = cargo_manifest_dir();
target_dir.push("target");
target_dir
})
})
}
/// Executes `js_code` and capture thw output.
pub fn exec_node_js(js_code: &str, opts: JsExecOptions) -> Result<String> {
if opts.cache {
let hash = calc_hash(js_code);
let cache_dir = cargo_cache_root().join(".swc-node-exec-cache");
let cache_path = cache_dir.join(format!("{}.stdout", hash));
if let Ok(s) = fs::read_to_string(&cache_path) {
return Ok(s);
}
let output = exec_node_js(
js_code,
JsExecOptions {
cache: false,
..opts
},
)?;
fs::create_dir_all(&cache_dir).context("failed to create cache directory")?;
fs::write(&cache_path, output.as_bytes()).context("failed to write cache")?;
return Ok(output);
}
let mut c = Command::new("node");
if opts.module {
c.arg("--input-type=module");
} else {
c.arg("--input-type=commonjs");
}
let output = c
.arg("-e")
.arg(js_code)
.output()
.context("failed to execute output of minifier")?;
if !output.status.success() {
bail!(
"failed to execute:\n{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
)
}
String::from_utf8(output.stdout).context("output is not utf8")
}
fn calc_hash(s: &str) -> String {
let mut hasher = Sha1::default();
hasher.update(s.as_bytes());
let sum = hasher.finalize();
hex::encode(sum)
}

View File

@ -18,12 +18,13 @@ hex = "0.4.3"
serde = "1"
serde_json = "1"
sha-1 = "0.10"
swc_common = { version = "0.18.0", path = "../swc_common"}
swc_ecma_ast = {version = "0.78.0", path = "../swc_ecma_ast"}
swc_ecma_codegen = {version = "0.108.0", path = "../swc_ecma_codegen"}
swc_ecma_parser = {version = "0.104.0", path = "../swc_ecma_parser"}
swc_ecma_transforms_base = {version = "0.85.0", path = "../swc_ecma_transforms_base"}
swc_ecma_utils = {version = "0.85.0", path = "../swc_ecma_utils"}
swc_ecma_visit = {version = "0.64.0", path = "../swc_ecma_visit"}
swc_common = { version = "0.18.0", path = "../swc_common" }
swc_ecma_ast = { version = "0.78.0", path = "../swc_ecma_ast" }
swc_ecma_codegen = { version = "0.108.0", path = "../swc_ecma_codegen" }
swc_ecma_parser = { version = "0.104.0", path = "../swc_ecma_parser" }
swc_ecma_testing = { version = "0.1.0", path = "../swc_ecma_testing" }
swc_ecma_transforms_base = { version = "0.85.0", path = "../swc_ecma_transforms_base" }
swc_ecma_utils = { version = "0.85.0", path = "../swc_ecma_utils" }
swc_ecma_visit = { version = "0.64.0", path = "../swc_ecma_visit" }
tempfile = "3.1.0"
testing = {version = "0.20.0", path = "../testing"}
testing = { version = "0.20.0", path = "../testing" }

View File

@ -15,7 +15,7 @@ use std::{
};
use ansi_term::Color;
use anyhow::{bail, Context, Error};
use anyhow::Error;
use serde::de::DeserializeOwned;
use sha1::{Digest, Sha1};
use swc_common::{
@ -29,6 +29,7 @@ use swc_common::{
use swc_ecma_ast::{Pat, *};
use swc_ecma_codegen::Emitter;
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax};
use swc_ecma_testing::{exec_node_js, JsExecOptions};
use swc_ecma_transforms_base::{
fixer,
helpers::{inject_helpers, HELPERS},
@ -539,21 +540,13 @@ fn exec_with_node_test_runner(test_name: &str, src: &str) -> Result<(), ()> {
}
fn stdout_of(code: &str) -> Result<String, Error> {
let actual_output = Command::new("node")
.arg("-e")
.arg(&code)
.output()
.context("failed to execute output of minifier")?;
if !actual_output.status.success() {
bail!(
"failed to execute:\n{}\n{}",
String::from_utf8_lossy(&actual_output.stdout),
String::from_utf8_lossy(&actual_output.stderr)
)
}
Ok(String::from_utf8_lossy(&actual_output.stdout).to_string())
exec_node_js(
code,
JsExecOptions {
cache: true,
module: false,
},
)
}
/// Test transformation.

View File

@ -1,4 +1,5 @@
#![deny(warnings)]
#![allow(clippy::if_same_then_else)]
#![allow(clippy::needless_update)]
#![allow(clippy::redundant_clone)]
#![allow(clippy::while_let_on_iterator)]