mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 05:10:42 +00:00
Add manual testing setup for pkg6depotd
- Introduced scripts and configurations for manual testing using `anyvm` with OpenIndiana and OmniOS. - Implemented repository fetching (`fetch_repo.sh`) and server startup (`run_depotd.sh`) scripts. - Enhanced `pkg6depotd` to support default publisher routes and trailing slashes. - Updated integration tests to verify new publisher route behavior.
This commit is contained in:
parent
d16e5339ce
commit
22178cffd7
9 changed files with 317 additions and 22 deletions
|
|
@ -991,7 +991,10 @@ impl ReadableRepository for FileBackend {
|
|||
}
|
||||
|
||||
// Create and return a RepositoryInfo struct
|
||||
Ok(RepositoryInfo { publishers })
|
||||
Ok(RepositoryInfo {
|
||||
publishers,
|
||||
default_publisher: self.config.default_publisher.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// List packages in the repository
|
||||
|
|
|
|||
|
|
@ -274,6 +274,8 @@ pub struct PublisherInfo {
|
|||
pub struct RepositoryInfo {
|
||||
/// Information about publishers in the repository
|
||||
pub publishers: Vec<PublisherInfo>,
|
||||
/// Name of the default publisher, if any
|
||||
pub default_publisher: Option<String>,
|
||||
}
|
||||
|
||||
/// Information about a package in a repository
|
||||
|
|
|
|||
|
|
@ -407,7 +407,10 @@ impl ReadableRepository for RestBackend {
|
|||
}
|
||||
|
||||
// Create and return a RepositoryInfo struct
|
||||
Ok(RepositoryInfo { publishers })
|
||||
Ok(RepositoryInfo {
|
||||
publishers,
|
||||
default_publisher: self.config.default_publisher.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// List packages in the repository
|
||||
|
|
|
|||
|
|
@ -25,46 +25,78 @@ struct P5iFile {
|
|||
|
||||
pub async fn get_publisher_v0(
|
||||
state: State<Arc<DepotRepo>>,
|
||||
path: Path<String>,
|
||||
Path(publisher): Path<String>,
|
||||
) -> Result<Response, DepotError> {
|
||||
get_publisher_impl(state, path).await
|
||||
get_publisher_response(state, Some(publisher)).await
|
||||
}
|
||||
|
||||
pub async fn get_publisher_v1(
|
||||
state: State<Arc<DepotRepo>>,
|
||||
path: Path<String>,
|
||||
Path(publisher): Path<String>,
|
||||
) -> Result<Response, DepotError> {
|
||||
get_publisher_impl(state, path).await
|
||||
get_publisher_response(state, Some(publisher)).await
|
||||
}
|
||||
|
||||
async fn get_publisher_impl(
|
||||
pub async fn get_default_publisher_v0(
|
||||
state: State<Arc<DepotRepo>>,
|
||||
) -> Result<Response, DepotError> {
|
||||
get_publisher_response(state, None).await
|
||||
}
|
||||
|
||||
pub async fn get_default_publisher_v1(
|
||||
state: State<Arc<DepotRepo>>,
|
||||
) -> Result<Response, DepotError> {
|
||||
get_publisher_response(state, None).await
|
||||
}
|
||||
|
||||
async fn get_publisher_response(
|
||||
State(repo): State<Arc<DepotRepo>>,
|
||||
Path(publisher): Path<String>,
|
||||
publisher: Option<String>,
|
||||
) -> Result<Response, DepotError> {
|
||||
let repo_info = repo.get_info()?;
|
||||
|
||||
let pub_info = repo_info
|
||||
.publishers
|
||||
.into_iter()
|
||||
.find(|p| p.name == publisher);
|
||||
if let Some(name) = publisher {
|
||||
let pub_info = repo_info.publishers.into_iter().find(|p| p.name == name);
|
||||
|
||||
if let Some(p) = pub_info {
|
||||
let p5i = P5iFile {
|
||||
packages: Vec::new(),
|
||||
publishers: vec![P5iPublisherInfo {
|
||||
if let Some(p) = pub_info {
|
||||
let p5i = P5iFile {
|
||||
packages: Vec::new(),
|
||||
publishers: vec![P5iPublisherInfo {
|
||||
alias: None,
|
||||
name: p.name,
|
||||
packages: Vec::new(),
|
||||
repositories: Vec::new(),
|
||||
}],
|
||||
version: 1,
|
||||
};
|
||||
let json =
|
||||
serde_json::to_string_pretty(&p5i).map_err(|e| DepotError::Server(e.to_string()))?;
|
||||
Ok(([(header::CONTENT_TYPE, "application/vnd.pkg5.info")], json).into_response())
|
||||
} else {
|
||||
Err(DepotError::Repo(
|
||||
libips::repository::RepositoryError::PublisherNotFound(name),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
// Return all publishers
|
||||
let publishers = repo_info
|
||||
.publishers
|
||||
.into_iter()
|
||||
.map(|p| P5iPublisherInfo {
|
||||
alias: None,
|
||||
name: p.name,
|
||||
packages: Vec::new(),
|
||||
repositories: Vec::new(),
|
||||
}],
|
||||
})
|
||||
.collect();
|
||||
|
||||
let p5i = P5iFile {
|
||||
packages: Vec::new(),
|
||||
publishers,
|
||||
version: 1,
|
||||
};
|
||||
let json =
|
||||
serde_json::to_string_pretty(&p5i).map_err(|e| DepotError::Server(e.to_string()))?;
|
||||
Ok(([(header::CONTENT_TYPE, "application/vnd.pkg5.info")], json).into_response())
|
||||
} else {
|
||||
Err(DepotError::Repo(
|
||||
libips::repository::RepositoryError::PublisherNotFound(publisher),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use tower_http::trace::TraceLayer;
|
|||
|
||||
pub fn app_router(state: Arc<DepotRepo>) -> Router {
|
||||
Router::new()
|
||||
.route("/versions/0", get(versions::get_versions))
|
||||
.route("/versions/0/", get(versions::get_versions))
|
||||
.route(
|
||||
"/{publisher}/catalog/1/{filename}",
|
||||
|
|
@ -37,7 +38,13 @@ pub fn app_router(state: Arc<DepotRepo>) -> Router {
|
|||
)
|
||||
.route("/{publisher}/info/0/{fmri}", get(info::get_info))
|
||||
.route("/{publisher}/publisher/0", get(publisher::get_publisher_v0))
|
||||
.route("/{publisher}/publisher/0/", get(publisher::get_publisher_v0))
|
||||
.route("/{publisher}/publisher/1", get(publisher::get_publisher_v1))
|
||||
.route("/{publisher}/publisher/1/", get(publisher::get_publisher_v1))
|
||||
.route("/publisher/0", get(publisher::get_default_publisher_v0))
|
||||
.route("/publisher/0/", get(publisher::get_default_publisher_v0))
|
||||
.route("/publisher/1", get(publisher::get_default_publisher_v1))
|
||||
.route("/publisher/1/", get(publisher::get_default_publisher_v1))
|
||||
.route("/{publisher}/search/0/{token}", get(search::get_search_v0))
|
||||
.route("/{publisher}/search/1/{token}", get(search::get_search_v1))
|
||||
// Admin API over HTTP
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ async fn test_depot_server() {
|
|||
.unwrap();
|
||||
assert!(resp.status().is_success());
|
||||
let text = resp.text().await.unwrap();
|
||||
assert!(text.contains("pkg-server pkg6depotd-0.5.1"));
|
||||
assert!(text.contains("pkg-server pkg6depotd-"));
|
||||
assert!(text.contains("catalog 1"));
|
||||
assert!(text.contains("manifest 0 1"));
|
||||
|
||||
|
|
@ -158,6 +158,12 @@ async fn test_depot_server() {
|
|||
let pub_url = format!("{}/test/publisher/1", base_url);
|
||||
let resp = client.get(&pub_url).send().await.unwrap();
|
||||
assert!(resp.status().is_success());
|
||||
|
||||
// Test Publisher v1 with trailing slash
|
||||
let pub_url_slash = format!("{}/test/publisher/1/", base_url);
|
||||
let resp = client.get(&pub_url_slash).send().await.unwrap();
|
||||
assert!(resp.status().is_success());
|
||||
|
||||
assert!(
|
||||
resp.headers()
|
||||
.get("content-type")
|
||||
|
|
@ -169,6 +175,36 @@ async fn test_depot_server() {
|
|||
let pub_json: serde_json::Value = resp.json().await.unwrap();
|
||||
assert_eq!(pub_json["version"], 1);
|
||||
assert_eq!(pub_json["publishers"][0]["name"], "test");
|
||||
|
||||
// Test Default Publisher Route v1
|
||||
let def_pub_url = format!("{}/publisher/1", base_url);
|
||||
let resp = client.get(&def_pub_url).send().await.unwrap();
|
||||
assert!(resp.status().is_success());
|
||||
|
||||
// Test Default Publisher Route v1 with trailing slash
|
||||
let def_pub_url_slash = format!("{}/publisher/1/", base_url);
|
||||
let resp = client.get(&def_pub_url_slash).send().await.unwrap();
|
||||
assert!(resp.status().is_success());
|
||||
|
||||
let pub_json: serde_json::Value = resp.json().await.unwrap();
|
||||
// In current implementation it returns one publisher.
|
||||
// We want it to return all publishers.
|
||||
assert_eq!(pub_json["publishers"].as_array().unwrap().len(), 1);
|
||||
assert_eq!(pub_json["publishers"][0]["name"], "test");
|
||||
|
||||
// Test Default Publisher Route v0
|
||||
let def_pub_url_v0 = format!("{}/publisher/0", base_url);
|
||||
let resp = client.get(&def_pub_url_v0).send().await.unwrap();
|
||||
assert!(resp.status().is_success());
|
||||
|
||||
// Test Default Publisher Route v0 with trailing slash
|
||||
let def_pub_url_v0_slash = format!("{}/publisher/0/", base_url);
|
||||
let resp = client.get(&def_pub_url_v0_slash).send().await.unwrap();
|
||||
assert!(resp.status().is_success());
|
||||
|
||||
let pub_json: serde_json::Value = resp.json().await.unwrap();
|
||||
assert_eq!(pub_json["publishers"].as_array().unwrap().len(), 1);
|
||||
assert_eq!(pub_json["publishers"][0]["name"], "test");
|
||||
|
||||
// 6. Test File
|
||||
// We assume file exists if manifest works.
|
||||
|
|
@ -385,3 +421,62 @@ async fn test_file_url_without_algo() {
|
|||
);
|
||||
let _content = resp.text().await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_multiple_publishers_default_route() {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
let repo_path = temp_dir.path().join("repo_multi");
|
||||
let mut backend = FileBackend::create(&repo_path, RepositoryVersion::V4).unwrap();
|
||||
|
||||
backend.add_publisher("pub1").unwrap();
|
||||
backend.add_publisher("pub2").unwrap();
|
||||
|
||||
let config = Config {
|
||||
server: ServerConfig {
|
||||
bind: vec!["127.0.0.1:0".to_string()],
|
||||
workers: None,
|
||||
max_connections: None,
|
||||
reuseport: None,
|
||||
cache_max_age: Some(3600),
|
||||
tls_cert: None,
|
||||
tls_key: None,
|
||||
},
|
||||
repository: RepositoryConfig {
|
||||
root: repo_path.clone(),
|
||||
mode: Some("readonly".to_string()),
|
||||
},
|
||||
telemetry: None,
|
||||
publishers: None,
|
||||
admin: None,
|
||||
oauth2: None,
|
||||
};
|
||||
|
||||
let repo = DepotRepo::new(&config).unwrap();
|
||||
let state = Arc::new(repo);
|
||||
let router = http::routes::app_router(state);
|
||||
|
||||
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
|
||||
tokio::spawn(async move {
|
||||
http::server::run(router, listener).await.unwrap();
|
||||
});
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let base_url = format!("http://{}", addr);
|
||||
|
||||
let def_pub_url = format!("{}/publisher/0", base_url);
|
||||
let resp = client.get(&def_pub_url).send().await.unwrap();
|
||||
assert!(resp.status().is_success());
|
||||
|
||||
let pub_json: serde_json::Value = resp.json().await.unwrap();
|
||||
let pubs = pub_json["publishers"].as_array().unwrap();
|
||||
|
||||
// CURRENT BEHAVIOR: returns 1
|
||||
// DESIRED BEHAVIOR: returns 2
|
||||
assert_eq!(pubs.len(), 2, "Should return all publishers");
|
||||
|
||||
let names: Vec<String> = pubs.iter().map(|p| p["name"].as_str().unwrap().to_string()).collect();
|
||||
assert!(names.contains(&"pub1".to_string()));
|
||||
assert!(names.contains(&"pub2".to_string()));
|
||||
}
|
||||
|
|
|
|||
79
testing/manual/README.md
Normal file
79
testing/manual/README.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Manual Testing Setup for pkg6depotd
|
||||
|
||||
This directory contains scripts and configurations for manual testing of `pkg6depotd` using `anyvm` with OpenIndiana and OmniOS.
|
||||
|
||||
## Overview
|
||||
|
||||
The goal is to test `pkg6depotd` as a server for the standard Python `pkg` client running inside an illumos VM.
|
||||
|
||||
1. **Host**: Runs `pkg6depotd` serving a local repository.
|
||||
2. **VM**: Runs OpenIndiana or OmniOS and uses `pkg` to communicate with the host.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `~/bin/anyvm.py` script (automated QEMU VM launcher).
|
||||
- Rust toolchain installed on the host.
|
||||
|
||||
## Step-by-Step Instructions
|
||||
|
||||
### 1. Start the VM
|
||||
|
||||
Choose either OpenIndiana or OmniOS. Use the `anyvm.py` script located in `~/bin/`.
|
||||
|
||||
```bash
|
||||
# For OpenIndiana
|
||||
python3 ~/bin/anyvm.py --os openindiana --release 202510 -v $(pwd):/root/ips
|
||||
|
||||
# For OmniOS
|
||||
python3 ~/bin/anyvm.py --os omnios --release r151056 -v $(pwd):/root/ips
|
||||
```
|
||||
|
||||
You can add `--ssh-port 2222` if you want a fixed SSH port. `anyvm.py` will display the SSH command to use.
|
||||
|
||||
### 2. Fetch a sample repository inside the VM
|
||||
|
||||
Once the VM is running, SSH into it and run the `fetch_repo.sh` script to create a small local repository.
|
||||
Since we mounted the project root to `/root/ips`, you can fetch the repository directly into that mount to make it immediately available on the host.
|
||||
|
||||
```bash
|
||||
# From the host (replace <port> with the one assigned by anyvm)
|
||||
ssh -p <port> root@localhost
|
||||
|
||||
# Inside the VM
|
||||
cd /root/ips
|
||||
./testing/manual/fetch_repo.sh https://pkg.openindiana.org/hipster ./test_repo
|
||||
```
|
||||
|
||||
This will create a repository at `./test_repo` inside the VM (which is also visible on the host) containing a few packages.
|
||||
|
||||
### 3. Run pkg6depotd on the host
|
||||
|
||||
Now that the repository is available on the host, you can run `pkg6depotd`.
|
||||
|
||||
```bash
|
||||
./testing/manual/run_depotd.sh ./test_repo
|
||||
```
|
||||
|
||||
The server will start on `0.0.0.0:8080`.
|
||||
|
||||
### 4. Test with the pkg client inside the VM
|
||||
|
||||
Back inside the VM, point the `pkg` client to the host's `pkg6depotd`.
|
||||
In QEMU's default user networking, the host is reachable at `10.0.2.2`.
|
||||
|
||||
```bash
|
||||
# Inside the VM
|
||||
# 1. Add the publisher
|
||||
pkg set-publisher -g http://10.0.2.2:8080 test
|
||||
|
||||
# 2. List packages from the new publisher
|
||||
pkg list -v -p test
|
||||
|
||||
# 3. Try to install a package (if available in the fetched subset)
|
||||
pkg install library/zlib
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Connection issues**: Ensure `pkg6depotd` is binding to an address reachable from the VM (e.g., `0.0.0.0` or the host's bridge IP).
|
||||
- **Missing packages**: Ensure the packages you are trying to install were included in the `fetch_repo.sh` call.
|
||||
36
testing/manual/fetch_repo.sh
Executable file
36
testing/manual/fetch_repo.sh
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Script to fetch a package repository copy using pkgrecv.
|
||||
# This script is intended to be run inside an OpenIndiana or OmniOS VM.
|
||||
|
||||
set -e
|
||||
|
||||
SOURCE_URL="${1:-https://pkg.openindiana.org/hipster}"
|
||||
DEST_DIR="${2:-/var/share/pkg_repo}"
|
||||
# Default to a small set of packages for testing if none specified
|
||||
# 'entire' or '*' can be used to fetch more/all packages, but be aware of size.
|
||||
shift 2 || true
|
||||
PACKAGES=("$@")
|
||||
|
||||
if [ ${#PACKAGES[@]} -eq 0 ]; then
|
||||
echo "No packages specified, fetching a small set for testing..."
|
||||
PACKAGES=("library/zlib" "system/library")
|
||||
fi
|
||||
|
||||
echo "Source: $SOURCE_URL"
|
||||
echo "Destination: $DEST_DIR"
|
||||
echo "Packages: ${PACKAGES[*]}"
|
||||
|
||||
if [ ! -d "$DEST_DIR" ]; then
|
||||
echo "Creating repository at $DEST_DIR..."
|
||||
mkdir -p "$DEST_DIR"
|
||||
pkgrepo create "$DEST_DIR"
|
||||
# We'll set a generic prefix, or use the one from source if we wanted to be more fancy
|
||||
pkgrepo set -s "$DEST_DIR" publisher/prefix=openindiana.org
|
||||
fi
|
||||
|
||||
pkgrecv -s "$SOURCE_URL" -d "$DEST_DIR" "${PACKAGES[@]}" --newest
|
||||
|
||||
|
||||
echo "Repository fetch complete."
|
||||
echo "You can now sync $DEST_DIR to your host to use with pkg6depotd."
|
||||
38
testing/manual/run_depotd.sh
Executable file
38
testing/manual/run_depotd.sh
Executable file
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Script to build and run pkg6depotd for manual testing.
|
||||
|
||||
set -e
|
||||
|
||||
REPO_ROOT="${1:-/tmp/pkg_repo}"
|
||||
|
||||
echo "Building pkg6depotd..."
|
||||
cargo build -p pkg6depotd
|
||||
|
||||
if [ ! -d "$REPO_ROOT" ]; then
|
||||
echo "Warning: Repository root $REPO_ROOT does not exist."
|
||||
echo "You might want to fetch a repository first using fetch_repo.sh inside a VM"
|
||||
echo "and then sync it to this path."
|
||||
fi
|
||||
|
||||
# Create a temporary config file based on the one in the root but with the correct repo path
|
||||
CONFIG_FILE="/tmp/pkg6depotd_test.kdl"
|
||||
cat > "$CONFIG_FILE" <<EOF
|
||||
server {
|
||||
bind "0.0.0.0:8080"
|
||||
workers 4
|
||||
}
|
||||
|
||||
repository {
|
||||
root "$REPO_ROOT"
|
||||
mode "readonly"
|
||||
}
|
||||
|
||||
telemetry {
|
||||
service-name "pkg6depotd"
|
||||
log-format "json"
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "Starting pkg6depotd with config $CONFIG_FILE..."
|
||||
RUST_LOG=debug ./target/debug/pkg6depotd -c "$CONFIG_FILE" start
|
||||
Loading…
Add table
Reference in a new issue