1use std::fmt::Display;
2
3use nethsm_sdk_rs::models::{SignMode, Switch, UnattendedBootConfig};
4use serde::{Deserialize, Serialize};
5use ureq::Response;
6
7#[derive(Debug, Deserialize)]
12pub struct Message {
13 message: String,
14}
15
16impl From<Response> for Message {
17 fn from(value: Response) -> Self {
18 if let Ok(message) = value.into_json() {
19 message
20 } else {
21 Message {
22 message: "Deserialization error (no message in body)".to_string(),
23 }
24 }
25 }
26}
27
28impl Display for Message {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.write_str(&self.message)
31 }
32}
33
34#[derive(Debug)]
35pub struct ApiErrorMessage {
36 pub status_code: u16,
37 pub message: Message,
38}
39
40impl From<(u16, Message)> for ApiErrorMessage {
41 fn from(value: (u16, Message)) -> Self {
42 Self {
43 status_code: value.0,
44 message: value.1,
45 }
46 }
47}
48
49impl Display for ApiErrorMessage {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 f.write_str(&format!(
52 "{} (status code {})",
53 self.message, self.status_code
54 ))
55 }
56}
57
58pub struct NetHsmApiError<T> {
63 error: Option<nethsm_sdk_rs::apis::Error<T>>,
64 message: Option<String>,
65}
66
67impl<T> From<nethsm_sdk_rs::apis::Error<T>> for NetHsmApiError<T> {
68 fn from(value: nethsm_sdk_rs::apis::Error<T>) -> Self {
69 match value {
70 nethsm_sdk_rs::apis::Error::Ureq(error) => match error {
71 nethsm_sdk_rs::ureq::Error::Status(code, response) => Self {
72 error: None,
73 message: Some(ApiErrorMessage::from((code, response.into())).to_string()),
74 },
75 nethsm_sdk_rs::ureq::Error::Transport(transport) => Self {
76 error: None,
77 message: Some(format!("{}", transport)),
78 },
79 },
80 nethsm_sdk_rs::apis::Error::ResponseError(resp) => Self {
81 error: None,
82 message: Some(format!(
83 "Status code: {}: {}",
84 resp.status,
85 serde_json::from_slice::<Message>(&resp.content)
88 .map(|m| m.message)
89 .unwrap_or_else(|_| String::from_utf8_lossy(&resp.content).into())
91 )),
92 },
93 _ => Self {
94 error: Some(value),
95 message: None,
96 },
97 }
98 }
99}
100
101impl<T> Display for NetHsmApiError<T> {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 if let Some(message) = self.message.as_ref() {
104 write!(f, "{}", message)?;
105 } else if let Some(error) = self.error.as_ref() {
106 write!(f, "{}", error)?;
107 }
108 Ok(())
109 }
110}
111
112#[derive(
117 Clone,
118 Copy,
119 Debug,
120 Deserialize,
121 strum::Display,
122 strum::EnumString,
123 strum::EnumIter,
124 strum::IntoStaticStr,
125 Eq,
126 PartialEq,
127 Ord,
128 PartialOrd,
129 Hash,
130 Serialize,
131)]
132#[strum(ascii_case_insensitive)]
133pub enum SignatureType {
134 EcdsaP224,
137
138 EcdsaP256,
141
142 EcdsaP384,
145
146 EcdsaP521,
149
150 EdDsa,
152
153 Pkcs1,
155
156 PssMd5,
158
159 PssSha1,
161
162 PssSha224,
164
165 PssSha256,
167
168 PssSha384,
170
171 PssSha512,
173}
174
175impl From<SignatureType> for SignMode {
176 fn from(value: SignatureType) -> Self {
177 match value {
178 SignatureType::Pkcs1 => SignMode::Pkcs1,
179 SignatureType::PssMd5 => SignMode::PssMd5,
180 SignatureType::PssSha1 => SignMode::PssSha1,
181 SignatureType::PssSha224 => SignMode::PssSha224,
182 SignatureType::PssSha256 => SignMode::PssSha256,
183 SignatureType::PssSha384 => SignMode::PssSha384,
184 SignatureType::PssSha512 => SignMode::PssSha512,
185 SignatureType::EdDsa => SignMode::EdDsa,
186 SignatureType::EcdsaP224
187 | SignatureType::EcdsaP256
188 | SignatureType::EcdsaP384
189 | SignatureType::EcdsaP521 => SignMode::Ecdsa,
190 }
191 }
192}
193
194#[derive(
200 Clone,
201 Debug,
202 strum::Display,
203 strum::EnumString,
204 strum::EnumIter,
205 strum::IntoStaticStr,
206 Eq,
207 PartialEq,
208)]
209#[strum(ascii_case_insensitive)]
210pub enum BootMode {
211 Attended,
214 Unattended,
217}
218
219impl From<UnattendedBootConfig> for BootMode {
220 fn from(value: UnattendedBootConfig) -> Self {
221 match value.status {
222 Switch::On => BootMode::Unattended,
223 Switch::Off => BootMode::Attended,
224 }
225 }
226}
227
228impl From<BootMode> for UnattendedBootConfig {
229 fn from(value: BootMode) -> Self {
230 match value {
231 BootMode::Unattended => UnattendedBootConfig { status: Switch::On },
232 BootMode::Attended => UnattendedBootConfig {
233 status: Switch::Off,
234 },
235 }
236 }
237}
238
239#[derive(
241 Clone,
242 Copy,
243 Debug,
244 Default,
245 Deserialize,
246 strum::Display,
247 strum::EnumString,
248 strum::EnumIter,
249 strum::IntoStaticStr,
250 Eq,
251 Hash,
252 Ord,
253 PartialEq,
254 PartialOrd,
255 Serialize,
256)]
257#[strum(ascii_case_insensitive)]
258pub enum DecryptMode {
259 AesCbc,
261
262 OaepMd5,
264
265 OaepSha1,
267
268 OaepSha224,
270
271 OaepSha256,
273
274 OaepSha384,
276
277 OaepSha512,
279
280 Pkcs1,
282
283 #[default]
285 Raw,
286}
287
288impl From<DecryptMode> for nethsm_sdk_rs::models::DecryptMode {
289 fn from(value: DecryptMode) -> Self {
290 match value {
291 DecryptMode::AesCbc => Self::AesCbc,
292 DecryptMode::OaepMd5 => Self::OaepMd5,
293 DecryptMode::OaepSha1 => Self::OaepSha1,
294 DecryptMode::OaepSha224 => Self::OaepSha224,
295 DecryptMode::OaepSha256 => Self::OaepSha256,
296 DecryptMode::OaepSha384 => Self::OaepSha384,
297 DecryptMode::OaepSha512 => Self::OaepSha512,
298 DecryptMode::Pkcs1 => Self::Pkcs1,
299 DecryptMode::Raw => Self::Raw,
300 }
301 }
302}
303
304#[derive(
306 Clone,
307 Copy,
308 Debug,
309 Default,
310 Deserialize,
311 strum::Display,
312 strum::EnumString,
313 strum::EnumIter,
314 strum::IntoStaticStr,
315 Eq,
316 Hash,
317 Ord,
318 PartialEq,
319 PartialOrd,
320 Serialize,
321)]
322#[strum(ascii_case_insensitive)]
323pub enum EncryptMode {
324 #[default]
326 AesCbc,
327}
328
329impl From<EncryptMode> for nethsm_sdk_rs::models::EncryptMode {
330 fn from(value: EncryptMode) -> Self {
331 match value {
332 EncryptMode::AesCbc => Self::AesCbc,
333 }
334 }
335}
336
337#[derive(
339 Clone,
340 Copy,
341 Debug,
342 Default,
343 Deserialize,
344 strum::Display,
345 strum::EnumString,
346 strum::EnumIter,
347 strum::IntoStaticStr,
348 Hash,
349 Eq,
350 Ord,
351 PartialEq,
352 PartialOrd,
353 Serialize,
354)]
355#[strum(ascii_case_insensitive)]
356pub enum KeyMechanism {
357 AesDecryptionCbc,
359
360 AesEncryptionCbc,
362
363 EcdsaSignature,
365
366 #[default]
368 EdDsaSignature,
369
370 RsaDecryptionOaepMd5,
372
373 RsaDecryptionOaepSha1,
375
376 RsaDecryptionOaepSha224,
378
379 RsaDecryptionOaepSha256,
381
382 RsaDecryptionOaepSha384,
384
385 RsaDecryptionOaepSha512,
387
388 RsaDecryptionPkcs1,
390
391 RsaDecryptionRaw,
393
394 RsaSignaturePkcs1,
396
397 RsaSignaturePssMd5,
399
400 RsaSignaturePssSha1,
402
403 RsaSignaturePssSha224,
405
406 RsaSignaturePssSha256,
408
409 RsaSignaturePssSha384,
411
412 RsaSignaturePssSha512,
414}
415
416impl KeyMechanism {
417 pub fn curve25519_mechanisms() -> Vec<KeyMechanism> {
419 vec![KeyMechanism::EdDsaSignature]
420 }
421
422 pub fn elliptic_curve_mechanisms() -> Vec<KeyMechanism> {
424 vec![KeyMechanism::EcdsaSignature]
425 }
426
427 pub fn generic_mechanisms() -> Vec<KeyMechanism> {
429 vec![
430 KeyMechanism::AesDecryptionCbc,
431 KeyMechanism::AesEncryptionCbc,
432 ]
433 }
434
435 pub fn rsa_mechanisms() -> Vec<KeyMechanism> {
437 vec![
438 KeyMechanism::RsaDecryptionRaw,
439 KeyMechanism::RsaDecryptionPkcs1,
440 KeyMechanism::RsaDecryptionOaepMd5,
441 KeyMechanism::RsaDecryptionOaepSha1,
442 KeyMechanism::RsaDecryptionOaepSha224,
443 KeyMechanism::RsaDecryptionOaepSha256,
444 KeyMechanism::RsaDecryptionOaepSha384,
445 KeyMechanism::RsaDecryptionOaepSha512,
446 KeyMechanism::RsaSignaturePkcs1,
447 KeyMechanism::RsaSignaturePssMd5,
448 KeyMechanism::RsaSignaturePssSha1,
449 KeyMechanism::RsaSignaturePssSha224,
450 KeyMechanism::RsaSignaturePssSha256,
451 KeyMechanism::RsaSignaturePssSha384,
452 KeyMechanism::RsaSignaturePssSha512,
453 ]
454 }
455}
456
457impl From<KeyMechanism> for nethsm_sdk_rs::models::KeyMechanism {
458 fn from(value: KeyMechanism) -> Self {
459 match value {
460 KeyMechanism::AesDecryptionCbc => Self::AesDecryptionCbc,
461 KeyMechanism::AesEncryptionCbc => Self::AesEncryptionCbc,
462 KeyMechanism::EcdsaSignature => Self::EcdsaSignature,
463 KeyMechanism::EdDsaSignature => Self::EdDsaSignature,
464 KeyMechanism::RsaDecryptionOaepMd5 => Self::RsaDecryptionOaepMd5,
465 KeyMechanism::RsaDecryptionOaepSha1 => Self::RsaDecryptionOaepSha1,
466 KeyMechanism::RsaDecryptionOaepSha224 => Self::RsaDecryptionOaepSha224,
467 KeyMechanism::RsaDecryptionOaepSha256 => Self::RsaDecryptionOaepSha256,
468 KeyMechanism::RsaDecryptionOaepSha384 => Self::RsaDecryptionOaepSha384,
469 KeyMechanism::RsaDecryptionOaepSha512 => Self::RsaDecryptionOaepSha512,
470 KeyMechanism::RsaDecryptionPkcs1 => Self::RsaDecryptionPkcs1,
471 KeyMechanism::RsaDecryptionRaw => Self::RsaDecryptionRaw,
472 KeyMechanism::RsaSignaturePkcs1 => Self::RsaSignaturePkcs1,
473 KeyMechanism::RsaSignaturePssMd5 => Self::RsaSignaturePssMd5,
474 KeyMechanism::RsaSignaturePssSha1 => Self::RsaSignaturePssSha1,
475 KeyMechanism::RsaSignaturePssSha224 => Self::RsaSignaturePssSha224,
476 KeyMechanism::RsaSignaturePssSha256 => Self::RsaSignaturePssSha256,
477 KeyMechanism::RsaSignaturePssSha384 => Self::RsaSignaturePssSha384,
478 KeyMechanism::RsaSignaturePssSha512 => Self::RsaSignaturePssSha512,
479 }
480 }
481}
482
483#[derive(
485 Clone,
486 Copy,
487 Debug,
488 Default,
489 Deserialize,
490 strum::Display,
491 strum::EnumString,
492 strum::EnumIter,
493 strum::IntoStaticStr,
494 Eq,
495 Hash,
496 Ord,
497 PartialEq,
498 PartialOrd,
499 Serialize,
500)]
501#[strum(ascii_case_insensitive)]
502pub enum KeyType {
503 #[default]
505 Curve25519,
506
507 EcP224,
509
510 EcP256,
512
513 EcP384,
515
516 EcP521,
518
519 Generic,
521
522 Rsa,
524}
525
526impl From<KeyType> for nethsm_sdk_rs::models::KeyType {
527 fn from(value: KeyType) -> Self {
528 match value {
529 KeyType::Curve25519 => Self::Curve25519,
530 KeyType::EcP224 => Self::EcP224,
531 KeyType::EcP256 => Self::EcP256,
532 KeyType::EcP384 => Self::EcP384,
533 KeyType::EcP521 => Self::EcP521,
534 KeyType::Generic => Self::Generic,
535 KeyType::Rsa => Self::Rsa,
536 }
537 }
538}
539
540impl From<nethsm_sdk_rs::models::KeyType> for KeyType {
541 fn from(value: nethsm_sdk_rs::models::KeyType) -> Self {
542 use nethsm_sdk_rs::models::KeyType;
543 match value {
544 KeyType::Curve25519 => Self::Curve25519,
545 KeyType::EcP224 => Self::EcP224,
546 KeyType::EcP256 => Self::EcP256,
547 KeyType::EcP384 => Self::EcP384,
548 KeyType::EcP521 => Self::EcP521,
549 KeyType::Generic => Self::Generic,
550 KeyType::Rsa => Self::Rsa,
551 }
552 }
553}
554
555#[derive(
557 Clone,
558 Copy,
559 Debug,
560 Default,
561 Deserialize,
562 strum::Display,
563 strum::EnumString,
564 strum::EnumIter,
565 strum::IntoStaticStr,
566 Eq,
567 Hash,
568 Ord,
569 PartialEq,
570 PartialOrd,
571 Serialize,
572)]
573#[strum(ascii_case_insensitive)]
574pub enum KeyFormat {
575 Pem,
577
578 #[default]
580 Der,
581}
582
583#[derive(
585 Clone,
586 Copy,
587 Debug,
588 Default,
589 Deserialize,
590 strum::Display,
591 strum::EnumString,
592 strum::EnumIter,
593 strum::IntoStaticStr,
594 Eq,
595 Hash,
596 Ord,
597 PartialEq,
598 PartialOrd,
599 Serialize,
600)]
601#[strum(ascii_case_insensitive)]
602pub enum LogLevel {
603 Debug,
605
606 Error,
608
609 #[default]
611 Info,
612
613 Warning,
615}
616
617impl From<LogLevel> for nethsm_sdk_rs::models::LogLevel {
618 fn from(value: LogLevel) -> Self {
619 match value {
620 LogLevel::Debug => Self::Debug,
621 LogLevel::Error => Self::Error,
622 LogLevel::Info => Self::Info,
623 LogLevel::Warning => Self::Warning,
624 }
625 }
626}
627
628#[derive(
630 Clone,
631 Copy,
632 Debug,
633 Default,
634 Deserialize,
635 strum::Display,
636 strum::EnumString,
637 strum::EnumIter,
638 strum::IntoStaticStr,
639 Eq,
640 Hash,
641 Ord,
642 PartialEq,
643 PartialOrd,
644 Serialize,
645)]
646#[strum(ascii_case_insensitive)]
647pub enum TlsKeyType {
648 Curve25519,
650
651 EcP224,
653
654 EcP256,
656
657 EcP384,
659
660 EcP521,
662
663 #[default]
665 Rsa,
666}
667
668impl From<TlsKeyType> for nethsm_sdk_rs::models::TlsKeyType {
669 fn from(value: TlsKeyType) -> Self {
670 match value {
671 TlsKeyType::Curve25519 => Self::Curve25519,
672 TlsKeyType::EcP224 => Self::EcP224,
673 TlsKeyType::EcP256 => Self::EcP256,
674 TlsKeyType::EcP384 => Self::EcP384,
675 TlsKeyType::EcP521 => Self::EcP521,
676 TlsKeyType::Rsa => Self::Rsa,
677 }
678 }
679}
680
681#[derive(
683 Clone,
684 Copy,
685 Debug,
686 Default,
687 Deserialize,
688 strum::Display,
689 strum::EnumString,
690 strum::EnumIter,
691 strum::IntoStaticStr,
692 Eq,
693 PartialEq,
694 Ord,
695 PartialOrd,
696 Hash,
697 Serialize,
698)]
699#[strum(ascii_case_insensitive)]
700pub enum UserRole {
701 Administrator,
703 Backup,
705 Metrics,
707 #[default]
709 Operator,
710}
711
712impl From<UserRole> for nethsm_sdk_rs::models::UserRole {
713 fn from(value: UserRole) -> Self {
714 match value {
715 UserRole::Administrator => Self::Administrator,
716 UserRole::Backup => Self::Backup,
717 UserRole::Metrics => Self::Metrics,
718 UserRole::Operator => Self::Operator,
719 }
720 }
721}
722
723#[cfg(test)]
724mod tests {
725 use std::str::FromStr;
726
727 use rstest::rstest;
728 use testresult::TestResult;
729
730 use super::*;
731
732 #[rstest]
733 #[case("raw", Some(DecryptMode::Raw))]
734 #[case("pkcs1", Some(DecryptMode::Pkcs1))]
735 #[case("oaepmd5", Some(DecryptMode::OaepMd5))]
736 #[case("oaepsha1", Some(DecryptMode::OaepSha1))]
737 #[case("oaepsha224", Some(DecryptMode::OaepSha224))]
738 #[case("oaepsha256", Some(DecryptMode::OaepSha256))]
739 #[case("oaepsha384", Some(DecryptMode::OaepSha384))]
740 #[case("oaepsha512", Some(DecryptMode::OaepSha512))]
741 #[case("aescbc", Some(DecryptMode::AesCbc))]
742 #[case("foo", None)]
743 fn decryptmode_fromstr(
744 #[case] input: &str,
745 #[case] expected: Option<DecryptMode>,
746 ) -> TestResult {
747 if let Some(expected) = expected {
748 assert_eq!(DecryptMode::from_str(input)?, expected);
749 } else {
750 assert!(DecryptMode::from_str(input).is_err());
751 }
752 Ok(())
753 }
754
755 #[rstest]
756 #[case("aescbc", Some(EncryptMode::AesCbc))]
757 #[case("foo", None)]
758 fn encryptmode_fromstr(
759 #[case] input: &str,
760 #[case] expected: Option<EncryptMode>,
761 ) -> TestResult {
762 if let Some(expected) = expected {
763 assert_eq!(EncryptMode::from_str(input)?, expected);
764 } else {
765 assert!(EncryptMode::from_str(input).is_err());
766 }
767 Ok(())
768 }
769
770 #[rstest]
771 #[case("rsadecryptionraw", Some(KeyMechanism::RsaDecryptionRaw))]
772 #[case("rsadecryptionpkcs1", Some(KeyMechanism::RsaDecryptionPkcs1))]
773 #[case("rsadecryptionoaepmd5", Some(KeyMechanism::RsaDecryptionOaepMd5))]
774 #[case("rsadecryptionoaepsha1", Some(KeyMechanism::RsaDecryptionOaepSha1))]
775 #[case("rsadecryptionoaepsha224", Some(KeyMechanism::RsaDecryptionOaepSha224))]
776 #[case("rsadecryptionoaepsha256", Some(KeyMechanism::RsaDecryptionOaepSha256))]
777 #[case("rsadecryptionoaepsha384", Some(KeyMechanism::RsaDecryptionOaepSha384))]
778 #[case("rsadecryptionoaepsha512", Some(KeyMechanism::RsaDecryptionOaepSha512))]
779 #[case("rsadecryptionoaepsha512", Some(KeyMechanism::RsaDecryptionOaepSha512))]
780 #[case("rsasignaturepkcs1", Some(KeyMechanism::RsaSignaturePkcs1))]
781 #[case("rsasignaturepssmd5", Some(KeyMechanism::RsaSignaturePssMd5))]
782 #[case("rsasignaturepsssha1", Some(KeyMechanism::RsaSignaturePssSha1))]
783 #[case("rsasignaturepsssha224", Some(KeyMechanism::RsaSignaturePssSha224))]
784 #[case("rsasignaturepsssha256", Some(KeyMechanism::RsaSignaturePssSha256))]
785 #[case("rsasignaturepsssha384", Some(KeyMechanism::RsaSignaturePssSha384))]
786 #[case("rsasignaturepsssha512", Some(KeyMechanism::RsaSignaturePssSha512))]
787 #[case("eddsasignature", Some(KeyMechanism::EdDsaSignature))]
788 #[case("ecdsasignature", Some(KeyMechanism::EcdsaSignature))]
789 #[case("aesencryptioncbc", Some(KeyMechanism::AesEncryptionCbc))]
790 #[case("aesdecryptioncbc", Some(KeyMechanism::AesDecryptionCbc))]
791 #[case("foo", None)]
792 fn keymechanism_fromstr(
793 #[case] input: &str,
794 #[case] expected: Option<KeyMechanism>,
795 ) -> TestResult {
796 if let Some(expected) = expected {
797 assert_eq!(KeyMechanism::from_str(input)?, expected);
798 } else {
799 assert!(KeyMechanism::from_str(input).is_err());
800 }
801 Ok(())
802 }
803
804 #[rstest]
805 #[case("rsa", Some(KeyType::Rsa))]
806 #[case("curve25519", Some(KeyType::Curve25519))]
807 #[case("ecp224", Some(KeyType::EcP224))]
808 #[case("ecp256", Some(KeyType::EcP256))]
809 #[case("ecp384", Some(KeyType::EcP384))]
810 #[case("ecp521", Some(KeyType::EcP521))]
811 #[case("generic", Some(KeyType::Generic))]
812 #[case("foo", None)]
813 fn keytype_fromstr(#[case] input: &str, #[case] expected: Option<KeyType>) -> TestResult {
814 if let Some(expected) = expected {
815 assert_eq!(KeyType::from_str(input)?, expected);
816 } else {
817 assert!(KeyType::from_str(input).is_err());
818 }
819 Ok(())
820 }
821
822 #[rstest]
823 #[case("ecdsap224", Some(SignatureType::EcdsaP224))]
824 #[case("ecdsap256", Some(SignatureType::EcdsaP256))]
825 #[case("ecdsap384", Some(SignatureType::EcdsaP384))]
826 #[case("ecdsap521", Some(SignatureType::EcdsaP521))]
827 #[case("eddsa", Some(SignatureType::EdDsa))]
828 #[case("pkcs1", Some(SignatureType::Pkcs1))]
829 #[case("pssmd5", Some(SignatureType::PssMd5))]
830 #[case("psssha1", Some(SignatureType::PssSha1))]
831 #[case("psssha224", Some(SignatureType::PssSha224))]
832 #[case("psssha256", Some(SignatureType::PssSha256))]
833 #[case("psssha384", Some(SignatureType::PssSha384))]
834 #[case("psssha512", Some(SignatureType::PssSha512))]
835 #[case("foo", None)]
836 fn signaturetype_fromstr(
837 #[case] input: &str,
838 #[case] expected: Option<SignatureType>,
839 ) -> TestResult {
840 if let Some(expected) = expected {
841 assert_eq!(SignatureType::from_str(input)?, expected);
842 } else {
843 assert!(SignatureType::from_str(input).is_err());
844 }
845 Ok(())
846 }
847
848 #[rstest]
849 #[case("rsa", Some(TlsKeyType::Rsa))]
850 #[case("curve25519", Some(TlsKeyType::Curve25519))]
851 #[case("ecp224", Some(TlsKeyType::EcP224))]
852 #[case("ecp256", Some(TlsKeyType::EcP256))]
853 #[case("ecp384", Some(TlsKeyType::EcP384))]
854 #[case("ecp521", Some(TlsKeyType::EcP521))]
855 #[case("foo", None)]
856 fn tlskeytype_fromstr(#[case] input: &str, #[case] expected: Option<TlsKeyType>) -> TestResult {
857 if let Some(expected) = expected {
858 assert_eq!(TlsKeyType::from_str(input)?, expected);
859 } else {
860 assert!(TlsKeyType::from_str(input).is_err());
861 }
862 Ok(())
863 }
864
865 #[rstest]
866 #[case("administrator", Some(UserRole::Administrator))]
867 #[case("backup", Some(UserRole::Backup))]
868 #[case("metrics", Some(UserRole::Metrics))]
869 #[case("operator", Some(UserRole::Operator))]
870 #[case("foo", None)]
871 fn userrole_fromstr(#[case] input: &str, #[case] expected: Option<UserRole>) -> TestResult {
872 if let Some(expected) = expected {
873 assert_eq!(UserRole::from_str(input)?, expected);
874 } else {
875 assert!(UserRole::from_str(input).is_err());
876 }
877 Ok(())
878 }
879}