summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.woodpecker.yaml52
-rw-r--r--Cargo.lock255
-rw-r--r--Cargo.toml7
-rw-r--r--src/cfg/config.rs10
-rw-r--r--src/lib.rs14
-rw-r--r--src/main.rs2
-rw-r--r--src/net/http_package.rs43
-rw-r--r--src/net/i2p_package.rs4
-rw-r--r--src/pkgtoolkit/pkgtools.rs2
-rw-r--r--tests/http_funcs.rs199
-rw-r--r--tests/i2p_functions.rs101
-rw-r--r--tests/pkgtoolkit_funcs.rs193
-rw-r--r--tests/secondary_funcs.rs29
-rw-r--r--tests/shared.rs22
14 files changed, 894 insertions, 39 deletions
diff --git a/.woodpecker.yaml b/.woodpecker.yaml
index 46a5e75..ea55210 100644
--- a/.woodpecker.yaml
+++ b/.woodpecker.yaml
@@ -1,16 +1,58 @@
# Define the sequence of steps for the CI pipeline
steps:
- full-test:
+ dependencies:
image: rust
- commands:
- - apt install openssl -y
+ environment:
+ RUST_BACKTRACE: 1
+ CARGO_TERM_COLOR: always
+ commands:
- rustup default stable
- rustup component add clippy rustfmt
- - cargo clippy --jobs 2 -- -D clippy::all
+ - apt install openssl -y
+ when:
+ branch: main
+ event: [ push, pull_request ]
+ build:
+ image: rust
+ environment:
+ RUST_BACKTRACE: 1
+ CARGO_TERM_COLOR: always
+ commands:
+ - cargo build --verbose --release --jobs 2
+ when:
+ branch: main
+ event: [ push, pull_request ]
+ clippy:
+ image: rust
+ environment:
+ RUST_BACKTRACE: 1
+ CARGO_TERM_COLOR: always
+ commands:
- cargo fmt --all -- --check
+ - cargo clippy --jobs 2 -- -D clippy::all
+ when:
+ branch: main
+ event: [ push, pull_request ]
+
+ build:
+ image: rust
+ environment:
+ RUST_BACKTRACE: 1
+ CARGO_TERM_COLOR: always
+ commands:
- cargo build --verbose --release --jobs 2
- - cargo test --verbose --jobs 2
when:
branch: main
event: [ push, pull_request ]
+
+ tests:
+ image: rust
+ environment:
+ RUST_BACKTRACE: 1
+ CARGO_TERM_COLOR: always
+ commands:
+ - cargo test --verbose --jobs 2
+ when:
+ branch: main
+ event: [ push, pull_request ] \ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 5716b77..bcfa62f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -30,6 +30,15 @@ dependencies = [
]
[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -86,6 +95,38 @@ dependencies = [
]
[[package]]
+name = "assert-json-diff"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "async-stream"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -255,6 +296,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
+name = "colored"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
name = "console"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -320,7 +370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
dependencies = [
"generic-array",
- "rand_core",
+ "rand_core 0.6.4",
"subtle",
"zeroize",
]
@@ -457,7 +507,7 @@ checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
dependencies = [
"curve25519-dalek",
"ed25519",
- "rand_core",
+ "rand_core 0.6.4",
"serde",
"sha2",
"subtle",
@@ -477,7 +527,7 @@ dependencies = [
"generic-array",
"group",
"pkcs8",
- "rand_core",
+ "rand_core 0.6.4",
"sec1",
"subtle",
"zeroize",
@@ -509,7 +559,7 @@ dependencies = [
"num-traits",
"p256",
"parking_lot",
- "rand_core",
+ "rand_core 0.6.4",
"sha1",
"sha2",
"siphasher",
@@ -537,6 +587,29 @@ dependencies = [
]
[[package]]
+name = "env_filter"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "jiff",
+ "log",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -575,7 +648,7 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
dependencies = [
- "rand_core",
+ "rand_core 0.6.4",
"subtle",
]
@@ -788,7 +861,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff",
- "rand_core",
+ "rand_core 0.6.4",
"subtle",
]
@@ -889,6 +962,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
name = "hyper"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -902,6 +981,7 @@ dependencies = [
"http",
"http-body",
"httparse",
+ "httpdate",
"itoa",
"pin-project-lite",
"pin-utils",
@@ -1131,6 +1211,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
+name = "jiff"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35"
+dependencies = [
+ "jiff-static",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde_core",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "js-sys"
version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1203,15 +1307,19 @@ dependencies = [
"cc",
"clap",
"emissary-core",
+ "env_logger",
"flate2",
"futures-util",
"indicatif",
"log",
+ "mockito",
"reqwest",
"serde",
"sqlite",
"tar",
+ "tempfile",
"tokio",
+ "tokio-test",
"toml",
"url",
"yosemite",
@@ -1251,6 +1359,31 @@ dependencies = [
]
[[package]]
+name = "mockito"
+version = "1.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e0603425789b4a70fcc4ac4f5a46a566c116ee3e2a6b768dc623f7719c611de"
+dependencies = [
+ "assert-json-diff",
+ "bytes",
+ "colored",
+ "futures-core",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "log",
+ "pin-project-lite",
+ "rand 0.9.2",
+ "regex",
+ "serde_json",
+ "serde_urlencoded",
+ "similar",
+ "tokio",
+]
+
+[[package]]
name = "native-tls"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1474,6 +1607,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
+name = "portable-atomic-util"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
name = "potential_utf"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1531,8 +1673,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
- "rand_chacha",
- "rand_core",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.3",
]
[[package]]
@@ -1542,7 +1694,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
- "rand_core",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.3",
]
[[package]]
@@ -1555,6 +1717,15 @@ dependencies = [
]
[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom 0.3.4",
+]
+
+[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1564,6 +1735,35 @@ dependencies = [
]
[[package]]
+name = "regex"
+version = "1.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
+
+[[package]]
name = "reqwest"
version = "0.12.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1854,7 +2054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"digest",
- "rand_core",
+ "rand_core 0.6.4",
]
[[package]]
@@ -1864,6 +2064,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
+name = "similar"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
+
+[[package]]
name = "siphasher"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2086,6 +2292,7 @@ dependencies = [
"bytes",
"libc",
"mio",
+ "parking_lot",
"pin-project-lite",
"socket2",
"tokio-macros",
@@ -2124,6 +2331,30 @@ dependencies = [
]
[[package]]
+name = "tokio-stream"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-test"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7"
+dependencies = [
+ "async-stream",
+ "bytes",
+ "futures-core",
+ "tokio",
+ "tokio-stream",
+]
+
+[[package]]
name = "tokio-util"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2677,7 +2908,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
dependencies = [
"curve25519-dalek",
- "rand_core",
+ "rand_core 0.6.4",
"zeroize",
]
@@ -2722,7 +2953,7 @@ checksum = "19cf621ae2b2d7e5d1e3827231fbf59ca4fb72b3589e36cdf648e820f1cf6e0d"
dependencies = [
"futures",
"nom",
- "rand",
+ "rand 0.8.5",
"thiserror",
"tokio",
"tracing",
diff --git a/Cargo.toml b/Cargo.toml
index 5cdd184..0422956 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,3 +26,10 @@ url = "2.5.7"
indicatif = "0.18.3"
futures-util = "0.3.31"
+[dev-dependencies]
+env_logger = "0.11.8"
+log = "0.4.28"
+mockito = "1.7.1"
+tempfile = "3.23.0"
+tokio-test = "0.4.4"
+
diff --git a/src/cfg/config.rs b/src/cfg/config.rs
index de9901f..213224f 100644
--- a/src/cfg/config.rs
+++ b/src/cfg/config.rs
@@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use std::fs;
use toml;
-#[derive(Debug, Deserialize, Serialize)]
+#[derive(Deserialize, Debug, Serialize, Clone)]
#[serde(rename_all = "lowercase")]
pub enum Loglevel {
Trace,
@@ -13,14 +13,14 @@ pub enum Loglevel {
}
/// `mesk.toml` configuration fields here
-#[derive(Deserialize, Debug, Serialize)]
+#[derive(Deserialize, Debug, Serialize, Clone)]
pub struct Config {
pub repo: Repo,
pub log: Log,
pub paths: Paths,
}
-#[derive(Deserialize, Debug, Serialize)]
+#[derive(Deserialize, Debug, Serialize, Clone)]
pub struct Log {
#[serde(rename = "log_file")]
pub log_file: String,
@@ -29,7 +29,7 @@ pub struct Log {
}
// Rename needed for editing mesk.toml file fields but dont touch code.
-#[derive(Deserialize, Debug, Serialize)]
+#[derive(Deserialize, Debug, Serialize, Clone)]
pub struct Repo {
#[serde(rename = "repo_url")]
pub repo_url: String,
@@ -43,7 +43,7 @@ pub struct Repo {
// pub arch = arch;
}
-#[derive(Deserialize, Debug, Serialize)]
+#[derive(Deserialize, Debug, Serialize, Clone)]
pub struct Paths {
#[serde(rename = "cache_dir")]
pub cache_dir: String,
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..ed6b426
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,14 @@
+
+pub mod cfg {
+ pub mod config;
+}
+
+pub mod net {
+ pub mod http_package;
+ pub mod i2p_package;
+}
+
+pub mod pkgtoolkit {
+ pub mod pkgtools;
+}
+
diff --git a/src/main.rs b/src/main.rs
index 2d36f20..4403c51 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,5 @@
mod cfg;
-mod net; // This should contain both i2p_package and http_package modules
+mod net;
mod pkgtoolkit;
use crate::cfg::config::Config;
diff --git a/src/net/http_package.rs b/src/net/http_package.rs
index ec7c318..ade4ee1 100644
--- a/src/net/http_package.rs
+++ b/src/net/http_package.rs
@@ -4,14 +4,15 @@ use futures_util::stream::TryStreamExt;
use indicatif::{ProgressBar, ProgressStyle};
use reqwest;
use serde::Deserialize;
-use std::collections::HashMap;
-use std::path::Path;
-use tokio::fs::File;
-use tokio::io::AsyncWriteExt;
+use std::{ collections::HashMap, path::Path };
+use tokio::{ fs::File, io::AsyncWriteExt};
+use std::fs::File as StdFile;
+use flate2::read::GzDecoder;
+use tar::Archive;
pub struct HTTPPackage {
- config: Config,
- index_packages: Option<HashMap<String, Package>>,
+ pub config: Config,
+ pub index_packages: Option<HashMap<String, Package>>,
}
#[derive(Deserialize, Debug)]
@@ -42,6 +43,8 @@ impl HTTPPackage {
let repo_url_str = &self.config.repo.repo_url;
let cache_dir = &self.config.paths.cache_dir;
+ log::debug!("Cache directory: {:?}", cache_dir);
+
let index_url = if repo_url_str.ends_with(".tar.gz") {
repo_url_str.clone()
} else {
@@ -86,6 +89,10 @@ impl HTTPPackage {
let mut stream = response.bytes_stream();
let file_path = Path::new(cache_dir).join("INDEX.tar.gz");
+ // Ensure cache_dir exists
+ tokio::fs::create_dir_all(cache_dir).await
+ .map_err(|e| format!("Failed to create cache dir: {}", e))?;
+
let mut file = File::create(&file_path).await?;
let mut downloaded: u64 = 0;
@@ -98,9 +105,16 @@ impl HTTPPackage {
pb.finish_with_message("INDEX.tar.gz download finished");
- // --- Извлечение и парсинг INDEX.toml ---
log::info!("Extracting INDEX.tar.gz to cache directory...");
- Package::extract_archive(&file_path.to_string_lossy())?; // Используем существующую функцию из pkgtoolkit
+ // Package::extract_archive(&file_path.to_string_lossy())?;
+
+
+ let archive_file = StdFile::open(&file_path)
+ .map_err(|e| format!("Failed to open archive: {}", e))?;
+ let gz_decoder = GzDecoder::new(archive_file);
+ let mut archive = Archive::new(gz_decoder);
+ archive.unpack(cache_dir)
+ .map_err(|e| format!("Failed to unpack archive: {}", e))?;
let index_toml_path = Path::new(cache_dir).join("INDEX.toml");
if !index_toml_path.exists() {
@@ -110,12 +124,13 @@ impl HTTPPackage {
}
let index_content = tokio::fs::read_to_string(&index_toml_path).await?;
- let index_data: IndexData = toml::from_str(&index_content)?;
+ log::debug!("Content of INDEX.toml:\n{}", index_content);
+
+ let index_data: IndexData = toml::from_str(&index_content)
+ .map_err(|e| format!("Failed to parse INDEX.toml: {}", e))?;
let mut package_map = HashMap::new();
for pkg in index_data.packages {
- // PKG_URL = /repo/package.mesk
- // FULL URL = "http://mesk.anthrill.i2p/i2p/repo/pkg.mesk"
let base_url = url::Url::parse(&self.config.repo.repo_url)?;
let full_url = base_url.join(&pkg.url)?;
let mut pkg_clone = pkg.clone();
@@ -131,7 +146,7 @@ impl HTTPPackage {
);
Ok(true)
- }
+}
/// An internal auxiliary function for downloading data and writing it to a file with a progress display.
///
@@ -212,7 +227,7 @@ impl HTTPPackage {
) -> Result<bool, Box<dyn std::error::Error>> {
let package_info = self.fetch_package_info(package_name)?;
let url = &package_info.url;
-
+
let client = reqwest::Client::new();
let file_name = Path::new(url)
@@ -223,6 +238,8 @@ impl HTTPPackage {
let cache_dir = &self.config.paths.cache_dir;
let file_path = Path::new(cache_dir).join(file_name);
+ tokio::fs::create_dir_all(&cache_dir).await?;
+
Self::download_file_with_progress(&client, url, &file_path, file_name).await?;
log::info!(
diff --git a/src/net/i2p_package.rs b/src/net/i2p_package.rs
index 751d561..2b847d6 100644
--- a/src/net/i2p_package.rs
+++ b/src/net/i2p_package.rs
@@ -19,8 +19,8 @@ use yosemite::Session;
use yosemite::SessionOptions;
pub struct I2PPackage {
- config: Config,
- index_packages: Option<HashMap<String, Package>>,
+ pub config: Config,
+ pub index_packages: Option<HashMap<String, Package>>,
}
#[derive(Deserialize, Debug)]
diff --git a/src/pkgtoolkit/pkgtools.rs b/src/pkgtoolkit/pkgtools.rs
index 9fe01c6..29145d3 100644
--- a/src/pkgtoolkit/pkgtools.rs
+++ b/src/pkgtoolkit/pkgtools.rs
@@ -77,7 +77,7 @@ struct Build {
}
impl Archs {
- fn as_str(&self) -> &'static str {
+ pub fn as_str(&self) -> &'static str {
match self {
Archs::X86_64 => "x86_64",
Archs::Aarch64 => "aarch64",
diff --git a/tests/http_funcs.rs b/tests/http_funcs.rs
new file mode 100644
index 0000000..efbaa53
--- /dev/null
+++ b/tests/http_funcs.rs
@@ -0,0 +1,199 @@
+use mesk::pkgtoolkit::pkgtools::{Package, Archs};
+use mesk::net::http_package::HTTPPackage;
+use std::fs;
+
+mod shared;
+use shared::create_test_config;
+
+use std::collections::HashMap;
+use tempfile::TempDir;
+use tokio;
+
+// Add these imports for logging
+use log::{info, debug, error};
+
+#[cfg(test)]
+mod http_package_tests {
+ use super::*;
+
+ // Helper function to initialize the logger for each test.
+ // This uses `call_once` to ensure it's only initialized once,
+ // even if called multiple times, preventing panics.
+ fn init_logger() {
+ let _ = env_logger::builder()
+ .is_test(true)
+ .try_init();
+ }
+
+ #[tokio::test]
+ async fn test_http_fetch_index_success() -> Result<(), Box<dyn std::error::Error>> {
+ init_logger(); // Initialize logger
+ info!("Starting test_http_fetch_index_success");
+
+ let mut server = mockito::Server::new_async().await;
+ let index_toml_content = r#"
+[[packages]]
+name = "test-pkg"
+version = "1.0.0"
+arch = "X86_64"
+url = "/repo/test-pkg.mesk"
+descr = "A test package from index"
+license = "MIT"
+"#;
+
+ let temp_dir = TempDir::new()?;
+ let index_toml_path = temp_dir.path().join("INDEX.toml");
+ fs::write(&index_toml_path, index_toml_content)?;
+ let archive_path = temp_dir.path().join("INDEX.tar.gz");
+
+ // Создаём архив
+ let file = fs::File::create(&archive_path)?;
+ let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
+ let mut tar_builder = tar::Builder::new(gz_encoder);
+ tar_builder.append_path_with_name(&index_toml_path, "INDEX.toml")?;
+ tar_builder.into_inner()?.finish()?;
+
+ let mock_body = fs::read(&archive_path)?;
+ let _mock = server
+ .mock("GET", "/INDEX.tar.gz")
+ .with_status(200)
+ .with_header("content-length", &mock_body.len().to_string())
+ .with_body(mock_body)
+ .create_async()
+ .await;
+
+ let temp_config_dir = TempDir::new()?;
+ let config = create_test_config(temp_config_dir.path().to_str().unwrap());
+
+ let mut config_with_mock_url = config.clone();
+ config_with_mock_url.repo.repo_url = server.url();
+
+ let mut http_pkg = HTTPPackage::new(config_with_mock_url);
+
+ debug!("Attempting to fetch index via HTTP");
+ let result = http_pkg.fetch_index_http().await;
+
+ info!("Checking if fetch_index_http result is OK");
+ assert!(result.is_ok(), "fetch_index_http should return Ok");
+
+ info!("Checking if fetch_index_http returned true");
+ assert_eq!(result.unwrap(), true, "fetch_index_http should indicate success");
+
+
+ info!("Checking if index_packages is populated");
+ assert!(http_pkg.index_packages.is_some(), "index_packages should not be None after successful fetch");
+
+ let packages = http_pkg.index_packages.as_ref().unwrap();
+ info!("Checking number of packages in the index");
+ assert_eq!(packages.len(), 1, "There should be exactly one package in the index");
+
+ info!("Checking if 'test-pkg' exists in the index");
+ assert!(packages.contains_key("test-pkg"), "The package 'test-pkg' should be present in the index");
+
+ let pkg_info = packages.get("test-pkg").unwrap();
+
+ info!("Checking if package URL is correctly formed");
+ assert!(pkg_info.url.starts_with(&server.url()), "Package URL should be prefixed with the server URL");
+
+ Ok(())
+ }
+
+ #[tokio::test]
+ async fn test_http_fetch_index_http_error() -> Result<(), Box<dyn std::error::Error>> {
+ init_logger();
+ info!("Starting test_http_fetch_index_http_error");
+
+ let mut server = mockito::Server::new_async().await;
+ let _mock = server
+ .mock("GET", "/INDEX.tar.gz")
+ .with_status(404) // Ошибка HTTP
+ .create_async()
+ .await;
+
+ let temp_config_dir = TempDir::new()?;
+ let config = create_test_config(temp_config_dir.path().to_str().unwrap());
+ let mut config_with_mock_url = config.clone();
+ config_with_mock_url.repo.repo_url = server.url();
+
+ let mut http_pkg = HTTPPackage::new(config_with_mock_url);
+
+ debug!("Attempting to fetch index with expected 404 error");
+ let result = http_pkg.fetch_index_http().await;
+
+ info!("Checking if fetch_index_http resulted in an error as expected");
+ assert!(result.is_err(), "fetch_index_http should return an Err for a 404 response");
+
+ let err_msg = result.unwrap_err().to_string();
+ info!("Verifying error message contains 'HTTP Error: 404'");
+ assert!(err_msg.contains("HTTP Error: 404"), "Error message should contain 'HTTP Error: 404', got: {}", err_msg);
+
+ Ok(())
+ }
+
+ #[tokio::test]
+ async fn test_http_fetch_package_info_success() -> Result<(), Box<dyn std::error::Error>> {
+ init_logger();
+ info!("Starting test_http_fetch_package_info_success");
+
+ let temp_config_dir = TempDir::new()?;
+ let config = create_test_config(temp_config_dir.path().to_str().unwrap());
+
+ let mut http_pkg = HTTPPackage::new(config);
+ let mut packages_map = HashMap::new();
+ let pkg = Package {
+ name: "test-pkg".to_string(),
+ version: "1.0.0".to_string(),
+ arch: Archs::X86_64,
+ descr: Some("Test".to_string()),
+ license: Some("MIT".to_string()),
+ url: "http://example.com/repo/test-pkg.mesk".to_string(),
+ };
+ packages_map.insert("test-pkg".to_string(), pkg);
+ http_pkg.index_packages = Some(packages_map);
+
+ debug!("Fetching package info for 'test-pkg'");
+ let pkg_info = http_pkg.fetch_package_info("test-pkg");
+
+ info!("Checking if fetch_package_info returned successfully");
+ assert!(pkg_info.is_ok(), "fetch_package_info should return Ok for an existing package");
+
+ info!("Checking the retrieved package name");
+ assert_eq!(pkg_info.unwrap().name, "test-pkg", "Retrieved package name should be 'test-pkg'");
+
+ Ok(())
+ }
+
+ #[tokio::test]
+ async fn test_http_fetch_package_info_not_found() -> Result<(), Box<dyn std::error::Error>> {
+ init_logger();
+ info!("Starting test_http_fetch_package_info_not_found");
+
+ let temp_config_dir = TempDir::new()?;
+ let config = create_test_config(temp_config_dir.path().to_str().unwrap());
+
+ let http_pkg = HTTPPackage::new(config.clone());
+ debug!("Attempting to fetch package info before index load");
+ let result = http_pkg.fetch_package_info("nonexistent-pkg");
+
+ info!("Checking if fetch_package_info failed due to unloaded index");
+ assert!(result.is_err(), "fetch_package_info should fail when index is not loaded");
+
+ let err_msg = result.unwrap_err().to_string();
+ info!("Verifying error message contains 'Index not loaded'");
+ assert!(err_msg.contains("Index not loaded"), "Error message should contain 'Index not loaded', got: {}", err_msg);
+
+ let mut http_pkg_empty_index = HTTPPackage::new(config);
+ http_pkg_empty_index.index_packages = Some(HashMap::new());
+ debug!("Attempting to fetch package info from an empty index");
+ let result_empty = http_pkg_empty_index.fetch_package_info("nonexistent-pkg");
+
+ info!("Checking if fetch_package_info failed due to missing package in index");
+ assert!(result_empty.is_err(), "fetch_package_info should fail for a package not in the index");
+
+ let err_msg_empty = result_empty.unwrap_err().to_string();
+ info!("Verifying error message contains 'not found in index'");
+ assert!(err_msg_empty.contains("not found in index"), "Error message should contain 'not found in index', got: {}", err_msg_empty);
+
+ Ok(())
+ }
+} \ No newline at end of file
diff --git a/tests/i2p_functions.rs b/tests/i2p_functions.rs
new file mode 100644
index 0000000..6b24d14
--- /dev/null
+++ b/tests/i2p_functions.rs
@@ -0,0 +1,101 @@
+use mesk::pkgtoolkit::pkgtools::{Package, Archs};
+use mesk::net::i2p_package::I2PPackage;
+
+mod shared;
+use shared::create_test_config;
+
+use std::collections::HashMap;
+use tempfile::TempDir;
+use tokio;
+
+#[cfg(test)]
+mod i2p_package_tests {
+ use super::*;
+
+ // fn parse_http_response(response_bytes: &[u8]) -> Result<(u16, &[u8]), Box<dyn std::error::Error>> { ... }
+ // #[test]
+ // fn test_parse_http_response() { ... }
+ /*
+ #[tokio::test]
+ async fn test_i2p_fetch_index_success() -> Result<(), Box<dyn std::error::Error>> {
+ let temp_config_dir = TempDir::new()?;
+ let config = create_test_config(temp_config_dir.path().to_str().unwrap());
+ let mut config_with_mock_url = config.clone();
+ config_with_mock_url.repo.repo_url = "http://dummy.i2p/repo";
+
+ let mut mock_session = MockSession::new();
+ mock_session
+ .expect_connect()
+ .with(eq("dummy.i2p"))
+ .returning(|_| {
+ // Возвращаем мок-поток, который возвращает байты архива
+ let index_toml_content = r#"[[packages]] name = "test-pkg" ... "#;
+ let mut archive_data = Vec::new();
+ // ... заполняем archive_data как в test_http_fetch_index_success ...
+ let response_body = format!(
+ "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
+ archive_data.len(),
+ std::str::from_utf8(&archive_data).unwrap()
+ ).into_bytes();
+ Ok(MockStream::new(response_body))
+ });
+
+
+ let mut i2p_pkg = I2PPackage::new_with_session(config_with_mock_url, Box::new(mock_session));
+
+ let result = i2p_pkg.fetch_index().await;
+
+ assert!(result.is_ok());
+
+ Ok(())
+ }
+ */
+ #[tokio::test]
+ async fn test_i2p_fetch_package_info_success() -> Result<(), Box<dyn std::error::Error>> {
+ let temp_config_dir = TempDir::new()?;
+ let config = create_test_config(temp_config_dir.path().to_str().unwrap());
+
+ let mut i2p_pkg = I2PPackage::new(config);
+ let mut packages_map = HashMap::new();
+ let pkg = Package {
+ name: "test-pkg".to_string(),
+ version: "1.0.0".to_string(),
+ arch: Archs::X86_64,
+ descr: Some("Test".to_string()),
+ license: Some("MIT".to_string()),
+ url: "http://example.i2p/repo/test-pkg.mesk".to_string(),
+ };
+ packages_map.insert("test-pkg".to_string(), pkg);
+ i2p_pkg.index_packages = Some(packages_map);
+
+ let pkg_info = i2p_pkg.fetch_package_info("test-pkg");
+
+ assert!(pkg_info.is_ok());
+ assert_eq!(pkg_info.unwrap().name, "test-pkg");
+
+ Ok(())
+ }
+
+ #[tokio::test]
+ async fn test_i2p_fetch_package_info_not_found() -> Result<(), Box<dyn std::error::Error>> {
+ let temp_config_dir = TempDir::new()?;
+ let config = create_test_config(temp_config_dir.path().to_str().unwrap());
+
+ let i2p_pkg = I2PPackage::new(config.clone()); // index_packages = None
+ let result = i2p_pkg.fetch_package_info("nonexistent-pkg");
+
+ assert!(result.is_err());
+ let err_msg = result.unwrap_err().to_string();
+ assert!(err_msg.contains("Index not loaded"));
+
+ let mut i2p_pkg_empty_index = I2PPackage::new(config);
+ i2p_pkg_empty_index.index_packages = Some(HashMap::new());
+ let result_empty = i2p_pkg_empty_index.fetch_package_info("nonexistent-pkg");
+
+ assert!(result_empty.is_err());
+ let err_msg_empty = result_empty.unwrap_err().to_string();
+ assert!(err_msg_empty.contains("not found in index"));
+
+ Ok(())
+ }
+}
diff --git a/tests/pkgtoolkit_funcs.rs b/tests/pkgtoolkit_funcs.rs
new file mode 100644
index 0000000..ae0c4d7
--- /dev/null
+++ b/tests/pkgtoolkit_funcs.rs
@@ -0,0 +1,193 @@
+use mesk::pkgtoolkit::pkgtools::{Package, Archs};
+
+
+mod shared;
+use shared::create_test_config;
+
+use tempfile::TempDir;
+use tokio;
+
+
+// Pkg toolkit tests
+#[cfg(test)]
+mod package_tests {
+ use super::*;
+ use std::fs;
+ use std::io::Write;
+
+ #[test]
+ fn test_archs_as_str() {
+ assert_eq!(Archs::X86_64.as_str(), "x86_64");
+ assert_eq!(Archs::Aarch64.as_str(), "aarch64");
+ assert_eq!(Archs::X86.as_str(), "x86");
+ assert_eq!(Archs::ArmV7.as_str(), "armv7");
+ assert_eq!(Archs::ArmV8.as_str(), "armv8");
+ }
+
+ #[tokio::test]
+ async fn test_extract_archive() -> Result<(), Box<dyn std::error::Error>> {
+ let temp_dir = TempDir::new()?;
+ let _config = create_test_config(temp_dir.path().to_str().unwrap());
+
+
+ let test_file_content = "test content";
+ let test_file_path = temp_dir.path().join("test_file.txt");
+ fs::write(&test_file_path, test_file_content)?;
+
+ let archive_path = temp_dir.path().join("test_archive.tar.gz");
+ let file = fs::File::create(&archive_path)?;
+ let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
+ let mut tar_builder = tar::Builder::new(gz_encoder);
+ tar_builder.append_path_with_name(&test_file_path, "extracted_test_file.txt")?;
+ tar_builder.into_inner()?.finish()?;
+
+
+ Package::extract_archive(archive_path.to_str().unwrap())?;
+
+
+ let extracted_file_path = temp_dir.path().join("extracted_test_file.txt");
+ assert!(extracted_file_path.exists());
+ let content = fs::read_to_string(extracted_file_path)?;
+ assert_eq!(content, test_file_content);
+
+ Ok(())
+ }
+
+
+ #[tokio::test]
+ async fn test_package_check_valid() -> Result<(), Box<dyn std::error::Error>> {
+ let temp_dir = TempDir::new()?;
+ let _config = create_test_config(temp_dir.path().to_str().unwrap());
+
+
+ let install_content = r#"
+[package]
+name = "test-pkg"
+version = "1.0.0"
+arch = "X86_64" # Используйте архитектуру хоста или измените для теста архитектуры
+descr = "A test package"
+license = "MIT"
+url = "/repo/test-pkg.mesk"
+
+[install]
+path = "/tmp/test_binary"
+user = "root"
+group = "root"
+mode = "755"
+"#;
+ let install_path = temp_dir.path().join("INSTALL");
+ let mut install_file = fs::File::create(&install_path)?;
+ install_file.write_all(install_content.as_bytes())?;
+
+
+ let archive_path = temp_dir.path().join("test_pkg_with_install.tar.gz");
+ let file = fs::File::create(&archive_path)?;
+ let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
+ let mut tar_builder = tar::Builder::new(gz_encoder);
+ tar_builder.append_path_with_name(&install_path, "INSTALL")?;
+ tar_builder.into_inner()?.finish()?;
+
+ let result = Package::check(archive_path.to_str().unwrap().to_string());
+
+ assert!(result.is_ok());
+ assert_eq!(result.unwrap(), true);
+
+ Ok(())
+ }
+
+
+ #[tokio::test]
+ async fn test_package_check_missing_install() -> Result<(), Box<dyn std::error::Error>> {
+ let temp_dir = TempDir::new()?;
+
+ let archive_path = temp_dir.path().join("test_pkg_without_install.tar.gz");
+ let file = fs::File::create(&archive_path)?;
+ let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
+ let mut tar_builder = tar::Builder::new(gz_encoder);
+ let dummy_path = temp_dir.path().join("dummy.txt");
+ fs::write(&dummy_path, "dummy")?;
+ tar_builder.append_path_with_name(&dummy_path, "dummy.txt")?;
+ tar_builder.into_inner()?.finish()?;
+
+ let result = Package::check(archive_path.to_str().unwrap().to_string());
+
+ assert!(result.is_err());
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), std::io::ErrorKind::NotFound);
+ assert!(err.to_string().contains("INSTALL file not found"));
+
+ Ok(())
+ }
+
+
+ #[tokio::test]
+ async fn test_package_check_empty_install() -> Result<(), Box<dyn std::error::Error>> {
+ let temp_dir = TempDir::new()?;
+
+ let install_path = temp_dir.path().join("INSTALL");
+ fs::write(&install_path, "")?;
+ let archive_path = temp_dir.path().join("test_pkg_with_empty_install.tar.gz");
+ let file = fs::File::create(&archive_path)?;
+ let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
+ let mut tar_builder = tar::Builder::new(gz_encoder);
+ tar_builder.append_path_with_name(&install_path, "INSTALL")?;
+ tar_builder.into_inner()?.finish()?;
+
+
+ let result = Package::check(archive_path.to_str().unwrap().to_string());
+
+ assert!(result.is_err());
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
+ assert!(err.to_string().contains("INSTALL file is empty"));
+
+ Ok(())
+ }
+
+
+ #[tokio::test]
+ async fn test_package_check_arch_mismatch() -> Result<(), Box<dyn std::error::Error>> {
+ let temp_dir = TempDir::new()?;
+ let _config = create_test_config(temp_dir.path().to_str().unwrap());
+
+ let host_arch = std::env::consts::ARCH;
+ let wrong_arch = if host_arch == "x86" { "x86_64" } else { "x86" };
+ let install_content = format!(r#"
+[package]
+name = "test-pkg"
+version = "1.0.0"
+arch = "{}"
+descr = "A test package for arch mismatch"
+license = "MIT"
+url = "/repo/test-pkg.mesk"
+
+[install]
+path = "/tmp/test_binary"
+user = "root"
+group = "root"
+mode = "755"
+"#, wrong_arch);
+
+ let install_path = temp_dir.path().join("INSTALL");
+ let mut install_file = fs::File::create(&install_path)?;
+ install_file.write_all(install_content.as_bytes())?;
+
+ let archive_path = temp_dir.path().join("test_pkg_with_wrong_arch.tar.gz");
+ let file = fs::File::create(&archive_path)?;
+ let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
+ let mut tar_builder = tar::Builder::new(gz_encoder);
+ tar_builder.append_path_with_name(&install_path, "INSTALL")?;
+ tar_builder.into_inner()?.finish()?;
+
+ let result = Package::check(archive_path.to_str().unwrap().to_string());
+
+
+ assert!(result.is_err());
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
+ assert!(err.to_string().contains("Arch mismatch"));
+
+ Ok(())
+ }
+
+} \ No newline at end of file
diff --git a/tests/secondary_funcs.rs b/tests/secondary_funcs.rs
new file mode 100644
index 0000000..84034d8
--- /dev/null
+++ b/tests/secondary_funcs.rs
@@ -0,0 +1,29 @@
+// use mesk::cfg::config::Config;
+// use toml;
+
+/*
+fn create_test_config(temp_dir_path: &str) -> Config {
+ /*
+ #[derive(Deserialize, Debug, Clone)]
+ pub struct Config {
+ pub repo: RepoConfig,
+ pub paths: PathConfig,
+ ...
+ }
+
+ #[derive(Deserialize, Debug, Clone)]
+ pub struct RepoConfig {
+ pub repo_url: String,
+ }
+
+ #[derive(Deserialize, Debug, Clone)]
+ pub struct PathConfig {
+ pub cache_dir: String,
+ ...
+ }
+ */
+ let cfg = Config::default().unwrap();
+ assert!(toml::to_string(&cfg).is_ok());
+ cfg
+}
+*/ \ No newline at end of file
diff --git a/tests/shared.rs b/tests/shared.rs
new file mode 100644
index 0000000..2ea0bf5
--- /dev/null
+++ b/tests/shared.rs
@@ -0,0 +1,22 @@
+use mesk::cfg::config::{Config, Repo, Log, Loglevel, Paths};
+
+pub fn create_test_config(temp_dir_path: &str) -> Config {
+ let cfg: Config = Config {
+ repo: Repo {
+ repo_url: format!(r"http://mesk.anthrill.i2p/repo/{}", std::env::consts::ARCH),
+ auto_update: true,
+ destination: (String::from("mesk"), String::from("mesk")),
+ repo_http_url: None,
+ },
+ log: Log {
+ log_file: String::from("/var/log/mesk.log"),
+ log_level: Loglevel::Info,
+ },
+ paths: Paths {
+ cache_dir: String::from(temp_dir_path),
+ build_dir: String::from(format!("{}/build", String::from(temp_dir_path)))
+ },
+ };
+
+ cfg
+} \ No newline at end of file