assorted_debian_utils/
excuses.rs

1// Copyright 2021-2022 Sebastian Ramacher
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4//! # Helpers to handle `excuses.yaml` for testing migration
5//!
6//! This module provides helpers to deserialize [excuses.yaml](https://release.debian.org/britney/excuses.yaml)
7//! with [serde]. Note however, that this module only handles a biased selection of fields.
8
9use std::{collections::HashMap, fmt::Formatter, io};
10
11use chrono::{DateTime, Utc};
12use serde::{de, Deserialize, Deserializer};
13use smallvec::SmallVec;
14
15use crate::{
16    architectures::Architecture, archive::Component, utils::DateTimeVisitor,
17    version::PackageVersion,
18};
19
20/// Deserialize a datetime string into a `DateTime<Utc>`
21fn deserialize_datetime<'de, D>(deserializer: D) -> std::result::Result<DateTime<Utc>, D::Error>
22where
23    D: Deserializer<'de>,
24{
25    deserializer.deserialize_str(DateTimeVisitor("%Y-%m-%d %H:%M:%S%.f"))
26}
27
28/// Deserialize a version or '-' as `PackageVersion` or `None`
29fn deserialize_version<'de, D>(
30    deserializer: D,
31) -> std::result::Result<Option<PackageVersion>, D::Error>
32where
33    D: Deserializer<'de>,
34{
35    #[derive(Debug)]
36    struct Visitor;
37
38    impl de::Visitor<'_> for Visitor {
39        type Value = Option<PackageVersion>;
40
41        fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
42            write!(formatter, "a package version or '-'")
43        }
44
45        fn visit_str<E>(self, s: &str) -> std::result::Result<Self::Value, E>
46        where
47            E: de::Error,
48        {
49            if s == "-" {
50                Ok(None)
51            } else {
52                PackageVersion::try_from(s)
53                    .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(s), &self))
54                    .map(Some)
55            }
56        }
57    }
58
59    deserializer.deserialize_str(Visitor)
60}
61
62/// The excuses.
63#[derive(Debug, PartialEq, Eq, Deserialize)]
64#[serde(rename_all = "kebab-case")]
65pub struct Excuses {
66    /// Date of the run that produced `excuses.yaml`
67    #[serde(deserialize_with = "deserialize_datetime")]
68    pub generated_date: DateTime<Utc>,
69    /// All excuse items
70    ///
71    /// While not every excuses item relates to a source package, the field is still named that way in `excuses.yaml`
72    pub sources: Vec<ExcusesItem>,
73}
74
75/// A policy's verdict
76#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)]
77pub enum Verdict {
78    /// Policy passed
79    #[serde(rename = "PASS")]
80    Pass,
81    /// Policy passed due to a hint
82    #[serde(rename = "PASS_HINTED")]
83    PassHinted,
84    /// Rejected due to a block hint or because the upload requires explicit approval (e.g.,
85    /// uploads to proposed-updates or testing-proposed-updates)
86    #[serde(rename = "REJECTED_NEEDS_APPROVAL")]
87    RejectedNeedsApproval,
88    /// Rejected tu to a permanent issue
89    #[serde(rename = "REJECTED_PERMANENTLY")]
90    RejectedPermanently,
91    /// Rejected due to a transient issue
92    #[serde(rename = "REJECTED_TEMPORARILY")]
93    RejectedTemporarily,
94    /// Rejected, but not able to determine if the issue is transient
95    #[serde(rename = "REJECTED_CANNOT_DETERMINE_IF_PERMANENT")]
96    RejectedCannotDetermineIfPermanent,
97    /// Reject due to another blocking item.
98    #[serde(rename = "REJECTED_BLOCKED_BY_ANOTHER_ITEM")]
99    RejectedBlockedByAnotherItem,
100    /// Reject due to another blocking item.
101    #[serde(rename = "REJECTED_WAITING_FOR_ANOTHER_ITEM")]
102    RejectedWaitingForAnotherItem,
103}
104
105/// Age policy info
106#[derive(Debug, PartialEq, Eq, Deserialize)]
107#[serde(rename_all = "kebab-case")]
108pub struct AgeInfo {
109    /// The required age
110    pub age_requirement: u32,
111    /// The current age
112    pub current_age: u32,
113    /// The verdict
114    pub verdict: Verdict,
115}
116
117/// Catch-all policy info
118#[derive(Debug, PartialEq, Eq, Deserialize)]
119#[serde(rename_all = "kebab-case")]
120pub struct UnspecfiedPolicyInfo {
121    /// The verdict
122    pub verdict: Verdict,
123}
124
125/// Built-on-buildd policy info
126#[derive(Debug, PartialEq, Eq, Deserialize)]
127#[serde(rename_all = "kebab-case")]
128pub struct BuiltOnBuildd {
129    /// The signers for each architecture
130    pub signed_by: HashMap<Architecture, Option<String>>,
131    /// The verdict
132    pub verdict: Verdict,
133}
134
135/// Collected policy infos
136#[derive(Debug, PartialEq, Eq, Deserialize)]
137#[serde(rename_all = "kebab-case")]
138pub struct PolicyInfo {
139    /// The age policy
140    pub age: Option<AgeInfo>,
141    /// The buildt-on-buildd policy
142    pub builtonbuildd: Option<BuiltOnBuildd>,
143    /// The autopkgtest porlicy
144    pub autopkgtest: Option<UnspecfiedPolicyInfo>,
145    /// All remaining policies
146    #[serde(flatten)]
147    pub extras: HashMap<String, UnspecfiedPolicyInfo>,
148    /*
149        autopkgtest: Option<UnspecfiedPolicyInfo>,
150        block: Option<UnspecfiedPolicyInfo>,
151        build_depends: Option<UnspecfiedPolicyInfo>,
152        built_using:  Option<UnspecfiedPolicyInfo>,
153        depends: Option<UnspecfiedPolicyInfo>,
154        piuparts: Option<UnspecfiedPolicyInfo>,
155        rc_bugs: Option<UnspecfiedPolicyInfo>,
156    */
157}
158
159/// List of missing builds
160#[derive(Debug, PartialEq, Eq, Deserialize)]
161#[serde(rename_all = "kebab-case")]
162pub struct MissingBuilds {
163    /// Architectures where builds are missing
164    // 16 is arbitrary, but is large enough to hold all current release architectures
165    pub on_architectures: SmallVec<[Architecture; 16]>,
166}
167
168/// A source package's excuses
169#[derive(Debug, PartialEq, Eq, Deserialize)]
170#[serde(rename_all = "kebab-case")]
171pub struct ExcusesItem {
172    /// Maintainer of the package
173    pub maintainer: Option<String>,
174    /// The item is a candidate for migration
175    pub is_candidate: bool,
176    /// Version in the source suite, i.e., the version to migrate
177    ///
178    /// If the value is `None`, the package is being removed.
179    #[serde(deserialize_with = "deserialize_version")]
180    pub new_version: Option<PackageVersion>,
181    /// Version in the target suite
182    ///
183    /// If the value is `None`, the package is not yet available in the target suite.
184    #[serde(deserialize_with = "deserialize_version")]
185    pub old_version: Option<PackageVersion>,
186    /// Migration item name
187    pub item_name: String,
188    /// Source package name
189    pub source: String,
190    /// Migration is blocked by another package
191    pub invalidated_by_other_package: Option<bool>,
192    /// Component of the source package
193    pub component: Option<Component>,
194    /// Missing builds
195    pub missing_builds: Option<MissingBuilds>,
196    /// Policy info
197    #[serde(rename = "policy_info")]
198    pub policy_info: Option<PolicyInfo>,
199    /// The excuses
200    pub excuses: Vec<String>,
201    /// Combined verdict
202    pub migration_policy_verdict: Verdict,
203}
204
205impl ExcusesItem {
206    /// Excuses item refers to package removal
207    pub fn is_removal(&self) -> bool {
208        self.new_version.is_none()
209    }
210
211    /// Excuses item refers to a binNMU
212    pub fn is_binnmu(&self) -> bool {
213        self.new_version == self.old_version
214    }
215
216    /// Get architecture of the binNMU or `None`
217    pub fn binnmu_arch(&self) -> Option<Architecture> {
218        self.item_name.split_once('/').map(|(_, arch)| {
219            arch.split_once('_')
220                .map_or(arch, |(arch, _)| arch)
221                .try_into()
222                .unwrap()
223        })
224    }
225
226    /// Excuses item refers to an item in (stable) proposed-updates
227    pub fn is_from_pu(&self) -> bool {
228        self.item_name.ends_with("_pu")
229    }
230
231    /// Excuses item refers to an item in testing-proposed-updates
232    pub fn is_from_tpu(&self) -> bool {
233        self.item_name.ends_with("_tpu")
234    }
235}
236
237/// Result type
238pub type Result<T> = serde_yaml::Result<T>;
239
240/// Read excuses from a reader
241pub fn from_reader(reader: impl io::Read) -> Result<Excuses> {
242    serde_yaml::from_reader(reader)
243}
244
245/// Read excuses from a string
246pub fn from_str(data: &str) -> Result<Excuses> {
247    serde_yaml::from_str(data)
248}
249
250#[cfg(test)]
251mod test {
252    use crate::excuses::Verdict;
253
254    #[test]
255    fn deserialize() {
256        let data = r##"generated-date: 2022-07-02 20:09:06.890414
257sources:
258- excuses:
259  - 'Migration status for -kalarmcal (4:21.12.3-2 to -): Will attempt migration (Any
260    information below is purely informational)'
261  - 'Additional info:'
262  - ∙ ∙ Package not in unstable, will try to remove
263  is-candidate: true
264  item-name: -kalarmcal
265  maintainer: Debian Qt/KDE Maintainers
266  migration-policy-verdict: PASS
267  new-version: '-'
268  old-version: 4:21.12.3-2
269  reason: []
270  source: kalarmcal
271- detailed-info:
272  - Checking build-dependency on amd64
273  - Checking build-dependency (indep) on amd64
274  excuses:
275  - 'Migration status for libmoosex-types-path-class-perl (0.09-1.1 to 0.09-2): Will
276    attempt migration (Any information below is purely informational)'
277  - 'Additional info:'
278  - ∙ ∙ Piuparts tested OK - <a href="https://piuparts.debian.org/sid/source/libm/libmoosex-types-path-class-perl.html">https://piuparts.debian.org/sid/source/libm/libmoosex-types-path-class-perl.html</a>
279  - '∙ ∙ autopkgtest for <a href="#libmoosex-types-path-class-perl">libmoosex-types-path-class-perl</a>/0.09-2:
280    <a href="https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/amd64">amd64</a>:
281    <a href="https://ci.debian.net/data/autopkgtest/testing/amd64/libm/libmoosex-types-path-class-perl/23220832/log.gz"><span
282    style="background:#87d96c">Pass</span></a>, <a href="https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/arm64">arm64</a>:
283    <a href="https://ci.debian.net/data/autopkgtest/testing/arm64/libm/libmoosex-types-path-class-perl/23221438/log.gz"><span
284    style="background:#87d96c">Pass</span></a>, <a href="https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/armhf">armhf</a>:
285    <a href="https://ci.debian.net/data/autopkgtest/testing/armhf/libm/libmoosex-types-path-class-perl/23222108/log.gz"><span
286    style="background:#87d96c">Pass</span></a>, <a href="https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/i386">i386</a>:
287    <a href="https://ci.debian.net/data/autopkgtest/testing/i386/libm/libmoosex-types-path-class-perl/23222731/log.gz"><span
288    style="background:#87d96c">Pass</span></a>, <a href="https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/ppc64el">ppc64el</a>:
289    <a href="https://ci.debian.net/data/autopkgtest/testing/ppc64el/libm/libmoosex-types-path-class-perl/23223345/log.gz"><span
290    style="background:#87d96c">Pass</span></a>, <a href="https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/s390x">s390x</a>:
291    <a href="https://ci.debian.net/data/autopkgtest/testing/s390x/libm/libmoosex-types-path-class-perl/23224981/log.gz"><span
292    style="background:#87d96c">Pass</span></a>'
293  - ∙ ∙ Required age reduced by 3 days because of autopkgtest
294  - ∙ ∙ 2 days old (needed 2 days)
295  is-candidate: true
296  item-name: libmoosex-types-path-class-perl
297  maintainer: Debian Perl Group
298  migration-policy-verdict: PASS
299  new-version: 0.09-2
300  old-version: 0.09-1.1
301  policy_info:
302    age:
303      age-requirement: 2
304      current-age: 2
305      verdict: PASS
306    autopkgtest:
307      libfcgi-engine-perl/0.22-1.1:
308        amd64:
309        - PASS
310        - https://ci.debian.net/data/autopkgtest/testing/amd64/libf/libfcgi-engine-perl/23220825/log.gz
311        - https://ci.debian.net/packages/libf/libfcgi-engine-perl/testing/amd64
312        - null
313        - null
314        arm64:
315        - PASS
316        - https://ci.debian.net/data/autopkgtest/testing/arm64/libf/libfcgi-engine-perl/23221431/log.gz
317        - https://ci.debian.net/packages/libf/libfcgi-engine-perl/testing/arm64
318        - null
319        - null
320        armhf:
321        - PASS
322        - https://ci.debian.net/data/autopkgtest/testing/armhf/libf/libfcgi-engine-perl/23222101/log.gz
323        - https://ci.debian.net/packages/libf/libfcgi-engine-perl/testing/armhf
324        - null
325        - null
326        i386:
327        - PASS
328        - https://ci.debian.net/data/autopkgtest/testing/i386/libf/libfcgi-engine-perl/23222724/log.gz
329        - https://ci.debian.net/packages/libf/libfcgi-engine-perl/testing/i386
330        - null
331        - null
332        ppc64el:
333        - PASS
334        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libf/libfcgi-engine-perl/23223338/log.gz
335        - https://ci.debian.net/packages/libf/libfcgi-engine-perl/testing/ppc64el
336        - null
337        - null
338        s390x:
339        - PASS
340        - https://ci.debian.net/data/autopkgtest/testing/s390x/libf/libfcgi-engine-perl/23224974/log.gz
341        - https://ci.debian.net/packages/libf/libfcgi-engine-perl/testing/s390x
342        - null
343        - null
344      libgit-pureperl-perl/0.53-2:
345        amd64:
346        - PASS
347        - https://ci.debian.net/data/autopkgtest/testing/amd64/libg/libgit-pureperl-perl/23220826/log.gz
348        - https://ci.debian.net/packages/libg/libgit-pureperl-perl/testing/amd64
349        - null
350        - null
351        arm64:
352        - PASS
353        - https://ci.debian.net/data/autopkgtest/testing/arm64/libg/libgit-pureperl-perl/23221432/log.gz
354        - https://ci.debian.net/packages/libg/libgit-pureperl-perl/testing/arm64
355        - null
356        - null
357        armhf:
358        - PASS
359        - https://ci.debian.net/data/autopkgtest/testing/armhf/libg/libgit-pureperl-perl/23222102/log.gz
360        - https://ci.debian.net/packages/libg/libgit-pureperl-perl/testing/armhf
361        - null
362        - null
363        i386:
364        - PASS
365        - https://ci.debian.net/data/autopkgtest/testing/i386/libg/libgit-pureperl-perl/23222725/log.gz
366        - https://ci.debian.net/packages/libg/libgit-pureperl-perl/testing/i386
367        - null
368        - null
369        ppc64el:
370        - PASS
371        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libg/libgit-pureperl-perl/23223339/log.gz
372        - https://ci.debian.net/packages/libg/libgit-pureperl-perl/testing/ppc64el
373        - null
374        - null
375        s390x:
376        - PASS
377        - https://ci.debian.net/data/autopkgtest/testing/s390x/libg/libgit-pureperl-perl/23224975/log.gz
378        - https://ci.debian.net/packages/libg/libgit-pureperl-perl/testing/s390x
379        - null
380        - null
381      libmagpie-perl/1.163200-3:
382        amd64:
383        - PASS
384        - https://ci.debian.net/data/autopkgtest/testing/amd64/libm/libmagpie-perl/23220827/log.gz
385        - https://ci.debian.net/packages/libm/libmagpie-perl/testing/amd64
386        - null
387        - null
388        arm64:
389        - PASS
390        - https://ci.debian.net/data/autopkgtest/testing/arm64/libm/libmagpie-perl/23221433/log.gz
391        - https://ci.debian.net/packages/libm/libmagpie-perl/testing/arm64
392        - null
393        - null
394        armhf:
395        - PASS
396        - https://ci.debian.net/data/autopkgtest/testing/armhf/libm/libmagpie-perl/23222103/log.gz
397        - https://ci.debian.net/packages/libm/libmagpie-perl/testing/armhf
398        - null
399        - null
400        i386:
401        - PASS
402        - https://ci.debian.net/data/autopkgtest/testing/i386/libm/libmagpie-perl/23222726/log.gz
403        - https://ci.debian.net/packages/libm/libmagpie-perl/testing/i386
404        - null
405        - null
406        ppc64el:
407        - PASS
408        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libm/libmagpie-perl/23223340/log.gz
409        - https://ci.debian.net/packages/libm/libmagpie-perl/testing/ppc64el
410        - null
411        - null
412        s390x:
413        - PASS
414        - https://ci.debian.net/data/autopkgtest/testing/s390x/libm/libmagpie-perl/23224976/log.gz
415        - https://ci.debian.net/packages/libm/libmagpie-perl/testing/s390x
416        - null
417        - null
418      libmoosex-configfromfile-perl/0.14-2:
419        amd64:
420        - PASS
421        - https://ci.debian.net/data/autopkgtest/testing/amd64/libm/libmoosex-configfromfile-perl/23220828/log.gz
422        - https://ci.debian.net/packages/libm/libmoosex-configfromfile-perl/testing/amd64
423        - null
424        - null
425        arm64:
426        - PASS
427        - https://ci.debian.net/data/autopkgtest/testing/arm64/libm/libmoosex-configfromfile-perl/23221434/log.gz
428        - https://ci.debian.net/packages/libm/libmoosex-configfromfile-perl/testing/arm64
429        - null
430        - null
431        armhf:
432        - PASS
433        - https://ci.debian.net/data/autopkgtest/testing/armhf/libm/libmoosex-configfromfile-perl/23222104/log.gz
434        - https://ci.debian.net/packages/libm/libmoosex-configfromfile-perl/testing/armhf
435        - null
436        - null
437        i386:
438        - PASS
439        - https://ci.debian.net/data/autopkgtest/testing/i386/libm/libmoosex-configfromfile-perl/23222727/log.gz
440        - https://ci.debian.net/packages/libm/libmoosex-configfromfile-perl/testing/i386
441        - null
442        - null
443        ppc64el:
444        - PASS
445        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libm/libmoosex-configfromfile-perl/23223341/log.gz
446        - https://ci.debian.net/packages/libm/libmoosex-configfromfile-perl/testing/ppc64el
447        - null
448        - null
449        s390x:
450        - PASS
451        - https://ci.debian.net/data/autopkgtest/testing/s390x/libm/libmoosex-configfromfile-perl/23224977/log.gz
452        - https://ci.debian.net/packages/libm/libmoosex-configfromfile-perl/testing/s390x
453        - null
454        - null
455      libmoosex-configuration-perl/0.2-2:
456        amd64:
457        - PASS
458        - https://ci.debian.net/data/autopkgtest/testing/amd64/libm/libmoosex-configuration-perl/23220829/log.gz
459        - https://ci.debian.net/packages/libm/libmoosex-configuration-perl/testing/amd64
460        - null
461        - null
462        arm64:
463        - PASS
464        - https://ci.debian.net/data/autopkgtest/testing/arm64/libm/libmoosex-configuration-perl/23221435/log.gz
465        - https://ci.debian.net/packages/libm/libmoosex-configuration-perl/testing/arm64
466        - null
467        - null
468        armhf:
469        - PASS
470        - https://ci.debian.net/data/autopkgtest/testing/armhf/libm/libmoosex-configuration-perl/23222105/log.gz
471        - https://ci.debian.net/packages/libm/libmoosex-configuration-perl/testing/armhf
472        - null
473        - null
474        i386:
475        - PASS
476        - https://ci.debian.net/data/autopkgtest/testing/i386/libm/libmoosex-configuration-perl/23222728/log.gz
477        - https://ci.debian.net/packages/libm/libmoosex-configuration-perl/testing/i386
478        - null
479        - null
480        ppc64el:
481        - PASS
482        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libm/libmoosex-configuration-perl/23223342/log.gz
483        - https://ci.debian.net/packages/libm/libmoosex-configuration-perl/testing/ppc64el
484        - null
485        - null
486        s390x:
487        - PASS
488        - https://ci.debian.net/data/autopkgtest/testing/s390x/libm/libmoosex-configuration-perl/23224978/log.gz
489        - https://ci.debian.net/packages/libm/libmoosex-configuration-perl/testing/s390x
490        - null
491        - null
492      libmoosex-daemonize-perl/0.22-1:
493        amd64:
494        - PASS
495        - https://ci.debian.net/data/autopkgtest/testing/amd64/libm/libmoosex-daemonize-perl/23220830/log.gz
496        - https://ci.debian.net/packages/libm/libmoosex-daemonize-perl/testing/amd64
497        - null
498        - null
499        arm64:
500        - PASS
501        - https://ci.debian.net/data/autopkgtest/testing/arm64/libm/libmoosex-daemonize-perl/23221436/log.gz
502        - https://ci.debian.net/packages/libm/libmoosex-daemonize-perl/testing/arm64
503        - null
504        - null
505        armhf:
506        - PASS
507        - https://ci.debian.net/data/autopkgtest/testing/armhf/libm/libmoosex-daemonize-perl/23222106/log.gz
508        - https://ci.debian.net/packages/libm/libmoosex-daemonize-perl/testing/armhf
509        - null
510        - null
511        i386:
512        - PASS
513        - https://ci.debian.net/data/autopkgtest/testing/i386/libm/libmoosex-daemonize-perl/23222729/log.gz
514        - https://ci.debian.net/packages/libm/libmoosex-daemonize-perl/testing/i386
515        - null
516        - null
517        ppc64el:
518        - PASS
519        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libm/libmoosex-daemonize-perl/23223343/log.gz
520        - https://ci.debian.net/packages/libm/libmoosex-daemonize-perl/testing/ppc64el
521        - null
522        - null
523        s390x:
524        - PASS
525        - https://ci.debian.net/data/autopkgtest/testing/s390x/libm/libmoosex-daemonize-perl/23224979/log.gz
526        - https://ci.debian.net/packages/libm/libmoosex-daemonize-perl/testing/s390x
527        - null
528        - null
529      libmoosex-runnable-perl/0.10-1:
530        amd64:
531        - PASS
532        - https://ci.debian.net/data/autopkgtest/testing/amd64/libm/libmoosex-runnable-perl/23220831/log.gz
533        - https://ci.debian.net/packages/libm/libmoosex-runnable-perl/testing/amd64
534        - null
535        - null
536        arm64:
537        - PASS
538        - https://ci.debian.net/data/autopkgtest/testing/arm64/libm/libmoosex-runnable-perl/23221437/log.gz
539        - https://ci.debian.net/packages/libm/libmoosex-runnable-perl/testing/arm64
540        - null
541        - null
542        armhf:
543        - PASS
544        - https://ci.debian.net/data/autopkgtest/testing/armhf/libm/libmoosex-runnable-perl/23222107/log.gz
545        - https://ci.debian.net/packages/libm/libmoosex-runnable-perl/testing/armhf
546        - null
547        - null
548        i386:
549        - PASS
550        - https://ci.debian.net/data/autopkgtest/testing/i386/libm/libmoosex-runnable-perl/23222730/log.gz
551        - https://ci.debian.net/packages/libm/libmoosex-runnable-perl/testing/i386
552        - null
553        - null
554        ppc64el:
555        - PASS
556        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libm/libmoosex-runnable-perl/23223344/log.gz
557        - https://ci.debian.net/packages/libm/libmoosex-runnable-perl/testing/ppc64el
558        - null
559        - null
560        s390x:
561        - PASS
562        - https://ci.debian.net/data/autopkgtest/testing/s390x/libm/libmoosex-runnable-perl/23224980/log.gz
563        - https://ci.debian.net/packages/libm/libmoosex-runnable-perl/testing/s390x
564        - null
565        - null
566      libmoosex-types-path-class-perl/0.09-2:
567        amd64:
568        - PASS
569        - https://ci.debian.net/data/autopkgtest/testing/amd64/libm/libmoosex-types-path-class-perl/23220832/log.gz
570        - https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/amd64
571        - null
572        - null
573        arm64:
574        - PASS
575        - https://ci.debian.net/data/autopkgtest/testing/arm64/libm/libmoosex-types-path-class-perl/23221438/log.gz
576        - https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/arm64
577        - null
578        - null
579        armhf:
580        - PASS
581        - https://ci.debian.net/data/autopkgtest/testing/armhf/libm/libmoosex-types-path-class-perl/23222108/log.gz
582        - https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/armhf
583        - null
584        - null
585        i386:
586        - PASS
587        - https://ci.debian.net/data/autopkgtest/testing/i386/libm/libmoosex-types-path-class-perl/23222731/log.gz
588        - https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/i386
589        - null
590        - null
591        ppc64el:
592        - PASS
593        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libm/libmoosex-types-path-class-perl/23223345/log.gz
594        - https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/ppc64el
595        - null
596        - null
597        s390x:
598        - PASS
599        - https://ci.debian.net/data/autopkgtest/testing/s390x/libm/libmoosex-types-path-class-perl/23224981/log.gz
600        - https://ci.debian.net/packages/libm/libmoosex-types-path-class-perl/testing/s390x
601        - null
602        - null
603      libpackage-locator-perl/0.10-3:
604        amd64:
605        - PASS
606        - https://ci.debian.net/data/autopkgtest/testing/amd64/libp/libpackage-locator-perl/23220833/log.gz
607        - https://ci.debian.net/packages/libp/libpackage-locator-perl/testing/amd64
608        - null
609        - null
610        arm64:
611        - PASS
612        - https://ci.debian.net/data/autopkgtest/testing/arm64/libp/libpackage-locator-perl/23221439/log.gz
613        - https://ci.debian.net/packages/libp/libpackage-locator-perl/testing/arm64
614        - null
615        - null
616        armhf:
617        - PASS
618        - https://ci.debian.net/data/autopkgtest/testing/armhf/libp/libpackage-locator-perl/23222109/log.gz
619        - https://ci.debian.net/packages/libp/libpackage-locator-perl/testing/armhf
620        - null
621        - null
622        i386:
623        - PASS
624        - https://ci.debian.net/data/autopkgtest/testing/i386/libp/libpackage-locator-perl/23222732/log.gz
625        - https://ci.debian.net/packages/libp/libpackage-locator-perl/testing/i386
626        - null
627        - null
628        ppc64el:
629        - PASS
630        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libp/libpackage-locator-perl/23223346/log.gz
631        - https://ci.debian.net/packages/libp/libpackage-locator-perl/testing/ppc64el
632        - null
633        - null
634        s390x:
635        - PASS
636        - https://ci.debian.net/data/autopkgtest/testing/s390x/libp/libpackage-locator-perl/23224982/log.gz
637        - https://ci.debian.net/packages/libp/libpackage-locator-perl/testing/s390x
638        - null
639        - null
640      libtest-tempdir-perl/0.11-1:
641        amd64:
642        - PASS
643        - https://ci.debian.net/data/autopkgtest/testing/amd64/libt/libtest-tempdir-perl/23220834/log.gz
644        - https://ci.debian.net/packages/libt/libtest-tempdir-perl/testing/amd64
645        - null
646        - null
647        arm64:
648        - PASS
649        - https://ci.debian.net/data/autopkgtest/testing/arm64/libt/libtest-tempdir-perl/23221440/log.gz
650        - https://ci.debian.net/packages/libt/libtest-tempdir-perl/testing/arm64
651        - null
652        - null
653        armhf:
654        - PASS
655        - https://ci.debian.net/data/autopkgtest/testing/armhf/libt/libtest-tempdir-perl/23222110/log.gz
656        - https://ci.debian.net/packages/libt/libtest-tempdir-perl/testing/armhf
657        - null
658        - null
659        i386:
660        - PASS
661        - https://ci.debian.net/data/autopkgtest/testing/i386/libt/libtest-tempdir-perl/23222733/log.gz
662        - https://ci.debian.net/packages/libt/libtest-tempdir-perl/testing/i386
663        - null
664        - null
665        ppc64el:
666        - PASS
667        - https://ci.debian.net/data/autopkgtest/testing/ppc64el/libt/libtest-tempdir-perl/23223347/log.gz
668        - https://ci.debian.net/packages/libt/libtest-tempdir-perl/testing/ppc64el
669        - null
670        - null
671        s390x:
672        - PASS
673        - https://ci.debian.net/data/autopkgtest/testing/s390x/libt/libtest-tempdir-perl/23224983/log.gz
674        - https://ci.debian.net/packages/libt/libtest-tempdir-perl/testing/s390x
675        - null
676        - null
677      verdict: PASS
678    block:
679      verdict: PASS
680    build-depends:
681      check-build-depends-indep-on-arch: amd64
682      check-build-depends-on-arch: amd64
683      verdict: PASS
684    built-using:
685      verdict: PASS
686    builtonbuildd:
687      signed-by:
688        all: buildd_all-x86-grnet-02@buildd.debian.org
689      verdict: PASS
690    depends:
691      verdict: PASS
692    implicit-deps:
693      implicit-deps:
694        broken-binaries: []
695      verdict: PASS
696    piuparts:
697      piuparts-test-url: https://piuparts.debian.org/sid/source/libm/libmoosex-types-path-class-perl.html
698      test-results: pass
699      verdict: PASS
700    rc-bugs:
701      shared-bugs: []
702      unique-source-bugs: []
703      unique-target-bugs: []
704      verdict: PASS
705  reason: []
706  source: libmoosex-types-path-class-perl
707        "##;
708
709        let excuses = super::from_str(data).expect("successful parsing of excuses");
710        let sources = excuses.sources;
711        assert_eq!(sources.len(), 2);
712
713        let kalarm = &sources[0];
714        assert!(kalarm.is_removal());
715
716        let moosex = &sources[1];
717        assert_eq!(moosex.source, "libmoosex-types-path-class-perl");
718        assert!(moosex.is_candidate);
719        assert_eq!(
720            moosex
721                .policy_info
722                .as_ref()
723                .unwrap()
724                .age
725                .as_ref()
726                .unwrap()
727                .verdict,
728            Verdict::Pass
729        );
730    }
731}