improved integration tests

14-integration-tests
plazmoid 3 years ago
parent 7735596bf0
commit 3e0c9ecd77
  1. 3
      .env
  2. 13
      Makefile
  3. 7
      bin/u_panel/src/main.rs
  4. 11
      bin/u_server/Cargo.toml
  5. 2
      bin/u_server/src/db.rs
  6. 13
      bin/u_server/src/handlers.rs
  7. 14
      bin/u_server/src/lib.rs
  8. 6
      bin/u_server/src/main.rs
  9. 2
      integration/.env
  10. 1
      integration/Cargo.toml
  11. 11
      integration/docker-compose.yml
  12. 2
      integration/docker_compose.py
  13. 52
      integration/tests/behaviour.rs
  14. 48
      integration/tests/helpers/client.rs
  15. 1
      integration/tests/helpers/mod.rs
  16. 3
      integration/tests/helpers/panel.rs
  17. 1
      integration/tests/tests.rs
  18. 1
      lib/u_lib/Cargo.toml
  19. 3
      lib/u_lib/src/api.rs
  20. 1
      lib/u_lib/src/lib.rs
  21. 3
      lib/u_lib/src/models/agent.rs
  22. 105
      lib/u_lib/src/utils.rs

@ -0,0 +1,3 @@
ADMIN_AUTH_TOKEN=464af63dbd241969baa1e94b2461d94d
POSTGRES_PASSWORD=12348756
DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@u_db/u_db

@ -1,15 +1,18 @@
.PHONY: build run clean
.PHONY: _pre_build debug release run clean
CARGO=./scripts/cargo_musl.sh
clean:
${CARGO} clean
build:
cd muslrust
_pre_build:
docker build -t unki/musllibs ./muslrust
cd -
${CARGO} build $@
debug: _pre_build
${CARGO} build
release: _pre_build
${CARGO} build --release
run: build
${CARGO} run

@ -1,5 +1,6 @@
use std::env;
use structopt::StructOpt;
use u_lib::{api::ClientHandler, models::JobMeta, UError};
use u_lib::{api::ClientHandler, models::JobMeta, utils::init_env, UError};
use uuid::Uuid;
const DELIM: &'static str = "*************\n";
@ -72,7 +73,8 @@ fn parse_uuid(src: &str) -> Result<Uuid, String> {
}
async fn process_cmd(cmd: Cmd) -> Result<(), UError> {
let cli_handler = ClientHandler::new(None).password("123qwe".to_string());
let token = env::var("ADMIN_AUTH_TOKEN").unwrap();
let cli_handler = ClientHandler::new(None).password(token);
match cmd {
Cmd::Agents(action) => match action {
LD::List { uid } => cli_handler
@ -123,6 +125,7 @@ async fn process_cmd(cmd: Cmd) -> Result<(), UError> {
#[tokio::main]
async fn main() -> Result<(), UError> {
init_env();
let args: Args = Args::from_args();
process_cmd(args.cmd).await
}

@ -5,7 +5,6 @@ name = "u_server"
version = "0.1.0"
[dependencies]
dotenv = "0.15.0"
env_logger = "0.7.1"
log = "0.4.11"
thiserror = "*"
@ -34,4 +33,12 @@ path = "../../lib/u_lib"
version = "*"
[dev-dependencies]
test-case = "1.1.0"
test-case = "1.1.0"
[lib]
name = "u_server_lib"
path = "src/lib.rs"
[[bin]]
name = "u_server"
path = "src/main.rs"

@ -1,5 +1,4 @@
use diesel::{pg::PgConnection, prelude::*, result::Error as DslError};
use dotenv::dotenv;
use once_cell::sync::OnceCell;
use std::{
env,
@ -21,7 +20,6 @@ static DB: OnceCell<Arc<Mutex<UDB>>> = OnceCell::new();
impl UDB {
pub fn lock_db() -> MutexGuard<'static, UDB> {
DB.get_or_init(|| {
dotenv().ok();
let db_path = env::var("DATABASE_URL").unwrap();
let conn = PgConnection::establish(&db_path).unwrap();
let instance = UDB { conn };

@ -4,7 +4,7 @@ use hyper::Body;
use serde::Serialize;
use u_lib::{
messaging::{AsMsg, BaseMessage},
models::{Agent, AssignedJob, ExecResult, JobMeta, JobState},
models::{Agent, AgentState, AssignedJob, ExecResult, JobMeta, JobState},
ULocalError,
};
use uuid::Uuid;
@ -76,9 +76,11 @@ impl Endpoints {
let result = UDB::lock_db().get_exact_jobs(uid, personal);
match result {
Ok(r) => {
let db = UDB::lock_db();
for j in r.iter() {
db.update_job_status(j.id, JobState::Running).ok();
if personal {
let db = UDB::lock_db();
for j in r.iter() {
db.update_job_status(j.id, JobState::Running).ok();
}
}
Ok(build_message(r))
}
@ -140,7 +142,8 @@ impl Endpoints {
failed.push(e.to_string())
}
}
ExecResult::Agent(a) => {
ExecResult::Agent(mut a) => {
a.state = AgentState::Active;
Self::add_agent(a).await?;
}
}

@ -12,14 +12,22 @@ extern crate mockall;
#[macro_use]
extern crate mockall_double;
// because of linking errors
extern crate openssl;
#[macro_use]
extern crate diesel;
//
use db::UDB;
#[double]
use handlers::Endpoints;
use serde::de::DeserializeOwned;
use std::env;
use u_lib::{
config::MASTER_PORT,
messaging::{AsMsg, BaseMessage},
models::*,
utils::init_env,
};
use uuid::Uuid;
@ -40,6 +48,7 @@ fn prefill_jobs() {
}
fn init() {
init_env();
env_logger::init();
prefill_jobs();
}
@ -99,11 +108,12 @@ fn make_filters() -> impl Filter<Extract = (impl Reply,), Error = Rejection> + C
.and(warp::path("report"))
.and(get_content::<Vec<ExecResult>>().and_then(Endpoints::report));
let auth_token = warp::header::exact("authorization", "Bearer 123qwe");
let auth_token = format!("Bearer {}", env::var("ADMIN_AUTH_TOKEN").unwrap()).into_boxed_str();
let authenticated = warp::header::exact("authorization", Box::leak(auth_token));
let agent_zone = get_jobs.clone().or(get_personal_jobs).or(report);
let auth_zone = auth_token.and(
let auth_zone = authenticated.and(
get_agents
.or(get_jobs)
.or(upload_jobs)

@ -1,8 +1,4 @@
extern crate openssl;
#[macro_use]
extern crate diesel;
use u_server::serve;
use u_server_lib::serve;
#[tokio::main]
async fn main() {

@ -1,2 +0,0 @@
PG_PASSWORD=12348756
DATABASE_URL=postgres://postgres:${PG_PASSWORD}@u_db/u_db

@ -13,6 +13,7 @@ env_logger = "0.8.3"
uuid = { version = "0.6.5", features = ["serde", "v4"] }
reqwest = { version = "0.11", features = ["json"] }
serde_json = "1.0"
serde = { version = "1.0.114", features = ["derive"] }
futures = "0.3.5"

@ -22,7 +22,7 @@ services:
environment:
RUST_LOG: warp
env_file:
- .env
- ../.env
healthcheck:
test: /bin/ss -tlpn | grep 63714
interval: 5s
@ -35,8 +35,8 @@ services:
- u_net
expose:
- '5432'
environment:
- POSTGRES_PASSWORD=${PG_PASSWORD}
env_file:
- ../.env
healthcheck:
test: /bin/ss -tlpn | grep 5432
interval: 5s
@ -71,6 +71,7 @@ services:
- u_net
volumes:
- ./:/tests/
- ../target/x86_64-unknown-linux-musl/release/u_panel:/u_panel
- ~/.cargo/registry:/root/.cargo/registry
working_dir:
/tests/
@ -80,4 +81,6 @@ services:
u_agent_2:
condition: service_started
u_server:
condition: service_healthy
condition: service_healthy
environment:
RUST_BACKTRACE: 1

@ -47,7 +47,7 @@ class Compose:
log(f'Running command "{cmd}" in container {container}')
result = docker([
'exec',
'-i',
'-ti',
container
] + cmd)
log('Ok')

@ -1,34 +1,38 @@
use futures::Future;
use reqwest::{Response, Result as RResult, Url};
use serde_json::{from_str, Value};
use crate::helpers::client::AgentClient;
use serde_json::json;
use uuid::Uuid;
const SERVER: &str = "u_server";
const PORT: &str = "63714";
type TestResult<R = ()> = Result<R, Box<dyn std::error::Error>>;
fn url<S: AsRef<str>>(url: S) -> Url {
Url::parse(&format!("http://{}:{}/{}", SERVER, PORT, url.as_ref())).unwrap()
}
async fn unpack(req: impl Future<Output = RResult<Response>>) -> Value {
let resp = req.await.unwrap().text().await.unwrap();
let resp: Value = from_str(&resp).unwrap();
resp.get("inner").unwrap().get(0).unwrap().clone()
}
async fn get<S: AsRef<str>>(_url: S) -> Value {
let req = reqwest::get(url(_url));
unpack(req).await
async fn register_agent() -> Uuid {
let cli = AgentClient::new();
let agent_uid = Uuid::new_v4();
let resp = cli.get(format!("get_agent_jobs/{}", agent_uid)).await;
let job_id = &resp["job_id"];
let resp = cli.get(format!("get_jobs/{}", job_id)).await;
assert_eq!(&resp["alias"], "agent_hello");
let agent_data = json! {
{"id": &agent_uid,"inner":[
{"Agent":
{"alias":null,
"hostname":"3b1030fa6324",
"id":&agent_uid,
"is_root":false,
"is_root_allowed":false,
"last_active":{"secs_since_epoch":1625271265,"nanos_since_epoch":92814921},
"platform":"x86_64-unknown-linux-gnu",
"regtime":{"secs_since_epoch":1625271265,"nanos_since_epoch":92814945},
"state":"New",
"token":null,
"username":"root"}
}]}
};
cli.post("report", &agent_data).await;
agent_uid
}
#[tokio::test]
async fn test_first_connection() -> TestResult {
let agent_uid = Uuid::new_v4();
let resp = get(format!("get_agent_jobs/{}", agent_uid)).await;
let job_id = &resp["job_id"];
let resp = get(format!("get_jobs/{}", job_id)).await;
assert_eq!(&resp["alias"], "agent_hello");
register_agent().await;
Ok(())
}

@ -0,0 +1,48 @@
use reqwest::{Client, RequestBuilder, Url};
use serde::Serialize;
use serde_json::{from_str, json, Value};
const SERVER: &str = "u_server";
const PORT: &str = "63714";
pub struct AgentClient {
client: Client,
base_url: Url,
}
impl AgentClient {
pub fn new() -> Self {
Self {
client: Client::new(),
base_url: Url::parse(&format!("http://{}:{}", SERVER, PORT)).unwrap(),
}
}
async fn process_request(&self, req: RequestBuilder, resp_needed: bool) -> Value {
let resp = req.send().await.unwrap();
if let Err(e) = resp.error_for_status_ref() {
panic!(
"Server responded with code {}\nError: {}",
e.status()
.map(|s| s.to_string())
.unwrap_or(String::from("<none>")),
e.to_string()
);
}
if !resp_needed {
return json!([]);
}
let resp: Value = from_str(&resp.text().await.unwrap()).unwrap();
resp.get("inner").unwrap().get(0).unwrap().clone()
}
pub async fn get<S: AsRef<str>>(&self, url: S) -> Value {
let req = self.client.get(self.base_url.join(url.as_ref()).unwrap());
self.process_request(req, true).await
}
pub async fn post<S: AsRef<str>, B: Serialize>(&self, url: S, body: &B) -> Value {
let req = self.client.post(self.base_url.join(url.as_ref()).unwrap());
self.process_request(req.json(body), false).await
}
}

@ -0,0 +1,3 @@
const BINARY: &str = "/u_panel";
pub struct Panel;

@ -1 +1,2 @@
mod behaviour;
mod helpers;

@ -7,6 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dotenv = "0.15.0"
serde = { version = "1.0.114", features = ["derive"] }
uuid = { version = "0.6.5", features = ["serde", "v4"] }
nix = "0.17"

@ -7,7 +7,6 @@ use crate::{
UError, UResult,
};
use reqwest::{Client, RequestBuilder, Url};
use std::{net::Ipv4Addr, str::FromStr};
use u_api_proc_macro::api_route;
use uuid::Uuid;
@ -59,7 +58,7 @@ impl ClientHandler {
#[api_route("POST")]
fn report<M: AsMsg>(&self, payload: &M) {}
//#/////////#// Admin area //#////////#//
//##########// Admin area //##########//
/// client listing
#[api_route("GET")]
fn get_agents(&self, url_param: Option<Uuid>) -> Vec<Agent> {}

@ -20,7 +20,6 @@ pub mod schema_exports {
#[macro_use]
extern crate lazy_static;
extern crate openssl;
#[macro_use]
extern crate diesel;

@ -79,10 +79,9 @@ impl Agent {
.await;
let decoder = |job_result: ExecResult| {
let assoc_job = unwrap_enum!(job_result, ExecResult::Assigned);
assoc_job.to_string_result().unwrap()
assoc_job.to_string_result().unwrap().trim().to_string()
};
#[cfg(unix)]
Self {
hostname: decoder(builder.pop("hostname")),
is_root: &decoder(builder.pop("is_root")) == "0",

@ -26,55 +26,6 @@ impl<T> OneOrMany<T> for Vec<T> {
}
}
pub fn daemonize() {
if getppid().as_raw() != 1 {
setsig(Signal::SIGTTOU, SigHandler::SigIgn);
setsig(Signal::SIGTTIN, SigHandler::SigIgn);
setsig(Signal::SIGTSTP, SigHandler::SigIgn);
}
for fd in 0..=2 {
match fdclose(fd) {
_ => (),
}
}
match chdir("/") {
_ => (),
};
match fork() {
Ok(ForkResult::Parent { .. }) => {
exit(0);
}
Ok(ForkResult::Child) => match setsid() {
_ => (),
},
Err(_) => exit(255),
}
}
pub fn setsig(sig: Signal, hnd: SigHandler) {
unsafe {
signal(sig, hnd).unwrap();
}
}
pub fn vec_to_string(v: &[u8]) -> String {
String::from_utf8_lossy(v).to_string()
}
pub fn opt_to_string<T: ToString>(item: Option<T>) -> String {
match item {
Some(s) => s.to_string(),
None => String::new(),
}
}
pub fn systime_to_string(time: &SystemTime) -> String {
DateTime::<Local>::from(*time)
.format("%d/%m/%Y %T")
.to_string()
}
pub struct TempFile {
path: PathBuf,
}
@ -159,3 +110,59 @@ macro_rules! unwrap_enum {
}
};
}
pub fn daemonize() {
if getppid().as_raw() != 1 {
setsig(Signal::SIGTTOU, SigHandler::SigIgn);
setsig(Signal::SIGTTIN, SigHandler::SigIgn);
setsig(Signal::SIGTSTP, SigHandler::SigIgn);
}
for fd in 0..=2 {
match fdclose(fd) {
_ => (),
}
}
match chdir("/") {
_ => (),
};
match fork() {
Ok(ForkResult::Parent { .. }) => {
exit(0);
}
Ok(ForkResult::Child) => match setsid() {
_ => (),
},
Err(_) => exit(255),
}
}
pub fn setsig(sig: Signal, hnd: SigHandler) {
unsafe {
signal(sig, hnd).unwrap();
}
}
pub fn vec_to_string(v: &[u8]) -> String {
String::from_utf8_lossy(v).to_string()
}
pub fn opt_to_string<T: ToString>(item: Option<T>) -> String {
match item {
Some(s) => s.to_string(),
None => String::new(),
}
}
pub fn systime_to_string(time: &SystemTime) -> String {
DateTime::<Local>::from(*time)
.format("%d/%m/%Y %T")
.to_string()
}
pub fn init_env() {
let envs = [".env"];
for envfile in &envs {
dotenv::from_filename(envfile).ok();
}
}

Loading…
Cancel
Save