Skip to content

Commit c513ad7

Browse files
author
Aliaksei Bialiauski
authored
Merge pull request #192 from h1alexbel/77
feat(#77): fakehub stop via cli::sys
2 parents 59be07b + 6545435 commit c513ad7

File tree

11 files changed

+359
-4
lines changed

11 files changed

+359
-4
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ curl -X POST \
8282

8383
This should generate you an access token to fakehub [API](#supported-api).
8484

85+
To stop a server, run:
86+
87+
```bash
88+
fakehub stop
89+
```
90+
8591
### Supported API
8692

8793
We support the following list of "fake" versions of GitHub endpoints:

cli/src/args.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pub(crate) enum Command {
4040
/// Start the server
4141
#[command(about = "Start the server")]
4242
Start(StartArgs),
43+
#[command(about = "Stop the server")]
44+
Stop,
4345
}
4446

4547
#[derive(Parser, Debug)]

cli/src/main.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,21 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
// SOFTWARE.
2222
/*!
23-
Fakehub server and storage.
23+
Fakehub cli.
2424
*/
2525
use clap::Parser;
26-
use log::info;
26+
use log::{error, info};
27+
28+
/// System calls.
29+
pub mod sys;
2730

2831
use fakehub_server::Server;
2932

3033
use crate::args::{Args, Command};
34+
use crate::sys::current_port::current_port;
35+
use crate::sys::kill_unix::kill_unix;
36+
use fakehub_server::sys::instance_os::instance_os;
37+
use fakehub_server::sys::sys_info::sys_info;
3138
#[cfg(target_os = "windows")]
3239
use std::os::windows::process::CommandExt;
3340

@@ -64,14 +71,15 @@ async fn main() {
6471
// Detached windows process flag.
6572
command.creation_flags(0x00000008);
6673
match command.spawn() {
67-
Ok(_) => println!(
74+
Ok(_) => info!(
6875
"Server is running in detached mode on port {}",
6976
start.port
7077
),
7178
Err(err) => {
72-
panic!("Failed to spawn detached process: {}", err)
79+
error!("Failed to spawn detached process: {}", err)
7380
}
7481
}
82+
sys_info();
7583
return;
7684
}
7785
Err(err) => {
@@ -88,5 +96,29 @@ async fn main() {
8896
),
8997
}
9098
}
99+
// @todo #77:45min Implement kill_windows_port(id) for windows OS.
100+
// Currently, we don't support port killing on Windows. Check
101+
// <a href="https://github.com/h1alexbel/fakehub/pull/159">this</a> pull
102+
// request for more information.
103+
Command::Stop => {
104+
tracing_subscriber::fmt::init();
105+
info!("Stopping fakehub...");
106+
let port = current_port();
107+
let result = match instance_os().as_str() {
108+
"linux" | "macos" => kill_unix(port),
109+
_ => {
110+
error!(
111+
"Cannot stop server on port {}, since we probably don't support {} platform",
112+
port, instance_os()
113+
);
114+
false
115+
}
116+
};
117+
if result {
118+
info!("fakehub stopped");
119+
} else {
120+
error!("Cannot stop fakehub on port: {}", port);
121+
}
122+
}
91123
}
92124
}

cli/src/sys/current_port.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2024 Aliaksei Bialiauski
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included
13+
// in all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
/// Current fakehub port.
24+
pub fn current_port() -> usize {
25+
let output = std::process::Command::new("sh")
26+
.arg("-c")
27+
.arg("lsof -i -P -n | grep fakehub | awk '{print $9}' | cut -d ':' -f2")
28+
.output()
29+
.expect("failed to get fakehub current port");
30+
let port = String::from_utf8(output.stdout).expect("failed to parse stdout");
31+
let trimmed = port.trim();
32+
trimmed
33+
.parse::<usize>()
34+
.expect("failed to convert port to usize")
35+
}
36+
37+
#[cfg(test)]
38+
mod tests {
39+
#[cfg_attr(target_os = "windows", allow(unused_imports))]
40+
use crate::sys::current_port::current_port;
41+
#[cfg_attr(target_os = "windows", allow(unused_imports))]
42+
use anyhow::Result;
43+
#[cfg_attr(target_os = "windows", allow(unused_imports))]
44+
use assert_cmd::Command;
45+
#[cfg_attr(target_os = "windows", allow(unused_imports))]
46+
use defer::defer;
47+
48+
// @todo #77:35min Enable current_port_from_lsof test in rultor.
49+
// This test fails for some reason during Rultor build, because
50+
// of current_port() panics with: 'failed to convert port to usize:
51+
// ParseIntError { kind: Empty }'. It can be probably due to build in
52+
// Docker.
53+
#[ignore]
54+
#[cfg(not(target_os = "windows"))]
55+
#[test]
56+
#[allow(clippy::question_mark_used)]
57+
fn returns_current_port_from_lsof() -> Result<()> {
58+
let port = 3000;
59+
let _defer = defer(|| kill(3000));
60+
Command::cargo_bin("fakehub")?
61+
.arg("start")
62+
.arg("-d")
63+
.assert();
64+
assert_eq!(current_port(), port);
65+
Ok(())
66+
}
67+
68+
#[cfg_attr(target_os = "windows", allow(dead_code))]
69+
fn kill(port: usize) {
70+
std::process::Command::new("sh")
71+
.arg("-c")
72+
.arg(format!("killport {}", port))
73+
.output()
74+
.unwrap_or_else(|_| panic!("Failed to kill process on port {}", port));
75+
}
76+
}

cli/src/sys/kill_unix.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2024 Aliaksei Bialiauski
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included
13+
// in all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
use log::{error, info};
24+
25+
/// Kill UNIX port.
26+
// @todo #77:60min Investigate why lsof does not work in tests, while
27+
// killport tool kills port properly. Due to this problem, we can't create
28+
// integration test case with fakehub start -d -> fakehub stop. Don't forget
29+
// to remove this puzzle.
30+
pub fn kill_unix(port: usize) -> bool {
31+
let output = std::process::Command::new("sh")
32+
.arg("-c")
33+
.arg(format!("lsof -ti :{} | xargs kill", port))
34+
.output()
35+
.expect("failed to kill process");
36+
let result;
37+
if !output.status.success() {
38+
let stderr = String::from_utf8_lossy(&output.stderr);
39+
if stderr.is_empty() {
40+
error!("No process found running on port {}: unable to kill", port);
41+
result = false;
42+
} else {
43+
error!("Failed to kill process on port {}: {}", port, stderr);
44+
result = false;
45+
}
46+
} else {
47+
result = true;
48+
info!("Port {} killed", port);
49+
}
50+
result
51+
}

cli/src/sys/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2024 Aliaksei Bialiauski
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included
13+
// in all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
/// Current fakehub port.
23+
pub mod current_port;
24+
/// Kill UNIX port.
25+
pub mod kill_unix;

server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ chrono = "0.4.38"
5353
rand = "0.8.5"
5454
regex = "1.10.6"
5555
parameterized = "2.0.0"
56+
testing_logger = "0.1.1"
5657

5758
[features]
5859
mirror_release = []

server/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@ use crate::handlers::register_user::register_user;
3434
use crate::handlers::user::user;
3535
use crate::handlers::users::users;
3636
use crate::objects::fakehub::FakeHub;
37+
use crate::sys::sys_info::sys_info;
3738

3839
/// Handlers.
3940
pub mod handlers;
4041
/// Fakehub objects.
4142
pub mod objects;
4243
/// Reports.
4344
pub mod report;
45+
/// System information.
46+
pub mod sys;
4447
#[allow(unused_imports)]
4548
#[macro_use]
4649
extern crate hamcrest;
@@ -84,6 +87,7 @@ impl Server {
8487
/// Start a server.
8588
pub async fn start(self) -> Result<()> {
8689
let addr: String = format!("0.0.0.0:{}", self.port);
90+
sys_info();
8791
let started: io::Result<TcpListener> = TcpListener::bind(addr.clone()).await;
8892
match started {
8993
Ok(listener) => axum::serve(

server/src/sys/instance_os.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2024 Aliaksei Bialiauski
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included
13+
// in all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
/// Instance OS.
23+
pub fn instance_os() -> String {
24+
String::from(std::env::consts::OS)
25+
}
26+
27+
#[cfg(test)]
28+
mod tests {
29+
30+
use crate::sys::instance_os::instance_os;
31+
use anyhow::Result;
32+
use hamcrest::{equal_to, is, HamcrestMatcher};
33+
34+
#[cfg(target_os = "linux")]
35+
#[test]
36+
fn returns_os_on_linux() -> Result<()> {
37+
assert_that!(&instance_os(), is(equal_to("linux")));
38+
Ok(())
39+
}
40+
41+
#[cfg(target_os = "macos")]
42+
#[test]
43+
fn returns_os_on_mac() -> Result<()> {
44+
assert_that!(&instance_os(), is(equal_to("macos")));
45+
Ok(())
46+
}
47+
48+
#[cfg(target_os = "windows")]
49+
#[test]
50+
fn returns_os_on_windows() -> Result<()> {
51+
assert_that!(&instance_os(), is(equal_to("windows")));
52+
Ok(())
53+
}
54+
}

server/src/sys/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2024 Aliaksei Bialiauski
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included
13+
// in all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
/// Instance OS.
23+
pub mod instance_os;
24+
/// System information.
25+
pub mod sys_info;

0 commit comments

Comments
 (0)