mirror of
https://github.com/NLnetLabs/krill.git
synced 2026-09-22 17:34:56 +02:00
Show repo state and published objects through API and CLI. (#104)
This commit is contained in:
+10
-2
@@ -14,6 +14,7 @@ use crate::commons::remote::rfc8183;
|
||||
use crate::commons::remote::rfc8183::RepositoryResponse;
|
||||
use crate::commons::util::httpclient;
|
||||
use crate::constants::KRILL_CLI_API_ENV;
|
||||
use commons::api::CaRepoDetails;
|
||||
|
||||
/// Command line tool for Krill admin tasks
|
||||
pub struct KrillClient {
|
||||
@@ -89,8 +90,8 @@ impl KrillClient {
|
||||
Ok(ApiResponse::Rfc8183ChildRequest(req))
|
||||
}
|
||||
|
||||
CaCommand::PublisherRequest(handle) => {
|
||||
let uri = format!("api/v1/cas/{}/publisher_request", handle);
|
||||
CaCommand::RepoPublisherRequest(handle) => {
|
||||
let uri = format!("api/v1/cas/{}/repo/publisher_request", handle);
|
||||
let req: PublisherRequest = self.get_json(&uri)?;
|
||||
let (handle, id_cert) = req.unpack();
|
||||
let req = rfc8183::PublisherRequest::new(None, handle, id_cert);
|
||||
@@ -98,6 +99,13 @@ impl KrillClient {
|
||||
Ok(ApiResponse::Rfc8183PublisherRequest(req))
|
||||
}
|
||||
|
||||
CaCommand::RepoDetails(handle) => {
|
||||
let uri = format!("api/v1/cas/{}/repo/", handle);
|
||||
let details: CaRepoDetails = self.get_json(&uri)?;
|
||||
|
||||
Ok(ApiResponse::RepoDetails(details))
|
||||
}
|
||||
|
||||
CaCommand::AddParent(handle, parent) => {
|
||||
let uri = format!("api/v1/cas/{}/parents", handle);
|
||||
self.post_json(&uri, parent)?;
|
||||
|
||||
+24
-2
@@ -475,10 +475,20 @@ impl Options {
|
||||
app.subcommand(sub)
|
||||
}
|
||||
|
||||
fn make_case_repo_show_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||
let mut sub = SubCommand::with_name("show").about("Show current repo config and state.");
|
||||
|
||||
sub = Self::add_general_args(sub);
|
||||
sub = Self::add_my_ca_arg(sub);
|
||||
|
||||
app.subcommand(sub)
|
||||
}
|
||||
|
||||
fn make_cas_repo_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||
let mut sub = SubCommand::with_name("repo").about("Manage the repository for your CA.");
|
||||
|
||||
sub = Self::make_case_repo_request_sc(sub);
|
||||
sub = Self::make_case_repo_show_sc(sub);
|
||||
|
||||
app.subcommand(sub)
|
||||
}
|
||||
@@ -871,7 +881,16 @@ impl Options {
|
||||
let general_args = GeneralArgs::from_matches(matches)?;
|
||||
let my_ca = Self::parse_my_ca(matches)?;
|
||||
|
||||
let command = Command::CertAuth(CaCommand::PublisherRequest(my_ca));
|
||||
let command = Command::CertAuth(CaCommand::RepoPublisherRequest(my_ca));
|
||||
|
||||
Ok(Options::make(general_args, command))
|
||||
}
|
||||
|
||||
fn parse_matches_cas_repo_details(matches: &ArgMatches) -> Result<Options, Error> {
|
||||
let general_args = GeneralArgs::from_matches(matches)?;
|
||||
let my_ca = Self::parse_my_ca(matches)?;
|
||||
|
||||
let command = Command::CertAuth(CaCommand::RepoDetails(my_ca));
|
||||
|
||||
Ok(Options::make(general_args, command))
|
||||
}
|
||||
@@ -879,6 +898,8 @@ impl Options {
|
||||
fn parse_matches_cas_repo(matches: &ArgMatches) -> Result<Options, Error> {
|
||||
if let Some(m) = matches.subcommand_matches("request") {
|
||||
Self::parse_matches_cas_repo_request(m)
|
||||
} else if let Some(m) = matches.subcommand_matches("show") {
|
||||
Self::parse_matches_cas_repo_details(m)
|
||||
} else {
|
||||
Err(Error::UnrecognisedSubCommand)
|
||||
}
|
||||
@@ -1013,7 +1034,8 @@ pub enum CaCommand {
|
||||
ChildRequest(Handle),
|
||||
|
||||
// Get the RFC8183 publisher request
|
||||
PublisherRequest(Handle),
|
||||
RepoPublisherRequest(Handle),
|
||||
RepoDetails(Handle),
|
||||
|
||||
// Add a parent to this CA
|
||||
AddParent(Handle, ParentCaReq),
|
||||
|
||||
+53
-2
@@ -1,8 +1,8 @@
|
||||
use std::str::{from_utf8_unchecked, FromStr};
|
||||
|
||||
use crate::commons::api::{
|
||||
CertAuthHistory, CertAuthInfo, CertAuthList, CurrentObjects, ParentCaContact, PublisherDetails,
|
||||
PublisherList, RouteAuthorization,
|
||||
CaRepoDetails, CertAuthHistory, CertAuthInfo, CertAuthList, CurrentObjects, CurrentRepoState,
|
||||
ParentCaContact, PubServerContact, PublisherDetails, PublisherList, RouteAuthorization,
|
||||
};
|
||||
use crate::commons::remote::api::ClientInfo;
|
||||
use crate::commons::remote::rfc8183;
|
||||
@@ -30,6 +30,8 @@ pub enum ApiResponse {
|
||||
Rfc8183ChildRequest(rfc8183::ChildRequest),
|
||||
Rfc8183PublisherRequest(rfc8183::PublisherRequest),
|
||||
|
||||
RepoDetails(CaRepoDetails),
|
||||
|
||||
Empty, // Typically a successful post just gets an empty 200 response
|
||||
GenericBody(String), // For when the server echos Json to a successful post
|
||||
}
|
||||
@@ -58,6 +60,7 @@ impl ApiResponse {
|
||||
ApiResponse::Rfc8183ChildRequest(req) => Ok(Some(req.report(fmt)?)),
|
||||
ApiResponse::Rfc8183PublisherRequest(req) => Ok(Some(req.report(fmt)?)),
|
||||
ApiResponse::Rfc8183RepositoryResponse(res) => Ok(Some(res.report(fmt)?)),
|
||||
ApiResponse::RepoDetails(details) => Ok(Some(details.report(fmt)?)),
|
||||
ApiResponse::GenericBody(body) => Ok(Some(body.clone())),
|
||||
ApiResponse::Empty => Ok(None),
|
||||
}
|
||||
@@ -353,3 +356,51 @@ impl Report for Vec<RouteAuthorization> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Report for CaRepoDetails {
|
||||
fn report(&self, format: ReportFormat) -> Result<String, ReportError> {
|
||||
match format {
|
||||
ReportFormat::Json => Ok(serde_json::to_string_pretty(self).unwrap()),
|
||||
ReportFormat::Default | ReportFormat::Text => {
|
||||
let mut res = String::new();
|
||||
|
||||
res.push_str("Repository Details:\n");
|
||||
match self.contact() {
|
||||
PubServerContact::Embedded(repo_info) => {
|
||||
res.push_str(" type: embedded\n");
|
||||
res.push_str(&format!(" base_uri: {}\n", repo_info.base_uri()));
|
||||
res.push_str(&format!(" rpki_notify: {}\n", repo_info.rpki_notify()));
|
||||
}
|
||||
PubServerContact::Rfc8181(response) => {
|
||||
res.push_str(" type: remote\n");
|
||||
res.push_str(&format!(" service uri: {}\n", response.service_uri()));
|
||||
let repo_info = response.repo_info();
|
||||
res.push_str(&format!(" base_uri: {}\n", repo_info.base_uri()));
|
||||
res.push_str(&format!(" rpki_notify: {}\n", repo_info.rpki_notify()));
|
||||
}
|
||||
}
|
||||
|
||||
res.push_str("\n");
|
||||
res.push_str("Currently published:\n");
|
||||
match self.state() {
|
||||
CurrentRepoState::Error(e) => {
|
||||
res.push_str(&format!(" Error contacting repo! => {}", e));
|
||||
}
|
||||
CurrentRepoState::List(list) => {
|
||||
let elements = list.elements();
|
||||
if elements.is_empty() {
|
||||
res.push_str(" <nothing>\n");
|
||||
} else {
|
||||
for el in elements.iter() {
|
||||
res.push_str(&format!(" {} {}\n", el.hash(), el.uri()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
_ => Err(ReportError::UnsupportedFormat),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +316,7 @@ impl PublisherClientRequest {
|
||||
|
||||
//------------ PubServerInfo -------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Display, Serialize)]
|
||||
#[derive(Clone, Debug, Deserialize, Display, Eq, PartialEq, Serialize)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum PubServerContact {
|
||||
#[display(fmt = "Embedded server.")]
|
||||
@@ -331,10 +331,21 @@ impl PubServerContact {
|
||||
PubServerContact::Embedded(info)
|
||||
}
|
||||
|
||||
pub fn is_embedded(&self) -> bool {
|
||||
match self {
|
||||
PubServerContact::Embedded(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rfc8183(response: rfc8183::RepositoryResponse) -> Self {
|
||||
PubServerContact::Rfc8181(response)
|
||||
}
|
||||
|
||||
pub fn is_rfc8183(&self) -> bool {
|
||||
!self.is_embedded()
|
||||
}
|
||||
|
||||
pub fn repo_info(&self) -> &RepoInfo {
|
||||
match self {
|
||||
PubServerContact::Embedded(info) => info,
|
||||
|
||||
+49
-1
@@ -23,7 +23,8 @@ use crate::commons::api::admin::{Handle, ParentCaContact};
|
||||
use crate::commons::api::publication;
|
||||
use crate::commons::api::publication::Publish;
|
||||
use crate::commons::api::{
|
||||
Base64, HexEncodedHash, IssuanceRequest, ParentHandle, RequestResourceLimit, RouteAuthorization,
|
||||
Base64, HexEncodedHash, IssuanceRequest, ListReply, ParentHandle, PubServerContact,
|
||||
RequestResourceLimit, RouteAuthorization,
|
||||
};
|
||||
use crate::commons::eventsourcing::AggregateHistory;
|
||||
use crate::commons::remote::id::IdCert;
|
||||
@@ -1577,6 +1578,53 @@ impl fmt::Display for ResourceClassKeysInfo {
|
||||
}
|
||||
}
|
||||
|
||||
//------------ CaRepoDetails -------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub enum CurrentRepoState {
|
||||
List(ListReply),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
impl CurrentRepoState {
|
||||
pub fn list(list: ListReply) -> Self {
|
||||
CurrentRepoState::List(list)
|
||||
}
|
||||
|
||||
pub fn error(e: impl fmt::Display) -> Self {
|
||||
CurrentRepoState::Error(e.to_string())
|
||||
}
|
||||
|
||||
pub fn as_list(&self) -> &ListReply {
|
||||
match &self {
|
||||
CurrentRepoState::List(list) => list,
|
||||
CurrentRepoState::Error(e) => panic!("{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct contains the API details for the configure Repository server,
|
||||
/// and objects published there, for a CA.
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub struct CaRepoDetails {
|
||||
contact: PubServerContact,
|
||||
state: CurrentRepoState,
|
||||
}
|
||||
|
||||
impl CaRepoDetails {
|
||||
pub fn new(contact: PubServerContact, state: CurrentRepoState) -> Self {
|
||||
CaRepoDetails { contact, state }
|
||||
}
|
||||
|
||||
pub fn contact(&self) -> &PubServerContact {
|
||||
&self.contact
|
||||
}
|
||||
|
||||
pub fn state(&self) -> &CurrentRepoState {
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
|
||||
//------------ ResSetErr -----------------------------------------------------
|
||||
|
||||
#[derive(Clone, Debug, Display, Eq, PartialEq)]
|
||||
|
||||
@@ -176,12 +176,6 @@ impl From<String> for HexEncodedHash {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for HexEncodedHash {
|
||||
fn to_string(&self) -> String {
|
||||
unsafe { String::from_utf8_unchecked(self.0.to_vec()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for HexEncodedHash {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -201,6 +195,13 @@ impl<'de> Deserialize<'de> for HexEncodedHash {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HexEncodedHash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let string = unsafe { String::from_utf8_unchecked(self.0.to_vec()) };
|
||||
write!(f, "{}", string)
|
||||
}
|
||||
}
|
||||
|
||||
//------------ Link ----------------------------------------------------------
|
||||
|
||||
/// Defines a link element to include as part of a links array in a Json
|
||||
|
||||
+15
-1
@@ -69,7 +69,7 @@ pub fn health() -> HttpResponse {
|
||||
|
||||
/// Returns the server health.
|
||||
pub fn api_health(server: web::Data<AppServer>, auth: Auth) -> HttpResponse {
|
||||
if_api_allowed(&server, &auth, || api_ok())
|
||||
if_api_allowed(&server, &auth, api_ok)
|
||||
}
|
||||
|
||||
fn if_allowed<F>(allowed: bool, op: F) -> HttpResponse
|
||||
@@ -360,6 +360,20 @@ pub fn ca_publisher_req(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ca_repo_details(
|
||||
server: web::Data<AppServer>,
|
||||
auth: Auth,
|
||||
handle: Path<Handle>,
|
||||
) -> HttpResponse {
|
||||
let handle = handle.into_inner();
|
||||
if_api_allowed(&server, &auth, || {
|
||||
match server.read().ca_repo_details(&handle) {
|
||||
Some(req) => render_json(req),
|
||||
None => api_not_found(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ca_add_parent(
|
||||
server: web::Data<AppServer>,
|
||||
auth: Auth,
|
||||
|
||||
@@ -78,7 +78,11 @@ pub fn start(config: &Config) -> Result<(), Error> {
|
||||
.route("/cas/{ca}/id", post().to(ca_update_id))
|
||||
.route("/cas/{ca}/history", get().to(ca_history))
|
||||
.route("/cas/{ca}/child_request", get().to(ca_child_req))
|
||||
.route("/cas/{ca}/publisher_request", get().to(ca_publisher_req))
|
||||
.route("/cas/{ca}/repo/", get().to(ca_repo_details))
|
||||
.route(
|
||||
"/cas/{ca}/repo/publisher_request",
|
||||
get().to(ca_publisher_req),
|
||||
)
|
||||
.route("/cas/{ca}/parents", post().to(ca_add_parent))
|
||||
.route("/cas/{ca}/parents/{parent}", post().to(ca_update_parent))
|
||||
.route("/cas/{ca}/parents/{parent}", delete().to(ca_remove_parent))
|
||||
|
||||
@@ -9,10 +9,11 @@ use rpki::cert::Cert;
|
||||
use rpki::uri;
|
||||
|
||||
use crate::commons::api::{
|
||||
AddChildRequest, CertAuthHistory, CertAuthInfo, CertAuthInit, CertAuthList, ChildCaInfo,
|
||||
ChildHandle, Handle, ListReply, ParentCaContact, ParentCaReq, ParentHandle, PublishDelta,
|
||||
PublisherDetails, PublisherHandle, PublisherRequest, RepoInfo, RouteAuthorizationUpdates,
|
||||
TaCertDetails, Token, UpdateChildRequest,
|
||||
AddChildRequest, CaRepoDetails, CertAuthHistory, CertAuthInfo, CertAuthInit, CertAuthList,
|
||||
ChildCaInfo, ChildHandle, CurrentRepoState, Handle, ListReply, ParentCaContact, ParentCaReq,
|
||||
ParentHandle, PubServerContact, PublishDelta, PublisherDetails, PublisherHandle,
|
||||
PublisherRequest, RepoInfo, RouteAuthorizationUpdates, TaCertDetails, Token,
|
||||
UpdateChildRequest,
|
||||
};
|
||||
use crate::commons::remote::rfc8183::{ChildRequest, RepositoryResponse};
|
||||
use crate::commons::remote::sigmsg::SignedMessage;
|
||||
@@ -350,6 +351,32 @@ impl KrillServer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the info about the configure repository server for a given Ca,
|
||||
/// and the actual objects published there, as reported by a list reply.
|
||||
pub fn ca_repo_details(&self, handle: &Handle) -> Option<CaRepoDetails> {
|
||||
self.caserver
|
||||
.get_ca(handle)
|
||||
.map(|ca| {
|
||||
let contact = ca.pub_server_contact().clone();
|
||||
|
||||
let state = match &contact {
|
||||
PubServerContact::Embedded(_) => match self.pubserver.list(handle) {
|
||||
Err(e) => CurrentRepoState::error(e),
|
||||
Ok(list) => CurrentRepoState::list(list),
|
||||
},
|
||||
PubServerContact::Rfc8181(_response) => {
|
||||
match self.caserver.send_rfc8181_list(handle) {
|
||||
Err(e) => CurrentRepoState::error(e),
|
||||
Ok(list) => CurrentRepoState::list(list),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CaRepoDetails::new(contact, state)
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub fn ca_update_id(&self, handle: Handle) -> EmptyRes {
|
||||
Ok(self.caserver.ca_update_id(handle)?)
|
||||
}
|
||||
|
||||
+72
-37
@@ -1,4 +1,5 @@
|
||||
extern crate krill;
|
||||
extern crate pretty;
|
||||
extern crate rpki;
|
||||
|
||||
use std::path::PathBuf;
|
||||
@@ -7,16 +8,19 @@ use std::str::FromStr;
|
||||
use rpki::crypto::{PublicKeyFormat, Signer};
|
||||
use rpki::uri;
|
||||
|
||||
use krill::cli::options::{Command, PublishersCommand};
|
||||
use krill::cli::options::{CaCommand, Command, PublishersCommand};
|
||||
use krill::cli::report::ApiResponse;
|
||||
use krill::commons::api::rrdp::CurrentObjects;
|
||||
use krill::commons::api::{Handle, PublisherHandle};
|
||||
use krill::commons::api::{CaRepoDetails, Handle, ParentCaReq, PublisherHandle, ResourceSet};
|
||||
use krill::commons::remote::builder::IdCertBuilder;
|
||||
use krill::commons::util::softsigner::OpenSslSigner;
|
||||
use krill::daemon::ca::ta_handle;
|
||||
use krill::daemon::test::{
|
||||
krill_admin, krill_pubd_admin, start_krill_pubd_server, test_with_krill_server,
|
||||
add_child_to_ta_embedded, add_parent_to_ca, init_child, krill_admin, krill_pubd_admin,
|
||||
start_krill_pubd_server, test_with_krill_server, wait_for_current_resources,
|
||||
};
|
||||
use krill::pubd::Publisher;
|
||||
use pretty::Doc::Append;
|
||||
|
||||
fn publisher(work_dir: &PathBuf, base_uri: &str) -> Publisher {
|
||||
let mut signer = OpenSslSigner::build(work_dir).unwrap();
|
||||
@@ -52,6 +56,14 @@ fn details_publisher(publisher: &PublisherHandle) -> ApiResponse {
|
||||
krill_pubd_admin(command)
|
||||
}
|
||||
|
||||
fn repo_details(ca: &Handle) -> CaRepoDetails {
|
||||
let command = Command::CertAuth(CaCommand::RepoDetails(ca.clone()));
|
||||
match krill_admin(command) {
|
||||
ApiResponse::RepoDetails(details) => details,
|
||||
_ => panic!("Expected repo details"),
|
||||
}
|
||||
}
|
||||
|
||||
/// This tests that you can run krill with an embedded TA and CA, and
|
||||
/// have the CA publish at another krill instance which is is set up
|
||||
/// as a publication server only (i.e. it just has no TA and CAs).
|
||||
@@ -60,44 +72,67 @@ fn remote_publication() {
|
||||
test_with_krill_server(|d| {
|
||||
start_krill_pubd_server();
|
||||
|
||||
let alice_handle = Handle::from_str_unsafe("alice");
|
||||
let alice = publisher(&d, "rsync://localhost/repo/0/alice/");
|
||||
let ta_handle = ta_handle();
|
||||
|
||||
// Add client "alice"
|
||||
add_publisher(&alice_handle, &alice);
|
||||
let child = Handle::from_str_unsafe("child");
|
||||
|
||||
// Find "alice" in list
|
||||
let res = list_publishers();
|
||||
match res {
|
||||
ApiResponse::PublisherList(list) => assert!(list
|
||||
.publishers()
|
||||
.iter()
|
||||
.find(|p| { p.id() == "alice" })
|
||||
.is_some()),
|
||||
_ => panic!("Expected publisher list"),
|
||||
// Set up child as a child of the TA
|
||||
{
|
||||
init_child(&child);
|
||||
let child_resources = ResourceSet::from_strs("", "10.0.0.0/16", "").unwrap();
|
||||
|
||||
let parent = {
|
||||
let parent_contact = add_child_to_ta_embedded(&child, child_resources.clone());
|
||||
ParentCaReq::new(ta_handle.clone(), parent_contact)
|
||||
};
|
||||
|
||||
add_parent_to_ca(&child, parent);
|
||||
wait_for_current_resources(&child, &child_resources);
|
||||
}
|
||||
|
||||
// Find details for alice
|
||||
let details_res = details_publisher(&alice_handle);
|
||||
match details_res {
|
||||
ApiResponse::PublisherDetails(details) => {
|
||||
assert_eq!(&alice_handle, details.handle());
|
||||
}
|
||||
_ => panic!("Expected details"),
|
||||
}
|
||||
// Child should now publish using the embedded repo
|
||||
let child_repo_details = repo_details(&child);
|
||||
assert!(child_repo_details.contact().is_embedded());
|
||||
let list = child_repo_details.state().as_list();
|
||||
assert_eq!(2, list.elements().len());
|
||||
|
||||
// Remove alice
|
||||
remove_publisher(&alice_handle);
|
||||
|
||||
// Expect that alice has been removed
|
||||
let res = list_publishers();
|
||||
match res {
|
||||
ApiResponse::PublisherList(list) => assert!(list
|
||||
.publishers()
|
||||
.iter()
|
||||
.find(|p| { p.id() == "alice" })
|
||||
.is_none()),
|
||||
_ => panic!("Expected publisher list"),
|
||||
}
|
||||
// let alice = publisher(&d, "rsync://localhost/repo/0/child/");
|
||||
//
|
||||
// // Add client "alice"
|
||||
// add_publisher(&alice_handle, &alice);
|
||||
//
|
||||
// // Find "alice" in list
|
||||
// let res = list_publishers();
|
||||
// match res {
|
||||
// ApiResponse::PublisherList(list) => assert!(list
|
||||
// .publishers()
|
||||
// .iter()
|
||||
// .find(|p| { p.id() == "alice" })
|
||||
// .is_some()),
|
||||
// _ => panic!("Expected publisher list"),
|
||||
// }
|
||||
//
|
||||
// // Find details for alice
|
||||
// let details_res = details_publisher(&alice_handle);
|
||||
// match details_res {
|
||||
// ApiResponse::PublisherDetails(details) => {
|
||||
// assert_eq!(&alice_handle, details.handle());
|
||||
// }
|
||||
// _ => panic!("Expected details"),
|
||||
// }
|
||||
//
|
||||
// // Remove alice
|
||||
// remove_publisher(&alice_handle);
|
||||
//
|
||||
// // Expect that alice has been removed
|
||||
// let res = list_publishers();
|
||||
// match res {
|
||||
// ApiResponse::PublisherList(list) => assert!(list
|
||||
// .publishers()
|
||||
// .iter()
|
||||
// .find(|p| { p.id() == "alice" })
|
||||
// .is_none()),
|
||||
// _ => panic!("Expected publisher list"),
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user