Skip to content
This repository was archived by the owner on Jun 3, 2021. It is now read-only.

Commit a1c37ee

Browse files
committed
refactor ExecutableMock
1 parent 3959160 commit a1c37ee

File tree

3 files changed

+72
-47
lines changed

3 files changed

+72
-47
lines changed

src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub mod utils;
2323
use crate::context::Context;
2424
use crate::recorder::{hole_recorder::run_against_tests, Recorder};
2525
use crate::test_checker::executable_mock;
26+
use crate::test_checker::executable_mock::ExecutableMock;
2627
use crate::test_spec::yaml::write_yaml;
2728
use crate::test_spec::Tests;
2829
use crate::tracer::stdio_redirecting::CaptureStderr;
@@ -80,7 +81,7 @@ pub fn run_main(context: &Context, args: &cli::Args) -> R<ExitCode> {
8081
Ok(match args {
8182
cli::Args::ExecutableMock {
8283
executable_mock_path,
83-
} => executable_mock::run(context, &executable_mock_path)?,
84+
} => ExecutableMock::run(context, &executable_mock_path)?,
8485
cli::Args::Scriptkeeper {
8586
script_path,
8687
record,
@@ -97,20 +98,19 @@ pub fn run_main(context: &Context, args: &cli::Args) -> R<ExitCode> {
9798
#[cfg(test)]
9899
mod run_main {
99100
use super::*;
100-
use executable_mock::create_mock_executable;
101+
use crate::test_checker::executable_mock;
101102
use test_utils::TempFile;
102103

103104
#[test]
104105
fn when_passed_executable_mock_flag_behaves_like_executable_mock() -> R<()> {
105106
let context = Context::new_mock();
106-
let executable_contents = create_mock_executable(
107+
let executable_mock = ExecutableMock::new(
107108
&context,
108109
executable_mock::Config {
109110
stdout: b"foo".to_vec(),
110111
exitcode: 0,
111112
},
112113
)?;
113-
let executable_mock = TempFile::write_temp_script(&executable_contents)?;
114114
run_main(
115115
&context,
116116
&cli::Args::ExecutableMock {

src/test_checker/executable_mock.rs

Lines changed: 61 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,74 @@
11
use crate::context::Context;
2+
use crate::tracer::tracee_memory;
3+
use crate::utils::short_temp_files::ShortTempFile;
24
use crate::{ExitCode, R};
35
use bincode::{deserialize, serialize};
6+
use libc::user_regs_struct;
7+
use nix::unistd::Pid;
48
use std::fs;
59
use std::io::Write;
610
use std::os::unix::ffi::OsStrExt;
7-
use std::path::Path;
11+
use std::path::{Path, PathBuf};
812

913
#[derive(Debug, Serialize, Deserialize)]
1014
pub struct Config {
1115
pub stdout: Vec<u8>,
1216
pub exitcode: i32,
1317
}
1418

15-
pub fn create_mock_executable(context: &Context, config: Config) -> R<Vec<u8>> {
16-
let mut result = b"#!".to_vec();
17-
result.append(
18-
&mut context
19-
.scriptkeeper_executable()
20-
.as_os_str()
21-
.as_bytes()
22-
.to_vec(),
23-
);
24-
result.append(&mut b" --executable-mock\n".to_vec());
25-
result.append(&mut serialize(&config)?);
26-
Ok(result)
19+
#[derive(Debug)]
20+
pub struct ExecutableMock {
21+
temp_file: ShortTempFile,
2722
}
2823

29-
pub fn run(context: &Context, executable_mock_path: &Path) -> R<ExitCode> {
30-
let config: Config = deserialize(&skip_hashbang_line(fs::read(executable_mock_path)?))?;
31-
context.stdout().write_all(&config.stdout)?;
32-
Ok(ExitCode(config.exitcode))
33-
}
24+
impl ExecutableMock {
25+
pub fn new(context: &Context, mock_config: Config) -> R<ExecutableMock> {
26+
let mut contents = b"#!".to_vec();
27+
contents.append(
28+
&mut context
29+
.scriptkeeper_executable()
30+
.as_os_str()
31+
.as_bytes()
32+
.to_vec(),
33+
);
34+
contents.append(&mut b" --executable-mock\n".to_vec());
35+
contents.append(&mut serialize(&mock_config)?);
36+
let temp_file = ShortTempFile::new(&contents)?;
37+
Ok(ExecutableMock { temp_file })
38+
}
3439

35-
fn skip_hashbang_line(input: Vec<u8>) -> Vec<u8> {
36-
input
37-
.clone()
38-
.into_iter()
39-
.skip_while(|char: &u8| *char != b'\n')
40-
.skip(1)
41-
.collect()
40+
pub fn path(&self) -> PathBuf {
41+
self.temp_file.path()
42+
}
43+
44+
pub fn poke_for_execve_syscall(
45+
pid: Pid,
46+
registers: &user_regs_struct,
47+
executable_mock_path: PathBuf,
48+
) -> R<()> {
49+
tracee_memory::poke_single_word_string(
50+
pid,
51+
registers.rdi,
52+
&executable_mock_path.as_os_str().as_bytes(),
53+
)
54+
}
55+
56+
pub fn run(context: &Context, executable_mock_path: &Path) -> R<ExitCode> {
57+
let config: Config = deserialize(&ExecutableMock::skip_hashbang_line(fs::read(
58+
executable_mock_path,
59+
)?))?;
60+
context.stdout().write_all(&config.stdout)?;
61+
Ok(ExitCode(config.exitcode))
62+
}
63+
64+
fn skip_hashbang_line(input: Vec<u8>) -> Vec<u8> {
65+
input
66+
.clone()
67+
.into_iter()
68+
.skip_while(|char: &u8| *char != b'\n')
69+
.skip(1)
70+
.collect()
71+
}
4272
}
4373

4474
#[cfg(test)]
@@ -48,28 +78,28 @@ mod test {
4878
use test_utils::TempFile;
4979

5080
#[test]
51-
fn renders_an_executable_that_outputs_the_given_stdout() -> R<()> {
52-
let mock_executable = TempFile::write_temp_script(&create_mock_executable(
81+
fn creates_an_executable_that_outputs_the_given_stdout() -> R<()> {
82+
let mock_executable = ExecutableMock::new(
5383
&Context::new_mock(),
5484
Config {
5585
stdout: b"foo".to_vec(),
5686
exitcode: 0,
5787
},
58-
)?)?;
88+
)?;
5989
let output = Command::new(mock_executable.path()).output()?;
6090
assert_eq!(output.stdout, b"foo");
6191
Ok(())
6292
}
6393

6494
#[test]
65-
fn renders_an_executable_that_exits_with_the_given_exitcode() -> R<()> {
66-
let mock_executable = TempFile::write_temp_script(&create_mock_executable(
95+
fn creates_an_executable_that_exits_with_the_given_exitcode() -> R<()> {
96+
let mock_executable = ExecutableMock::new(
6797
&Context::new_mock(),
6898
Config {
6999
stdout: b"foo".to_vec(),
70100
exitcode: 42,
71101
},
72-
)?)?;
102+
)?;
73103
let output = Command::new(mock_executable.path()).output()?;
74104
assert_eq!(output.status.code(), Some(42));
75105
Ok(())

src/test_checker/mod.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::tracer::{tracee_memory, SyscallMock};
99
use crate::utils::short_temp_files::ShortTempFile;
1010
use crate::R;
1111
use checker_result::CheckerResult;
12+
use executable_mock::ExecutableMock;
1213
use libc::{c_ulonglong, user_regs_struct};
1314
use nix::sys::ptrace;
1415
use nix::unistd::Pid;
@@ -22,7 +23,7 @@ pub struct TestChecker {
2223
pub test: Test,
2324
pub unmocked_commands: Vec<PathBuf>,
2425
pub result: CheckerResult,
25-
temporary_executables: Vec<ShortTempFile>,
26+
temporary_executables: Vec<ExecutableMock>,
2627
}
2728

2829
impl TestChecker {
@@ -62,11 +63,9 @@ impl TestChecker {
6263
TestChecker::allow_failing_scripts_to_continue()
6364
}
6465
};
65-
let mock_executable_contents =
66-
executable_mock::create_mock_executable(&self.context, mock_config)?;
67-
let temp_executable = ShortTempFile::new(&mock_executable_contents)?;
68-
let path = temp_executable.path();
69-
self.temporary_executables.push(temp_executable);
66+
let executable_mock = ExecutableMock::new(&self.context, mock_config)?;
67+
let path = executable_mock.path();
68+
self.temporary_executables.push(executable_mock);
7069
Ok(path)
7170
}
7271

@@ -102,15 +101,11 @@ impl SyscallMock for TestChecker {
102101
.iter()
103102
.any(|unmocked_command| test_spec::compare_executables(unmocked_command, &executable));
104103
if !is_unmocked_command {
105-
let mock_executable_path = self.handle_step(test_spec::Command {
104+
let executable_mock_path = self.handle_step(test_spec::Command {
106105
executable,
107106
arguments,
108107
})?;
109-
tracee_memory::poke_single_word_string(
110-
pid,
111-
registers.rdi,
112-
&mock_executable_path.as_os_str().as_bytes(),
113-
)?;
108+
ExecutableMock::poke_for_execve_syscall(pid, registers, executable_mock_path)?;
114109
}
115110
Ok(())
116111
}

0 commit comments

Comments
 (0)