Skip to content

Commit

Permalink
Rewrite tests
Browse files Browse the repository at this point in the history
* Add a roundtrip test
* Move comparison tests to tests/building.rs and extend them
* Use fixture RPMs for new tests in tests/parsing.rs
* Consolidate fixture generation scripts
* Add IMA signing to fixtures
* Create dedicated specfiles for exercising various advanced features
* Add more tests for file attrs and capabilities
* Move test_assets/ to tests/assets/
* Add more functionality and docs for dependency creation
  • Loading branch information
dralley committed Dec 30, 2023
1 parent 6ef163e commit 0753d94
Show file tree
Hide file tree
Showing 49 changed files with 1,639 additions and 885 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
out
**/*.rpm
Cargo.lock
!test_assets/*
!tests/assets/*
dnf-cache
.idea
.idea
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ serial_test = "2.0"
pretty_assertions = "1.3.0"
gethostname = "0.4"
hex-literal = "0.4"
bstr = "1.4.0"

[features]
default = ["signature-pgp"]
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,24 @@ This library does not build software like rpmbuild. It is meant for finished art
```rust
use rpm::signature::pgp::{Signer, Verifier};

let raw_secret_key = std::fs::read("./test_assets/secret_key.asc")?;
let raw_secret_key = std::fs::read("./tests/assets/signing_keys/secret_ed25519.asc")?;
// It's recommended to use timestamp of last commit in your VCS
let source_date = 1_600_000_000;
let pkg = rpm::PackageBuilder::new("test", "1.0.0", "MIT", "x86_64", "some awesome package")
.compression(rpm::CompressionType::Gzip)
.with_file(
"./test_assets/awesome.toml",
"./tests/assets/SOURCES/example_config.toml",
rpm::FileOptions::new("/etc/awesome/config.toml")
.is_config()
.is_no_replace(),
)?
// file mode is inherited from source file
.with_file(
"./test_assets/awesome.py",
"./tests/assets/SOURCES/multiplication_tables.py",
rpm::FileOptions::new("/usr/bin/awesome"),
)?
.with_file(
"./test_assets/awesome.toml",
"./tests/assets/SOURCES/example_config.toml",
// you can set a custom mode and custom user too
rpm::FileOptions::new("/etc/awesome/second.toml")
.mode(rpm::FileMode::regular(0o644))
Expand Down Expand Up @@ -88,7 +88,7 @@ pkg.write_file("./awesome.rpm")?;

// reading
let raw_pub_key = std::fs::read("/path/to/gpg.key.pub")?;
let pkg = rpm::Package::open("test_assets/389-ds-base-devel-1.3.8.4-15.el7.x86_64.rpm")?;
let pkg = rpm::Package::open("tests/assets/RPMS/signed/noarch/rpm-basic-with-ed25519-2.3.4-5.el9.noarch.rpm")?;

let name = pkg.metadata.get_name()?;
let version = pkg.metadata.get_version()?;
Expand Down
15 changes: 2 additions & 13 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ bitflags! {
const TRIGGERPREIN = 1 << 25; // %triggerprein dependency
const KEYRING = 1 << 26;
// bit 27 unused
const CONFIG = 1 << 28;
const CONFIG = 1 << 28; // config() dependency: TODO: wtf is a config dependency?
const META = 1 << 29; // meta dependency
}
}
Expand All @@ -522,17 +522,14 @@ bitflags! {
/// Macro expansion,
///
/// Corresponds to RPMSCRIPT_FLAG_EXPAND
///
const EXPAND = 1;
/// Header queryformat expansion,
///
/// Corresponds to RPMSCRIPT_FLAG_QFORMAT
///
const QFORMAT = 1 << 1;
/// Critical for success/failure,
///
/// Corresponds to RPMSCRIPT_FLAG_CRITICAL
///
const CRITICAL = 1 << 2;
}
}
Expand Down Expand Up @@ -570,7 +567,7 @@ bitflags! {
const DONOTUSE = 1 << 2; // %%donotuse
const MISSINGOK = 1 << 3; // %%config(missingok)
const NOREPLACE = 1 << 4; // %%config(noreplace)
// const SPECFILE = 1 << 5; // first file in SRPM?
const SPECFILE = 1 << 5; // specfile, which is the first file in a source RPM
const GHOST = 1 << 6; // %%ghost
const LICENSE = 1 << 7; // %%license
const README = 1 << 8; // %%readme
Expand All @@ -593,63 +590,55 @@ pub enum DigestAlgorithm {
}

/// Index tag values for the %prein scriptlet,
///
pub(crate) const PREIN_TAGS: ScriptletIndexTags = (
IndexTag::RPMTAG_PREIN,
IndexTag::RPMTAG_PREINFLAGS,
IndexTag::RPMTAG_PREINPROG,
);

/// Index tag values for the %postin scriptlet,
///
pub(crate) const POSTIN_TAGS: ScriptletIndexTags = (
IndexTag::RPMTAG_POSTIN,
IndexTag::RPMTAG_POSTINFLAGS,
IndexTag::RPMTAG_POSTINPROG,
);

/// Index tag values for the %preun scriptlet,
///
pub(crate) const PREUN_TAGS: ScriptletIndexTags = (
IndexTag::RPMTAG_PREUN,
IndexTag::RPMTAG_PREUNFLAGS,
IndexTag::RPMTAG_PREUNPROG,
);

/// Index tag values for the %postun scriptlet,
///
pub(crate) const POSTUN_TAGS: ScriptletIndexTags = (
IndexTag::RPMTAG_POSTUN,
IndexTag::RPMTAG_POSTUNFLAGS,
IndexTag::RPMTAG_POSTUNPROG,
);

/// Index tag values for the %pretrans scriptlet,
///
pub(crate) const PRETRANS_TAGS: ScriptletIndexTags = (
IndexTag::RPMTAG_PRETRANS,
IndexTag::RPMTAG_PRETRANSFLAGS,
IndexTag::RPMTAG_PRETRANSPROG,
);

/// Index tag values for the %posttrans scriptlet,
///
pub(crate) const POSTTRANS_TAGS: ScriptletIndexTags = (
IndexTag::RPMTAG_POSTTRANS,
IndexTag::RPMTAG_POSTTRANSFLAGS,
IndexTag::RPMTAG_POSTTRANSPROG,
);

/// Index tag values for the %preuntrans scriptlet,
///
pub(crate) const PREUNTRANS_TAGS: ScriptletIndexTags = (
IndexTag::RPMTAG_PREUNTRANS,
IndexTag::RPMTAG_PREUNTRANSFLAGS,
IndexTag::RPMTAG_PREUNTRANSPROG,
);

/// Index tag values for the %postuntrans scriptlet,
///
pub(crate) const POSTUNTRANS_TAGS: ScriptletIndexTags = (
IndexTag::RPMTAG_POSTUNTRANS,
IndexTag::RPMTAG_POSTUNTRANSFLAGS,
Expand Down
13 changes: 5 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@
//! # let _ = env_logger::Builder::new().filter_level(log::LevelFilter::Trace).is_test(true).try_init();
//! # #[cfg(feature = "signature-pgp")]
//! # {
//! let raw_secret_key = std::fs::read("./test_assets/secret_key.asc")?;
//! let raw_secret_key = std::fs::read("./tests/assets/signing_keys/secret_rsa4096.asc")?;
//! // It's recommended to use timestamp of last commit in your VCS
//! let source_date = 1_600_000_000;
//! let pkg = rpm::PackageBuilder::new("test", "1.0.0", "MIT", "x86_64", "some awesome package")
//! .compression(rpm::CompressionType::Gzip)
//! .with_file(
//! "./test_assets/awesome.toml",
//! "./tests/assets/SOURCES/example_config.toml",
//! rpm::FileOptions::new("/etc/awesome/config.toml").is_config(),
//! )?
//! // file mode is inherited from source file
//! .with_file(
//! "./test_assets/awesome.py",
//! "./tests/assets/SOURCES/multiplication_tables.py",
//! rpm::FileOptions::new("/usr/bin/awesome"),
//! )?
//! .with_file(
//! "./test_assets/awesome.toml",
//! "./tests/assets/SOURCES/example_config.toml",
//! // you can set a custom mode and custom user too
//! rpm::FileOptions::new("/etc/awesome/second.toml")
//! .mode(rpm::FileMode::regular(0o644))
Expand Down Expand Up @@ -66,7 +66,7 @@
//! pkg.write(&mut f)?;
//!
//! // reading
//! let raw_pub_key = std::fs::read("test_assets/public_key.asc")?;
//! let raw_pub_key = std::fs::read("tests/assets/signing_keys/public_rsa4096.asc")?;
//! let pkg = rpm::Package::open("/tmp/awesome.rpm")?;
//! // verifying
//! pkg.verify_signature(Verifier::load_from_asc_bytes(&raw_pub_key)?)?;
Expand All @@ -85,6 +85,3 @@ pub use crate::constants::*;

mod rpm;
pub use crate::rpm::*;

#[cfg(test)]
mod tests;
12 changes: 6 additions & 6 deletions src/rpm/headers/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::{
use super::*;
use crate::{constants::*, errors::*, Timestamp};

#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct Header<T: Tag> {
pub(crate) index_header: IndexHeader,
pub(crate) index_entries: Vec<IndexEntry<T>>,
Expand Down Expand Up @@ -384,8 +384,8 @@ pub struct FileOwnership {

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct FileDigest {
digest: String,
algo: DigestAlgorithm,
pub digest: String,
pub algo: DigestAlgorithm,
}

impl FileDigest {
Expand Down Expand Up @@ -480,7 +480,7 @@ where
}

/// A header keeping track of all other header records.
#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct IndexHeader {
/// rpm specific magic header
pub(crate) magic: [u8; 3],
Expand Down Expand Up @@ -547,7 +547,7 @@ impl IndexHeader {
}

/// A single entry within the [`IndexHeader`](self::IndexHeader)
#[derive(PartialEq)]
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct IndexEntry<T: num::FromPrimitive> {
pub(crate) tag: u32,
pub(crate) data: IndexData,
Expand Down Expand Up @@ -650,7 +650,7 @@ impl<T: Tag> fmt::Display for IndexEntry<T> {
}

/// Data as present in a [`IndexEntry`](self::IndexEntry) .
#[derive(Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum IndexData {
Null,
Char(Vec<u8>),
Expand Down
2 changes: 1 addition & 1 deletion src/rpm/headers/lead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::errors::*;
/// Used to contain valid data, now only a very limited subset is used
/// and the remaining data is set to fixed values such that compatibility is kept.
/// Only the "magic number" is still relevant as it is used to detect rpm files.
#[derive(Eq)]
#[derive(Clone, Eq)]
pub struct Lead {
magic: [u8; 4],
major: u8,
Expand Down
71 changes: 59 additions & 12 deletions src/rpm/headers/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ impl From<FileMode> for u16 {
/// Description of file modes.
///
/// A subset
#[derive(Debug)]
pub struct FileOptions {
pub(crate) destination: String,
Expand Down Expand Up @@ -304,10 +303,22 @@ pub struct Dependency {
}

impl Dependency {
/// Create a dependency on any version of some package or file (or string in general).
pub fn any(dep_name: impl Into<String>) -> Self {
Self::new(dep_name.into(), DependencyFlags::ANY, "".to_string())
}

/// Create a dependency on an exact version of some package.
pub fn eq(dep_name: impl Into<String>, version: impl Into<String>) -> Self {
Self::new(dep_name.into(), DependencyFlags::EQUAL, version.into())
}

/// Create a dependency on a version of some package less than the provided one.
pub fn less(dep_name: impl Into<String>, version: impl Into<String>) -> Self {
Self::new(dep_name.into(), DependencyFlags::LESS, version.into())
}

/// Create a dependency on a version of some package less than or equal to the provided one.
pub fn less_eq(dep_name: impl Into<String>, version: impl Into<String>) -> Self {
Self::new(
dep_name.into(),
Expand All @@ -316,14 +327,12 @@ impl Dependency {
)
}

pub fn eq(dep_name: impl Into<String>, version: impl Into<String>) -> Self {
Self::new(dep_name.into(), DependencyFlags::EQUAL, version.into())
}

/// Create a dependency on a version of some package greater than the provided one.
pub fn greater(dep_name: impl Into<String>, version: impl Into<String>) -> Self {
Self::new(dep_name.into(), DependencyFlags::GREATER, version.into())
}

/// Create a dependency on a version of some package greater than or equal to the provided one.
pub fn greater_eq(dep_name: impl Into<String>, version: impl Into<String>) -> Self {
Self::new(
dep_name.into(),
Expand All @@ -332,19 +341,60 @@ impl Dependency {
)
}

pub fn any(dep_name: impl Into<String>) -> Self {
Self::new(dep_name.into(), DependencyFlags::ANY, "".to_string())
// TODO: does version matter here? probably not the common case though

/// Create a dependency on a package or file required for a pre-install script.
pub fn script_pre(dep_name: impl Into<String>) -> Self {
Self::new(dep_name.into(), DependencyFlags::SCRIPT_PRE, "".to_string())
}

/// Create a dependency on a package or file required for a post-install script.
pub fn script_post(dep_name: impl Into<String>) -> Self {
Self::new(
dep_name.into(),
DependencyFlags::SCRIPT_POST,
"".to_string(),
)
}

/// Create a dependency on a package or file required for a pre-un-install script.
pub fn script_preun(dep_name: impl Into<String>) -> Self {
Self::new(
dep_name.into(),
DependencyFlags::SCRIPT_PREUN,
"".to_string(),
)
}

/// Create a dependency on a package or file required for a post-un-install script.
pub fn script_postun(dep_name: impl Into<String>) -> Self {
Self::new(
dep_name.into(),
DependencyFlags::SCRIPT_POSTUN,
"".to_string(),
)
}

/// Create a dependency on an rpm feature, required to install this package
pub fn rpmlib(dep_name: impl Into<String>, version: impl Into<String>) -> Self {
Self::new(
dep_name.into(),
DependencyFlags::RPMLIB | DependencyFlags::EQUAL,
DependencyFlags::RPMLIB | DependencyFlags::LESS | DependencyFlags::EQUAL,
version.into(),
)
}

/// Add a config dependency
pub fn config(dep_name: impl Into<String>, version: impl Into<String>) -> Self {
Self::new(
dep_name.into(),
DependencyFlags::CONFIG | DependencyFlags::EQUAL,
version.into(),
)
}

fn new(dep_name: String, flags: DependencyFlags, version: String) -> Self {
/// Create a new dependency
pub fn new(dep_name: String, flags: DependencyFlags, version: String) -> Self {
Dependency {
name: dep_name,
flags,
Expand Down Expand Up @@ -415,23 +465,20 @@ impl Scriptlet {
/// Sets the scriptlet flags,
///
/// **Note** These flags can be used to configure macro expansions etc.
///
#[inline]
pub fn flags(mut self, flags: ScriptletFlags) -> Self {
self.flags = Some(flags);
self
}

/// Sets the scriptlet interpreter/arguments,
///
#[inline]
pub fn prog(mut self, mut prog: Vec<impl Into<String>>) -> Self {
self.program = Some(prog.drain(..).map(|p| p.into()).collect_vec());
self
}

/// Consumes the receiver and applies all index entries for the scriptlet based on builder state,
///
pub(crate) fn apply(
self,
records: &mut Vec<IndexEntry<IndexTag>>,
Expand Down
Loading

0 comments on commit 0753d94

Please sign in to comment.