Skip to content

Commit

Permalink
Rewrite more 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
  • Loading branch information
dralley committed Apr 9, 2023
1 parent 2fbfb1a commit 9dbb7b8
Show file tree
Hide file tree
Showing 19 changed files with 564 additions and 370 deletions.
6 changes: 3 additions & 3 deletions src/rpm/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,14 @@ impl RPMBuilder {
self
}

pub fn add_changelog_entry<E, F>(mut self, author: E, entry: F, time: u32) -> Self
pub fn add_changelog_entry<E, F>(mut self, author: E, description: F, timestamp: u32) -> Self
where
E: Into<String>,
F: Into<String>,
{
self.changelog_authors.push(author.into());
self.changelog_entries.push(entry.into());
self.changelog_times.push(time);
self.changelog_entries.push(description.into());
self.changelog_times.push(timestamp);
self
}

Expand Down
10 changes: 5 additions & 5 deletions src/rpm/headers/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::path::PathBuf;
use super::*;
use crate::errors::*;

#[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 @@ -514,7 +514,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 @@ -594,8 +594,8 @@ impl IndexHeader {
}

/// A single entry within the [`IndexHeader`](self::IndexHeader)
#[derive(Debug, PartialEq)]
pub(crate) struct IndexEntry<T: num::FromPrimitive> {
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct IndexEntry<T: Tag> {
pub(crate) tag: T,
pub(crate) data: IndexData,
pub(crate) offset: i32,
Expand Down Expand Up @@ -675,7 +675,7 @@ impl<T: Tag> 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 @@ -13,7 +13,7 @@ use futures::io::{AsyncWrite, AsyncWriteExt};
/// 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
4 changes: 2 additions & 2 deletions src/rpm/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use std::io::Seek;
///
/// Can either be created using the [`RPMPackageBuilder`](super::builder::RPMPackageBuilder)
/// or used with [`parse`](`self::RPMPackage::parse`) to obtain from a file.
#[derive(Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct RPMPackage {
/// Header and metadata structures.
///
Expand Down Expand Up @@ -179,7 +179,7 @@ impl RPMPackage {
}
}

#[derive(PartialEq, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct RPMPackageMetadata {
pub lead: Lead,
pub signature: Header<IndexSignatureTag>,
Expand Down
39 changes: 0 additions & 39 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,45 +443,6 @@ async fn test_rpm_header_async() -> Result<(), Box<dyn std::error::Error>> {
test_rpm_header_base(package)
}

#[cfg(feature = "async-futures")]
#[tokio::test]
async fn test_rpm_builder_async() -> Result<(), Box<dyn std::error::Error>> {
use std::str::FromStr;

let mut buff = std::io::Cursor::new(Vec::<u8>::new());

let pkg = rpm::RPMBuilder::new("test", "1.0.0", "MIT", "x86_64", "some awesome package")
.compression(rpm::Compressor::from_str("gzip")?)
.with_file_async(
"Cargo.toml",
RPMFileOptions::new("/etc/awesome/config.toml").is_config(),
)
.await?
// file mode is inherited from source file
.with_file_async("Cargo.toml", RPMFileOptions::new("/usr/bin/awesome"))
.await?
.with_file_async(
"Cargo.toml",
// you can set a custom mode and custom user too
RPMFileOptions::new("/etc/awesome/second.toml")
.mode(0o100744)
.user("hugo"),
)
.await?
.pre_install_script("echo preinst")
.add_changelog_entry("me", "was awesome, eh?", 123123123)
.add_changelog_entry("you", "yeah, it was", 12312312)
.requires(Dependency::any("wget"))
.vendor("dummy vendor")
.url("dummy url")
.vcs("dummy vcs")
.build()?;

pkg.write(&mut buff)?;

Ok(())
}

#[test]
fn test_rpm_header() -> Result<(), Box<dyn std::error::Error>> {
let rpm_file_path = rpm_389_ds_file_path();
Expand Down
14 changes: 13 additions & 1 deletion test_assets/fixture_packages/build_packages.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
#!/bin/sh

export SOURCE_DATE_EPOCH="1681068559"
REPRODUCIBLE_OPTS=( --define "use_source_date_epoch_as_buildtime 1" --define "_binary_payload w.ufdio" --define "_source_payload w.ufdio" )

for spec in SPECS/*.spec; do
rpmbuild --define "_topdir `pwd`" --define "_binary_payload w.ufdio" --define "_source_payload w.ufdio" -ba $spec
rpmbuild --define "_topdir `pwd`" $"${REPRODUCIBLE_OPTS[@]}" -ba $spec
done

rm -r ./BUILDROOT/
rm -r ./BUILD/

RSA_KEY_OPTS=( --define "_gpg_name rsa3072-rpm-signing-key" )
EDDSA_KEY_OPTS=( --define "_gpg_name ed25519-rpm-signing-key" )

rpmsign --addsign RPMS/x86_64/rpm-empty-0-0.x86_64.rpm $"${EDDSA_KEY_OPTS[@]}"
rpmsign --addsign RPMS/x86_64/rpm-feature-coverage-2.3.4-5.el8.x86_64.rpm $"${RSA_KEY_OPTS[@]}"

# @todo: how to make IMA signing work? I get errors.
# --define "_file_signing_key rsa3072-rpm-signing-key" --signfiles
18 changes: 18 additions & 0 deletions test_assets/fixture_packages/configure_certs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# in case we ever need to regenerate these

# gpg --quick-generate-key 'rpm-rs key rsa3072 <[email protected]>' rsa3072 sign never
# gpg --quick-generate-key 'rpm-rs key ed25519 <[email protected]>' ed25519 sign never

# gpg --output ./signing_keys/public_rsa3072.asc --armor --export-secret-key [email protected]
# gpg --output ./signing_keys/secret_rsa3072.asc --armor --export-secret-key [email protected]

# gpg --output ./signing_keys/public_ed25519.asc --armor --export-secret-key [email protected]
# gpg --output ./signing_keys/secret_ed25519.asc --armor --export-secret-key [email protected]

gpg --import ./signing_keys/public_rsa3072.asc
gpg --import ./signing_keys/secret_rsa3072.asc
gpg --import ./signing_keys/public_ed25519.asc
gpg --import ./signing_keys/secret_ed25519.asc

sudo rpm --import ./signing_keys/public_rsa3072.asc
sudo rpm --import ./signing_keys/public_ed25519.asc
Binary file modified test_assets/fixture_packages/rpm-empty-0-0.src.rpm
Binary file not shown.
Binary file modified test_assets/fixture_packages/rpm-empty-0-0.x86_64.rpm
Binary file not shown.
Binary file not shown.
10 changes: 10 additions & 0 deletions test_assets/fixture_packages/signing_keys/public_ed25519.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEZDMGvRYJKwYBBAHaRw8BAQdASrUh0HQehtSwizkBSgYgSaACDks9C6yIewrO
UH6ehv60PWVkMjU1MTktcnBtLXNpZ25pbmcta2V5IDxlZDI1NTE5LXJwbS1zaWdu
aW5nLWtleUBleGFtcGxlLmNvbT6IkwQTFgoAOxYhBBgwZgjGUY6zix2XidD75dUz
MrnnBQJkMwa9AhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEND75dUz
MrnnIDQA/07Uwbzl2eIC4UHsepiVbnI73sb+4K3HqVFrM/my+5d+AQC8VmwlX1+y
Khz9gJ17tBAn519tulUxKzZvgoC6EZ11AQ==
=kOIO
-----END PGP PUBLIC KEY BLOCK-----
24 changes: 24 additions & 0 deletions test_assets/fixture_packages/signing_keys/public_rsa3072.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQGNBGQzBVYBDADgeyneDz+GKSlvUrAxcUt03LbSNKk3Wz/di1U3Wak+OHWk9RZK
Itp17GRVT+Vno9Fz2u/4FvXb3GAzG7tDYeV/kRoyPdEPPoaxwaeukA5rKWlyvkYD
AsRbZYQbCXYjQ04IsWhPGgLTPfFmMT5VEuTXE2Eb9u43bku/iw3DejdXBCNKNBwJ
bTRfdMzfgFybpDCbX4WB27Swtl5MmBlRTRFyvyHoYlAIuiBYGMpLrkRUw+5ZMSI2
GcmJXp/AqxLD3AiPZYnvBE/PC9Zkb4Ty1+XsJyWlTxKvFO2szj7Qa0lKcr2iGuWZ
rXKJo5uytpMZHmDJZLULHSHSitLJX3Cq8q0oPA3Z0PpijmmnWBIVShjflPGx/jEA
EuCy6ozIK00YyxXgWdt3+LfRdDMx5IHYlpKaEo+KicnWh802CWNEXHHk6VcdvWH+
KYmBIeYKP2Yay2YWnS8xP3MLk2QRvkwJJ9dnpXVZ9B3pQBTK3oiVWydeE+ZaHiMb
u6186dri1rAxHK0AEQEAAbRTcnNhMzA3Mi1ycG0tc2lnbmluZy1rZXkgKHJzYTMw
NzIgc2lnbmluZyBrZXkpIDxyc2EzMDcyLXJwbS1zaWduaW5nLWtleUBleGFtcGxl
LmNvbT6JAdEEEwEIADsWIQSMEWtRcfe81pf4+FJ+7xRST0FfXQUCZDMFVgIbAwUL
CQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRB+7xRST0FfXecRDACj7kcspbQB
fNzdHUNmpBruEQSnh/tndZLZx8n6fl/Hzke8l/YyAgdZm48PB0JuwVWkI2kQI5nz
taoqP0XgCruN1GO7j1Q5HhNh4qF8quv6jcQP4KXMCG+KsY+nL9yvVPytPzbzeagb
wAPaFsiTV0nba5UeGf4QyHkgzP2aUAxoh8LCfo+DoXU68UbDnpPfcJ5qaQEvcXRK
VirKEDGtN9wm1PXN77jAVg+aZ3I4SPX+05LFsbkq/827XYErbOnU0SrW09a4uHhd
6gHcL5aw7KglsEcUf0hWSeT0mX+TZhiyGHg2aC1ggTsvr4y7J4syVw/2ezGla2aX
n/2BpQET1a77uub2hCAP9iVyrcjXeNl61IsVcHTz7RmRmdG6DdA/MCTBYrwUOUFO
xVAANXpYHE27wsFL3WjoTPSlQAAV9omTu0SJoTYctgfXL7IOl5Uk+18F57KmYmjy
J4us8BaO3oHxzeYG7BOCtCTKQWsQwYMVflTd94DtwBG6F2BhGJfx10I=
=dNgi
-----END PGP PUBLIC KEY BLOCK-----
11 changes: 11 additions & 0 deletions test_assets/fixture_packages/signing_keys/secret_ed25519.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----

lFgEZDMGvRYJKwYBBAHaRw8BAQdASrUh0HQehtSwizkBSgYgSaACDks9C6yIewrO
UH6ehv4AAQD75kuLc7SufJW2tr5jHglJZTWcW6OcEq58v5Q2JaXSxRCRtD1lZDI1
NTE5LXJwbS1zaWduaW5nLWtleSA8ZWQyNTUxOS1ycG0tc2lnbmluZy1rZXlAZXhh
bXBsZS5jb20+iJMEExYKADsWIQQYMGYIxlGOs4sdl4nQ++XVMzK55wUCZDMGvQIb
AwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRDQ++XVMzK55yA0AP9O1MG8
5dniAuFB7HqYlW5yO97G/uCtx6lRazP5svuXfgEAvFZsJV9fsioc/YCde7QQJ+df
bbpVMSs2b4KAuhGddQE=
=OF0p
-----END PGP PRIVATE KEY BLOCK-----
45 changes: 45 additions & 0 deletions test_assets/fixture_packages/signing_keys/secret_rsa3072.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----

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
l/HXQg==
=K9Te
-----END PGP PRIVATE KEY BLOCK-----
99 changes: 99 additions & 0 deletions tests/building.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use std::io::Cursor;

use bstr::ByteSlice;
use pretty_assertions;

use rpm::*;

mod common;

/// Build an empty package and compare it to one built by rpmbuild
#[test]
fn test_empty_package_equivalent() -> Result<(), Box<dyn std::error::Error>> {
let empty_rpm = RPMPackage::open(common::rpm_empty_path())?;
let built_empty_rpm = RPMBuilder::new("rpm-empty", "0", "LGPL", "x86-64", "").build()?;

// @TODO: currently failing due to missing tags, different checksums, offsets etc.
// empty_rpm.canonicalize()?;
// built_empty_rpm.canonicalize()?;
// pretty_assertions::assert_eq!(empty_rpm.metadata, built_empty_rpm.metadata);

// Test that the payload generated is equivalent
pretty_assertions::assert_str_eq!(
format!("{:?}", &empty_rpm.content.as_bstr()),
format!("{:?}", &built_empty_rpm.content.as_bstr()),
);

Ok(())
}

/// Build an empty source package and compare it to one built by rpmbuild
/// Blocked on completion of source package support
#[ignore = "https://github.com/rpm-rs/rpm/issues/66"]
#[test]
fn test_empty_source_package_equivalent() -> Result<(), Box<dyn std::error::Error>> {
let empty_rpm = RPMPackage::open(common::rpm_empty_source_path())?;
let built_empty_rpm = RPMBuilder::new("rpm-empty", "0", "LGPL", "x86-64", "").build()?;

// @TODO: currently failing due to missing tags, different checksums, offsets etc.
// empty_rpm.canonicalize()?;
// built_empty_rpm.canonicalize()?;
// pretty_assertions::assert_eq!(empty_rpm.metadata, built_empty_rpm.metadata);

// Test that the payload generated is equivalent
pretty_assertions::assert_str_eq!(
format!("{:?}", &empty_rpm.content.as_bstr()),
format!("{:?}", &built_empty_rpm.content.as_bstr()),
);

Ok(())
}

// @todo: turn this into a comparison test for the rpm-feature-coverage RPM
/// Build an RPM using many features of RPM and (eventually) compare it to one built by rpmbuild
#[test]
fn test_rpm_builder() -> Result<(), Box<dyn std::error::Error>> {
use std::str::FromStr;

let mut buff = Vec::<u8>::new();

let pkg = rpm::RPMBuilder::new("test", "1.0.0", "MIT", "x86_64", "some awesome package")
.compression(rpm::Compressor::from_str("gzip")?)
.with_file(
"Cargo.toml",
RPMFileOptions::new("/etc/awesome/config.toml").is_config(),
)?
// file mode is inherited from source file
.with_file("Cargo.toml", RPMFileOptions::new("/usr/bin/awesome"))?
.with_file(
"Cargo.toml",
// you can set a custom mode and custom user too
RPMFileOptions::new("/etc/awesome/second.toml")
.mode(0o100744)
.user("hugo"),
)?
.pre_install_script("echo preinst")
.add_changelog_entry("me", "was awesome, eh?", 123123123)
.add_changelog_entry("you", "yeah, it was", 12312312)
.requires(Dependency::any("wget"))
.vendor("dummy vendor")
.url("dummy url")
.vcs("dummy vcs")
.build()?;

pkg.write(&mut buff)?;

Ok(())
}

/// Read a package, write it, and read it back - check for equivalence.
#[test]
fn test_rpm_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
let mut buf = Vec::new();
let rpm = RPMPackage::open(common::rpm_feature_coverage_pkg_path())?;
rpm.write(&mut buf)?;
let roundtripped_rpm = RPMPackage::parse(&mut Cursor::new(buf))?;

assert_eq!(rpm, roundtripped_rpm);
Ok(())
}
Loading

0 comments on commit 9dbb7b8

Please sign in to comment.