use std::io::Write;
use axum::extract::{Path, State};
use flate2::write::GzEncoder;
use crate::adapter_http_server::ServerState;
pub async fn handler<AR>(
State(state): State<ServerState<AR>>,
Path(arch): Path<String>,
) -> Result<String, super::ApiError>
where
AR: crate::domain::prelude::AptRepositoryReader + Clone,
{
state
.apt_repository
.packages_file(arch.as_str())
.await
.map_err(|err| {
tracing::error!(error = ?err, "unable to fetch packages");
super::ApiError::internal("unable to fetch packages")
})
}
pub async fn gz_handler<AR>(
State(state): State<ServerState<AR>>,
Path(arch): Path<String>,
) -> Result<Vec<u8>, super::ApiError>
where
AR: crate::domain::prelude::AptRepositoryReader + Clone,
{
let data = handler(State(state), Path(arch)).await?;
let mut encoder = GzEncoder::new(Vec::new(), flate2::Compression::default());
encoder.write(data.as_bytes()).map_err(|err| {
tracing::error!(error = ?err, "unable to compress response");
super::ApiError::internal("unable to compress response")
})?;
encoder.finish().map_err(|err| {
tracing::error!(error = ?err, "unable to compress response");
super::ApiError::internal("unable to compress response")
})
}
#[cfg(test)]
mod tests {
use axum::extract::{Path, State};
use crate::{adapter_http_server::ServerState, domain::prelude::MockAptRepositoryService};
#[tokio::test]
async fn should_list_packages_when_requested() {
let mut apt_repository = MockAptRepositoryService::new();
apt_repository
.expect_packages_file()
.once()
.return_once(|arch| {
assert_eq!(arch, "amd64");
Box::pin(async { Ok(String::from("Package: test\nVersion: 1.0.0")) })
});
let res = super::handler(
State(ServerState { apt_repository }),
Path(String::from("amd64")),
)
.await
.unwrap();
assert_eq!(res, "Package: test\nVersion: 1.0.0");
}
#[tokio::test]
async fn should_return_error_when_packages_fetch_fails() {
let mut apt_repository = MockAptRepositoryService::new();
apt_repository
.expect_packages_file()
.once()
.return_once(|_| Box::pin(async { Err(anyhow::anyhow!("fetch error")) }));
let res = super::handler(
State(ServerState { apt_repository }),
Path(String::from("amd64")),
)
.await;
assert!(res.is_err());
}
#[tokio::test]
async fn should_return_compressed_packages_when_gz_requested() {
let mut apt_repository = MockAptRepositoryService::new();
apt_repository
.expect_packages_file()
.once()
.return_once(|arch| {
assert_eq!(arch, "amd64");
Box::pin(async { Ok(String::from("Package: test\nVersion: 1.0.0")) })
});
let res = super::gz_handler(
State(ServerState { apt_repository }),
Path(String::from("amd64")),
)
.await
.unwrap();
assert!(res.len() > 2);
assert_eq!(res[0], 0x1f);
assert_eq!(res[1], 0x8b);
}
#[tokio::test]
async fn should_return_error_when_gz_packages_fetch_fails() {
let mut apt_repository = MockAptRepositoryService::new();
apt_repository
.expect_packages_file()
.once()
.return_once(|_| Box::pin(async { Err(anyhow::anyhow!("fetch error")) }));
let res = super::gz_handler(
State(ServerState { apt_repository }),
Path(String::from("amd64")),
)
.await;
assert!(res.is_err());
}
}