<commit_before>use crate::{
    add_team_to_crate,
    builders::{CrateBuilder, PublishBuilder},
    new_team,
    util::{MockCookieUser, MockTokenUser, RequestHelper},
    TestApp,
};
use cargo_registry::{
    models::Crate,
    views::{EncodableCrateOwnerInvitation, EncodableOwner, InvitationResponse},
};

use diesel::prelude::*;

#[derive(Deserialize)]
struct TeamResponse {
    teams: Vec<EncodableOwner>,
}
#[derive(Deserialize)]
struct UserResponse {
    users: Vec<EncodableOwner>,
}
#[derive(Deserialize)]
struct InvitationListResponse {
    crate_owner_invitations: Vec<EncodableCrateOwnerInvitation>,
}

// Implementing locally for now, unless these are needed elsewhere
impl MockCookieUser {
    /// As the currently logged in user, accept an invitation to become an owner of the named
    /// crate.
    fn accept_ownership_invitation(&self, krate_name: &str, krate_id: i32) {
        let body = json!({
            "crate_owner_invite": {
                "invited_by_username": "",
                "crate_name": krate_name,
                "crate_id": krate_id,
                "created_at": "",
                "accepted": true
            }
        });

        #[derive(Deserialize)]
        struct CrateOwnerInvitation {
            crate_owner_invitation: InvitationResponse,
        }

        let url = format!("/api/v1/me/crate_owner_invitations/{}", krate_id);
        let crate_owner_invite: CrateOwnerInvitation =
            self.put(&url, body.to_string().as_bytes()).good();
        assert!(crate_owner_invite.crate_owner_invitation.accepted);
        assert_eq!(crate_owner_invite.crate_owner_invitation.crate_id, krate_id);
    }

    /// As the currently logged in user, decline an invitation to become an owner of the named
    /// crate.
    fn decline_ownership_invitation(&self, krate_name: &str, krate_id: i32) {
        let body = json!({
            "crate_owner_invite": {
                "invited_by_username": "",
                "crate_name": krate_name,
                "crate_id": krate_id,
                "created_at": "",
                "accepted": false
            }
        });

        #[derive(Deserialize)]
        struct CrateOwnerInvitation {
            crate_owner_invitation: InvitationResponse,
        }

        let url = format!("/api/v1/me/crate_owner_invitations/{}", krate_id);
        let crate_owner_invite: CrateOwnerInvitation =
            self.put(&url, body.to_string().as_bytes()).good();
        assert!(!crate_owner_invite.crate_owner_invitation.accepted);
        assert_eq!(crate_owner_invite.crate_owner_invitation.crate_id, krate_id);
    }

    /// As the currently logged in user, list my pending invitations.
    fn list_invitations(&self) -> InvitationListResponse {
        self.get("/api/v1/me/crate_owner_invitations").good()
    }
}

#[test]
fn new_crate_owner() {
    let (app, _, _, token) = TestApp::full().with_token();

    // Create a crate under one user
    let crate_to_publish = PublishBuilder::new("foo_owner").version("1.0.0");
    token.enqueue_publish(crate_to_publish).good();

    // Add the second user as an owner
    let user2 = app.db_new_user("bar");
    token.add_user_owner("foo_owner", user2.as_model());

    // accept invitation for user to be added as owner
    let crate_id = app.db(|conn| Crate::by_name("foo_owner").first::<Crate>(conn).unwrap().id);
    user2.accept_ownership_invitation("foo_owner", crate_id);

    // Make sure this shows up as one of their crates.
    let crates = user2.search_by_user_id(user2.as_model().id);
    assert_eq!(crates.crates.len(), 1);

    // And upload a new crate as the second user
    let crate_to_publish = PublishBuilder::new("foo_owner").version("2.0.0");
    user2
        .db_new_token("bar_token")
        .enqueue_publish(crate_to_publish)
        .good();
}

fn create_and_add_owner(
    app: &TestApp,
    token: &MockTokenUser,
    username: &str,
    krate: &Crate,
) -> MockCookieUser {
    let user = app.db_new_user(username);
    token.add_user_owner(&krate.name, user.as_model());
    user.accept_ownership_invitation(&krate.name, krate.id);
    user
}

// Ensures that so long as at least one owner remains associated with the crate,
// a user can still remove their own login as an owner
#[test]
fn owners_can_remove_self() {
    let (app, _, user, token) = TestApp::init().with_token();
    let username = &user.as_model().gh_login;

    let krate = app
        .db(|conn| CrateBuilder::new("owners_selfremove", user.as_model().id).expect_build(conn));

    // Deleting yourself when you're the only owner isn't allowed.
    let json = token
        .remove_named_owner("owners_selfremove", username)
        .bad_with_status(200);
    assert!(json.errors[0]
        .detail
        .contains("cannot remove all individual owners of a crate"));

    create_and_add_owner(&app, &token, "secondowner", &krate);

    // Deleting yourself when there are other owners is allowed.
    let json = token
        .remove_named_owner("owners_selfremove", username)
        .good();
    assert!(json.ok);

    // After you delete yourself, you no longer have permisions to manage the crate.
    let json = token
        .remove_named_owner("owners_selfremove", username)
        .bad_with_status(200);
    assert!(json.errors[0]
        .detail
        .contains("only owners have permission to modify owners",));
}

// Verify consistency when adidng or removing multiple owners in a single request.
#[test]
fn modify_multiple_owners() {
    let (app, _, user, token) = TestApp::init().with_token();
    let username = &user.as_model().gh_login;

    let krate =
        app.db(|conn| CrateBuilder::new("owners_multiple", user.as_model().id).expect_build(conn));

    let user2 = create_and_add_owner(&app, &token, "user2", &krate);
    let user3 = create_and_add_owner(&app, &token, "user3", &krate);

    // Deleting all owners is not allowed.
    let json = token
        .remove_named_owners("owners_multiple", &[username, "user2", "user3"])
        .bad_with_status(200);
    assert!(&json.errors[0]
        .detail
        .contains("cannot remove all individual owners of a crate"));
    assert_eq!(app.db(|conn| krate.owners(&conn).unwrap()).len(), 3);

    // Deleting two owners at once is allowed.
    let json = token
        .remove_named_owners("owners_multiple", &["user2", "user3"])
        .good();
    assert!(json.ok);
    assert_eq!(app.db(|conn| krate.owners(&conn).unwrap()).len(), 1);

    // Adding multiple users fails if one of them already is an owner.
    let json = token
        .add_named_owners("owners_multiple", &["user2", username])
        .bad_with_status(200);
    assert!(&json.errors[0].detail.contains("is already an owner"));
    assert_eq!(app.db(|conn| krate.owners(&conn).unwrap()).len(), 1);

    // Adding multiple users at once succeeds.
    let json = token
        .add_named_owners("owners_multiple", &["user2", "user3"])
        .good();
    assert!(json.ok);
    user2.accept_ownership_invitation(&krate.name, krate.id);
    user3.accept_ownership_invitation(&krate.name, krate.id);
    assert_eq!(app.db(|conn| krate.owners(&conn).unwrap()).len(), 3);
}

/*  Testing the crate ownership between two crates and one team.
    Given two crates, one crate owned by both a team and a user,
    one only owned by a user, check that the CrateList returned
    for the user_id contains only the crates owned by that user,
    and that the CrateList returned for the team_id contains
    only crates owned by that team.
*/
#[test]
fn check_ownership_two_crates() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    let (krate_owned_by_team, team) = app.db(|conn| {
        let t = new_team("team_foo").create_or_update(conn).unwrap();
        let krate = CrateBuilder::new("foo", user.id).expect_build(conn);
        add_team_to_crate(&t, &krate, user, conn).unwrap();
        (krate, t)
    });

    let user2 = app.db_new_user("user_bar");
    let user2 = user2.as_model();
    let krate_not_owned_by_team =
        app.db(|conn| CrateBuilder::new("bar", user2.id).expect_build(conn));

    let json = anon.search_by_user_id(user2.id);
    assert_eq!(json.crates[0].name, krate_not_owned_by_team.name);
    assert_eq!(json.crates.len(), 1);

    let query = format!("team_id={}", team.id);
    let json = anon.search(&query);
    assert_eq!(json.crates.len(), 1);
    assert_eq!(json.crates[0].name, krate_owned_by_team.name);
}

/*  Given a crate owned by both a team and a user, check that the
    JSON returned by the /owner_team route and /owner_user route
    contains the correct kind of owner

    Note that in this case function new_team must take a team name
    of form github:org_name:team_name as that is the format
    EncodableOwner::encodable is expecting
*/
#[test]
fn check_ownership_one_crate() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    let team = app.db(|conn| {
        let t = new_team("github:test_org:team_sloth")
            .create_or_update(conn)
            .unwrap();
        let krate = CrateBuilder::new("best_crate", user.id).expect_build(conn);
        add_team_to_crate(&t, &krate, user, conn).unwrap();
        t
    });

    let json: TeamResponse = anon.get("/api/v1/crates/best_crate/owner_team").good();
    assert_eq!(json.teams[0].kind, "team");
    assert_eq!(json.teams[0].name, team.name);

    let json: UserResponse = anon.get("/api/v1/crates/best_crate/owner_user").good();
    assert_eq!(json.users[0].kind, "user");
    assert_eq!(json.users[0].name, user.name);
}

#[test]
fn invitations_are_empty_by_default() {
    let (_, _, user) = TestApp::init().with_user();

    let json = user.list_invitations();
    assert_eq!(json.crate_owner_invitations.len(), 0);
}

#[test]
fn invitations_list() {
    let (app, _, owner, token) = TestApp::init().with_token();
    let owner = owner.as_model();

    let krate = app.db(|conn| CrateBuilder::new("invited_crate", owner.id).expect_build(conn));

    let user = app.db_new_user("invited_user");
    token.add_user_owner("invited_crate", user.as_model());

    let json = user.list_invitations();
    assert_eq!(json.crate_owner_invitations.len(), 1);
    assert_eq!(
        json.crate_owner_invitations[0].invited_by_username,
        owner.gh_login
    );
    assert_eq!(json.crate_owner_invitations[0].crate_name, "invited_crate");
    assert_eq!(json.crate_owner_invitations[0].crate_id, krate.id);
}

/*  Given a user inviting a different user to be a crate
    owner, check that the user invited can accept their
    invitation, the invitation will be deleted from
    the invitations table, and a new crate owner will be
    inserted into the table for the given crate.
*/
#[test]
fn test_accept_invitation() {
    let (app, anon, owner, owner_token) = TestApp::init().with_token();
    let owner = owner.as_model();
    let invited_user = app.db_new_user("user_bar");
    let krate = app.db(|conn| CrateBuilder::new("accept_invitation", owner.id).expect_build(conn));

    // Invite a new owner
    owner_token.add_user_owner("accept_invitation", invited_user.as_model());

    // New owner accepts the invitation
    invited_user.accept_ownership_invitation(&krate.name, krate.id);

    // New owner's invitation list should now be empty
    let json = invited_user.list_invitations();
    assert_eq!(json.crate_owner_invitations.len(), 0);

    // New owner is now listed as an owner, so the crate has two owners
    let json = anon.show_crate_owners("accept_invitation");
    assert_eq!(json.users.len(), 2);
}

/*  Given a user inviting a different user to be a crate
    owner, check that the user invited can decline their
    invitation and the invitation will be deleted from
    the invitations table.
*/
#[test]
fn test_decline_invitation() {
    let (app, anon, owner, owner_token) = TestApp::init().with_token();
    let owner = owner.as_model();
    let invited_user = app.db_new_user("user_bar");
    let krate = app.db(|conn| CrateBuilder::new("decline_invitation", owner.id).expect_build(conn));

    // Invite a new owner
    owner_token.add_user_owner("decline_invitation", invited_user.as_model());

    // Invited user declines the invitation
    invited_user.decline_ownership_invitation(&krate.name, krate.id);

    // Invited user's invitation list should now be empty
    let json = invited_user.list_invitations();
    assert_eq!(json.crate_owner_invitations.len(), 0);

    // Invited user is NOT listed as an owner, so the crate still only has one owner
    let json = anon.show_crate_owners("decline_invitation");
    assert_eq!(json.users.len(), 1);
}
<commit_msg>Add a test that passes but will catch ownership deletion regressions<commit_after>use crate::{
    add_team_to_crate,
    builders::{CrateBuilder, PublishBuilder},
    new_team,
    util::{MockCookieUser, MockTokenUser, RequestHelper},
    TestApp,
};
use cargo_registry::{
    models::Crate,
    views::{EncodableCrateOwnerInvitation, EncodableOwner, InvitationResponse},
};

use diesel::prelude::*;

#[derive(Deserialize)]
struct TeamResponse {
    teams: Vec<EncodableOwner>,
}
#[derive(Deserialize)]
struct UserResponse {
    users: Vec<EncodableOwner>,
}
#[derive(Deserialize)]
struct InvitationListResponse {
    crate_owner_invitations: Vec<EncodableCrateOwnerInvitation>,
}

// Implementing locally for now, unless these are needed elsewhere
impl MockCookieUser {
    /// As the currently logged in user, accept an invitation to become an owner of the named
    /// crate.
    fn accept_ownership_invitation(&self, krate_name: &str, krate_id: i32) {
        let body = json!({
            "crate_owner_invite": {
                "invited_by_username": "",
                "crate_name": krate_name,
                "crate_id": krate_id,
                "created_at": "",
                "accepted": true
            }
        });

        #[derive(Deserialize)]
        struct CrateOwnerInvitation {
            crate_owner_invitation: InvitationResponse,
        }

        let url = format!("/api/v1/me/crate_owner_invitations/{}", krate_id);
        let crate_owner_invite: CrateOwnerInvitation =
            self.put(&url, body.to_string().as_bytes()).good();
        assert!(crate_owner_invite.crate_owner_invitation.accepted);
        assert_eq!(crate_owner_invite.crate_owner_invitation.crate_id, krate_id);
    }

    /// As the currently logged in user, decline an invitation to become an owner of the named
    /// crate.
    fn decline_ownership_invitation(&self, krate_name: &str, krate_id: i32) {
        let body = json!({
            "crate_owner_invite": {
                "invited_by_username": "",
                "crate_name": krate_name,
                "crate_id": krate_id,
                "created_at": "",
                "accepted": false
            }
        });

        #[derive(Deserialize)]
        struct CrateOwnerInvitation {
            crate_owner_invitation: InvitationResponse,
        }

        let url = format!("/api/v1/me/crate_owner_invitations/{}", krate_id);
        let crate_owner_invite: CrateOwnerInvitation =
            self.put(&url, body.to_string().as_bytes()).good();
        assert!(!crate_owner_invite.crate_owner_invitation.accepted);
        assert_eq!(crate_owner_invite.crate_owner_invitation.crate_id, krate_id);
    }

    /// As the currently logged in user, list my pending invitations.
    fn list_invitations(&self) -> InvitationListResponse {
        self.get("/api/v1/me/crate_owner_invitations").good()
    }
}

#[test]
fn new_crate_owner() {
    let (app, _, _, token) = TestApp::full().with_token();

    // Create a crate under one user
    let crate_to_publish = PublishBuilder::new("foo_owner").version("1.0.0");
    token.enqueue_publish(crate_to_publish).good();

    // Add the second user as an owner
    let user2 = app.db_new_user("bar");
    token.add_user_owner("foo_owner", user2.as_model());

    // accept invitation for user to be added as owner
    let crate_id = app.db(|conn| Crate::by_name("foo_owner").first::<Crate>(conn).unwrap().id);
    user2.accept_ownership_invitation("foo_owner", crate_id);

    // Make sure this shows up as one of their crates.
    let crates = user2.search_by_user_id(user2.as_model().id);
    assert_eq!(crates.crates.len(), 1);

    // And upload a new crate as the second user
    let crate_to_publish = PublishBuilder::new("foo_owner").version("2.0.0");
    user2
        .db_new_token("bar_token")
        .enqueue_publish(crate_to_publish)
        .good();
}

fn create_and_add_owner(
    app: &TestApp,
    token: &MockTokenUser,
    username: &str,
    krate: &Crate,
) -> MockCookieUser {
    let user = app.db_new_user(username);
    token.add_user_owner(&krate.name, user.as_model());
    user.accept_ownership_invitation(&krate.name, krate.id);
    user
}

// Ensures that so long as at least one owner remains associated with the crate,
// a user can still remove their own login as an owner
#[test]
fn owners_can_remove_self() {
    let (app, _, user, token) = TestApp::init().with_token();
    let username = &user.as_model().gh_login;

    let krate = app
        .db(|conn| CrateBuilder::new("owners_selfremove", user.as_model().id).expect_build(conn));

    // Deleting yourself when you're the only owner isn't allowed.
    let json = token
        .remove_named_owner("owners_selfremove", username)
        .bad_with_status(200);
    assert!(json.errors[0]
        .detail
        .contains("cannot remove all individual owners of a crate"));

    create_and_add_owner(&app, &token, "secondowner", &krate);

    // Deleting yourself when there are other owners is allowed.
    let json = token
        .remove_named_owner("owners_selfremove", username)
        .good();
    assert!(json.ok);

    // After you delete yourself, you no longer have permisions to manage the crate.
    let json = token
        .remove_named_owner("owners_selfremove", username)
        .bad_with_status(200);
    assert!(json.errors[0]
        .detail
        .contains("only owners have permission to modify owners",));
}

// Verify consistency when adidng or removing multiple owners in a single request.
#[test]
fn modify_multiple_owners() {
    let (app, _, user, token) = TestApp::init().with_token();
    let username = &user.as_model().gh_login;

    let krate =
        app.db(|conn| CrateBuilder::new("owners_multiple", user.as_model().id).expect_build(conn));

    let user2 = create_and_add_owner(&app, &token, "user2", &krate);
    let user3 = create_and_add_owner(&app, &token, "user3", &krate);

    // Deleting all owners is not allowed.
    let json = token
        .remove_named_owners("owners_multiple", &[username, "user2", "user3"])
        .bad_with_status(200);
    assert!(&json.errors[0]
        .detail
        .contains("cannot remove all individual owners of a crate"));
    assert_eq!(app.db(|conn| krate.owners(&conn).unwrap()).len(), 3);

    // Deleting two owners at once is allowed.
    let json = token
        .remove_named_owners("owners_multiple", &["user2", "user3"])
        .good();
    assert!(json.ok);
    assert_eq!(app.db(|conn| krate.owners(&conn).unwrap()).len(), 1);

    // Adding multiple users fails if one of them already is an owner.
    let json = token
        .add_named_owners("owners_multiple", &["user2", username])
        .bad_with_status(200);
    assert!(&json.errors[0].detail.contains("is already an owner"));
    assert_eq!(app.db(|conn| krate.owners(&conn).unwrap()).len(), 1);

    // Adding multiple users at once succeeds.
    let json = token
        .add_named_owners("owners_multiple", &["user2", "user3"])
        .good();
    assert!(json.ok);
    user2.accept_ownership_invitation(&krate.name, krate.id);
    user3.accept_ownership_invitation(&krate.name, krate.id);
    assert_eq!(app.db(|conn| krate.owners(&conn).unwrap()).len(), 3);
}

/*  Testing the crate ownership between two crates and one team.
    Given two crates, one crate owned by both a team and a user,
    one only owned by a user, check that the CrateList returned
    for the user_id contains only the crates owned by that user,
    and that the CrateList returned for the team_id contains
    only crates owned by that team.
*/
#[test]
fn check_ownership_two_crates() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    let (krate_owned_by_team, team) = app.db(|conn| {
        let t = new_team("team_foo").create_or_update(conn).unwrap();
        let krate = CrateBuilder::new("foo", user.id).expect_build(conn);
        add_team_to_crate(&t, &krate, user, conn).unwrap();
        (krate, t)
    });

    let user2 = app.db_new_user("user_bar");
    let user2 = user2.as_model();
    let krate_not_owned_by_team =
        app.db(|conn| CrateBuilder::new("bar", user2.id).expect_build(conn));

    let json = anon.search_by_user_id(user2.id);
    assert_eq!(json.crates[0].name, krate_not_owned_by_team.name);
    assert_eq!(json.crates.len(), 1);

    let query = format!("team_id={}", team.id);
    let json = anon.search(&query);
    assert_eq!(json.crates.len(), 1);
    assert_eq!(json.crates[0].name, krate_owned_by_team.name);
}

/*  Given a crate owned by both a team and a user, check that the
    JSON returned by the /owner_team route and /owner_user route
    contains the correct kind of owner

    Note that in this case function new_team must take a team name
    of form github:org_name:team_name as that is the format
    EncodableOwner::encodable is expecting
*/
#[test]
fn check_ownership_one_crate() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    let team = app.db(|conn| {
        let t = new_team("github:test_org:team_sloth")
            .create_or_update(conn)
            .unwrap();
        let krate = CrateBuilder::new("best_crate", user.id).expect_build(conn);
        add_team_to_crate(&t, &krate, user, conn).unwrap();
        t
    });

    let json: TeamResponse = anon.get("/api/v1/crates/best_crate/owner_team").good();
    assert_eq!(json.teams[0].kind, "team");
    assert_eq!(json.teams[0].name, team.name);

    let json: UserResponse = anon.get("/api/v1/crates/best_crate/owner_user").good();
    assert_eq!(json.users[0].kind, "user");
    assert_eq!(json.users[0].name, user.name);
}

#[test]
fn deleted_ownership_isnt_in_owner_user() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    app.db(|conn| {
        let krate = CrateBuilder::new("foo_my_packages", user.id).expect_build(conn);
        krate
            .owner_remove(app.as_inner(), conn, user, &user.gh_login)
            .unwrap();
    });

    let json: UserResponse = anon.get("/api/v1/crates/foo_my_packages/owner_user").good();
    assert_eq!(json.users.len(), 0);
}

#[test]
fn invitations_are_empty_by_default() {
    let (_, _, user) = TestApp::init().with_user();

    let json = user.list_invitations();
    assert_eq!(json.crate_owner_invitations.len(), 0);
}

#[test]
fn invitations_list() {
    let (app, _, owner, token) = TestApp::init().with_token();
    let owner = owner.as_model();

    let krate = app.db(|conn| CrateBuilder::new("invited_crate", owner.id).expect_build(conn));

    let user = app.db_new_user("invited_user");
    token.add_user_owner("invited_crate", user.as_model());

    let json = user.list_invitations();
    assert_eq!(json.crate_owner_invitations.len(), 1);
    assert_eq!(
        json.crate_owner_invitations[0].invited_by_username,
        owner.gh_login
    );
    assert_eq!(json.crate_owner_invitations[0].crate_name, "invited_crate");
    assert_eq!(json.crate_owner_invitations[0].crate_id, krate.id);
}

/*  Given a user inviting a different user to be a crate
    owner, check that the user invited can accept their
    invitation, the invitation will be deleted from
    the invitations table, and a new crate owner will be
    inserted into the table for the given crate.
*/
#[test]
fn test_accept_invitation() {
    let (app, anon, owner, owner_token) = TestApp::init().with_token();
    let owner = owner.as_model();
    let invited_user = app.db_new_user("user_bar");
    let krate = app.db(|conn| CrateBuilder::new("accept_invitation", owner.id).expect_build(conn));

    // Invite a new owner
    owner_token.add_user_owner("accept_invitation", invited_user.as_model());

    // New owner accepts the invitation
    invited_user.accept_ownership_invitation(&krate.name, krate.id);

    // New owner's invitation list should now be empty
    let json = invited_user.list_invitations();
    assert_eq!(json.crate_owner_invitations.len(), 0);

    // New owner is now listed as an owner, so the crate has two owners
    let json = anon.show_crate_owners("accept_invitation");
    assert_eq!(json.users.len(), 2);
}

/*  Given a user inviting a different user to be a crate
    owner, check that the user invited can decline their
    invitation and the invitation will be deleted from
    the invitations table.
*/
#[test]
fn test_decline_invitation() {
    let (app, anon, owner, owner_token) = TestApp::init().with_token();
    let owner = owner.as_model();
    let invited_user = app.db_new_user("user_bar");
    let krate = app.db(|conn| CrateBuilder::new("decline_invitation", owner.id).expect_build(conn));

    // Invite a new owner
    owner_token.add_user_owner("decline_invitation", invited_user.as_model());

    // Invited user declines the invitation
    invited_user.decline_ownership_invitation(&krate.name, krate.id);

    // Invited user's invitation list should now be empty
    let json = invited_user.list_invitations();
    assert_eq!(json.crate_owner_invitations.len(), 0);

    // Invited user is NOT listed as an owner, so the crate still only has one owner
    let json = anon.show_crate_owners("decline_invitation");
    assert_eq!(json.users.len(), 1);
}
<|endoftext|>


<commit_before>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

#[test]
fn test_quark() {
  let source = "null true false 1.3 0.3 2 3 name table";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_quark(&mut it), Ok(Node::Null));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(true)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(false)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(1.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(0.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(2)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Name(String::from("name"))));
  assert_eq!(parse_quark(&mut it), Ok(Node::Table));
  assert_eq!(parse_quark(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_quark(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_quark(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_atom() {
  let source = "null (null)";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_atom(&mut it), Ok(Node::Null));
  assert_eq!(parse_atom(&mut it), Ok(Node::Null));
  assert_eq!(parse_atom(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_atom(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_atom(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_simple() {
  let source = "foo foo.bar foo[bar] foo() foo:bar() foo.bar() foo.bar[baz]:qux()";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_simple(&mut it), Ok(Node::Name(String::from("foo"))));
  assert_eq!(parse_simple(&mut it), Ok(Node::Index {
    lhs: Box::new(Node::Name(String::from("foo"))),
    rhs: Box::new(Node::Str(String::from("bar"))),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Index {
    lhs: Box::new(Node::Name(String::from("foo"))),
    rhs: Box::new(Node::Name(String::from("bar"))),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Func {
    func: Box::new(Node::Name(String::from("foo"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Method {
    owner: Box::new(Node::Name(String::from("foo"))),
    method: Box::new(Node::Str(String::from("bar"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Func {
    func: Box::new(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    }),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Method {
    owner: Box::new(Node::Index {
      lhs: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      rhs: Box::new(Node::Name(String::from("baz"))),
    }),
    method: Box::new(Node::Str(String::from("qux"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_simple(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_simple(&mut it), Err(UnexpectedEOF));
}
<commit_msg>tests.parser: Add test_fn_args and test_un_expr<commit_after>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

#[test]
fn test_quark() {
  let source = "null true false 1.3 0.3 2 3 name table";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_quark(&mut it), Ok(Node::Null));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(true)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(false)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(1.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(0.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(2)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Name(String::from("name"))));
  assert_eq!(parse_quark(&mut it), Ok(Node::Table));
  assert_eq!(parse_quark(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_quark(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_quark(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_atom() {
  let source = "null (null)";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_atom(&mut it), Ok(Node::Null));
  assert_eq!(parse_atom(&mut it), Ok(Node::Null));
  assert_eq!(parse_atom(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_atom(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_atom(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_simple() {
  let source = "foo foo.bar foo[bar] foo() foo:bar() foo.bar() foo.bar[baz]:qux()";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_simple(&mut it), Ok(Node::Name(String::from("foo"))));
  assert_eq!(parse_simple(&mut it), Ok(Node::Index {
    lhs: Box::new(Node::Name(String::from("foo"))),
    rhs: Box::new(Node::Str(String::from("bar"))),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Index {
    lhs: Box::new(Node::Name(String::from("foo"))),
    rhs: Box::new(Node::Name(String::from("bar"))),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Func {
    func: Box::new(Node::Name(String::from("foo"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Method {
    owner: Box::new(Node::Name(String::from("foo"))),
    method: Box::new(Node::Str(String::from("bar"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Func {
    func: Box::new(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    }),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Method {
    owner: Box::new(Node::Index {
      lhs: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      rhs: Box::new(Node::Name(String::from("baz"))),
    }),
    method: Box::new(Node::Str(String::from("qux"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_simple(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_simple(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_fn_args() {
  let source = "()";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_fn_args(&mut it), Ok(Vec::new()));
  assert_eq!(parse_fn_args(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_fn_args(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_fn_args(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_un_expr() {
  let source = "5 foo() -5 -foo.bar !-5";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_un_expr(&mut it), Ok(Node::Int(5)));
  assert_eq!(parse_un_expr(&mut it), Ok(Node::Func {
    func: Box::new(Node::Name(String::from("foo"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_un_expr(&mut it), Ok(Node::UnExpr {
    op: lexer::Token::Sub,
    val: Box::new(Node::Int(5)),
  }));
  assert_eq!(parse_un_expr(&mut it), Ok(Node::UnExpr {
    op: lexer::Token::Sub,
    val: Box::new(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    }),
  }));
  assert_eq!(parse_un_expr(&mut it), Ok(Node::UnExpr {
    op: lexer::Token::Not,
    val: Box::new(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Int(5)),
    }),
  }));
  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedEOF));
}
<|endoftext|>


<commit_before>use tracker::{TrackerReq, TrackerResp};
use bencode::decode::belement_decode;
use hyper::Url;
use hyper::client::Request;
use hyper::client::Client;
use hyper::net::HttpStream;
use std::error::Error;
use std::fmt;
use std::io::Read;

pub trait TrackerHandler {
    fn request(self: &Self, req: &TrackerReq) -> Result<TrackerResp, TrackerError>;
}

pub struct HttpTrackerHandler {
    url: Url
}

impl HttpTrackerHandler {
    pub fn new(url: Url) -> HttpTrackerHandler {
        HttpTrackerHandler { url: url  }
    }
}

#[derive(Debug)]
pub enum TrackerError {
    Unknown
}

impl Error for TrackerError {
    fn description(&self) -> &str { unimplemented!() }
}

impl fmt::Display for TrackerError {
    fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
        unimplemented!()
    }
}

impl TrackerHandler for HttpTrackerHandler {
    fn request(&self, req: &TrackerReq) -> Result<TrackerResp, TrackerError> {
        //build the url
        let mut url = self.url.clone();
        let query_string = req.to_query_string_pairs().iter()
            .fold(String::new(), |string, &(ref k, ref v)| format!("{}{}={}", string, k, v));
        url.set_query(Some(&query_string));

        //make the request
        let client = Client::new();
        match client.get(url).send() {
            Ok(mut response) => {
                let mut response_bytes = Vec::new();
                response.read_to_end(&mut response_bytes);
                let response_dict = belement_decode(&response_bytes).unwrap();
                unimplemented!()
            },
            Err(_) => Err(TrackerError::Unknown),
        }

    }
}
<commit_msg>Make TrackerHandler request work<commit_after>use tracker::{TrackerReq, TrackerResp};
use bencode::decode::belement_decode;
use bencode::BDict;
use hyper::Url;
use hyper::client::Request;
use hyper::client::Client;
use hyper::net::HttpStream;
use std::error::Error;
use std::fmt;
use std::io::Read;
use convert::TryFrom;

pub trait TrackerHandler {
    fn request(self: &Self, req: &TrackerReq) -> Result<TrackerResp, TrackerError>;
}

pub struct HttpTrackerHandler {
    url: Url
}

impl HttpTrackerHandler {
    pub fn new(url: Url) -> HttpTrackerHandler {
        HttpTrackerHandler { url: url  }
    }
}

#[derive(Debug)]
pub enum TrackerError {
    Unknown
}

impl Error for TrackerError {
    fn description(&self) -> &str { unimplemented!() }
}

impl fmt::Display for TrackerError {
    fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
        unimplemented!()
    }
}

impl TrackerHandler for HttpTrackerHandler {
    fn request(&self, req: &TrackerReq) -> Result<TrackerResp, TrackerError> {
        //build the url
        let mut url = self.url.clone();
        let query_string = req.to_query_string_pairs().iter()
            .fold(String::new(), |string, &(ref k, ref v)| format!("{}{}={}", string, k, v));
        url.set_query(Some(&query_string));

        //make the request
        let client = Client::new();
        match client.get(url).send() {
            Ok(mut response) => {
                let mut response_bytes = Vec::new();
                response.read_to_end(&mut response_bytes);
                let response_dict =
                    BDict::try_from(belement_decode(&response_bytes).unwrap().0).unwrap();
                let tracker_response: TrackerResp = TrackerResp::try_from(response_dict).unwrap();
                Ok(tracker_response)
            },
            Err(_) => Err(TrackerError::Unknown),
        }

    }
}
<|endoftext|>


<commit_before>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

extern crate habitat_core as hab_core;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate log;
extern crate openssl;

pub mod error;

use std::sync::Arc;
use std::path::Path;

use hab_core::env::http_proxy_unless_domain_exempted;
use hyper::client::Client;
use hyper::client::pool::{Config, Pool};
use hyper::http::h1::Http11Protocol;
use hyper::net::{HttpsConnector, Openssl};
use hyper::Url;
use openssl::ssl::{SslContext, SslMethod, SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3, SSL_OP_NO_COMPRESSION};

pub use error::{Error, Result};

/// Builds a new hyper HTTP client with appropriate SSL configuration and HTTP/HTTPS proxy support.
///
/// ## Linux Platforms
///
/// We need a set of root certificates when connected to SSL/TLS web endpoints and this usually
/// boild down to using an all-in-one certificate file (such as a `cacert.pem` file) or a directory
/// of files which are certificates. The strategy to location or use a reasonable set of
/// certificates is as follows:
///
/// 1. If the `SSL_CERT_FILE` environment variable is set, then use its value for the certificates.
///    Interally this is triggering default OpenSSL behavior for this environment variable.
/// 2. If the `SSL_CERT_DIR` environment variable is set, then use its value for the directory
///    containing certificates. Like the `SSL_CERT_FILE` case above, this triggers default OpenSSL
///    behavior for this environment variable.
/// 3. If the `core/cacerts` Habitat package is installed locally, then use the latest release's
///    `cacert.pem` file.
/// 4. If none of the conditions above are met, then a `cacert.pem` will be written in an SSL cache
///    directory (by default `/hab/cache/ssl` for a root user and `$HOME/.hab/cache/ssl` for a
///    non-root user) and this will be used. The contents of this file will be inlined in this
///    crate at build time as a fallback insurance policy, meaning that if the a program using this
///    code is operating in a minimal environment which may not contain system certificates, it can
///    still operate. Once a `core/cacerts` Habitat package is present, the logic would fall back
///    to preferring the package version to the cached/inline file version.
///
/// ## Mac Platforms
///
/// The Mac platoform uses a Security Framework to store and find root certificates and the hyper
/// library will default to using this on the Mac. Therefore the behavior on the Mac remains
/// unchanged and will use the system's certificates.
///
pub fn new_hyper_client(for_domain: Option<&Url>, fs_root_path: Option<&Path>) -> Result<Client> {
    let for_domain = match for_domain {
        Some(url) => url.host_str().unwrap_or(""),
        None => "",
    };
    match try!(http_proxy_unless_domain_exempted(for_domain)) {
        Some((proxy_host, proxy_port)) => {
            debug!("Using proxy {}:{}...", &proxy_host, &proxy_port);
            Ok(Client::with_http_proxy(proxy_host, proxy_port))
        }
        None => {
            let ctx = try!(ssl_ctx(fs_root_path));
            let connector = HttpsConnector::new(Openssl { context: Arc::new(ctx) });
            let pool = Pool::with_connector(Config::default(), connector);
            Ok(Client::with_protocol(Http11Protocol::with_connector(pool)))
        }
    }
}

fn ssl_ctx(fs_root_path: Option<&Path>) -> Result<SslContext> {
    // The spirit of this implementation is directly from Hyper's default OpensslClient function:
    // https://github.com/hyperium/hyper/blob/v0.9.5/src/net.rs#L653-L661
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ssl::set_ca(&mut ctx, fs_root_path));
    ctx.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
    try!(ctx.set_cipher_list("ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4@STRENGTH"));
    Ok(ctx)
}

#[cfg(target_os = "linux")]
mod ssl {
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::Path;
    use std::str::FromStr;

    use hab_core::env;
    use hab_core::fs::cache_ssl_path;
    use hab_core::package::{PackageIdent, PackageInstall};
    use openssl::ssl::SslContext;

    use error::Result;

    const CACERTS_PKG_IDENT: &'static str = "core/cacerts";
    const CACERT_PEM: &'static str = include_str!(concat!(env!("OUT_DIR"), "/cacert.pem"));

    pub fn set_ca(ctx: &mut SslContext, fs_root_path: Option<&Path>) -> Result<()> {
        let cacerts_ident = try!(PackageIdent::from_str(CACERTS_PKG_IDENT));

        if let Ok(_) = env::var("SSL_CERT_FILE") {
            try!(ctx.set_default_verify_paths());
        } else if let Ok(_) = env::var("SSL_CERT_DIR") {
            try!(ctx.set_default_verify_paths());
        } else if let Ok(pkg_install) = PackageInstall::load(&cacerts_ident, fs_root_path) {
            let pkg_certs = pkg_install.installed_path().join("ssl/cert.pem");
            debug!("Setting CA file for SSL context to: {}",
                   pkg_certs.display());
            try!(ctx.set_CA_file(pkg_certs));
        } else {
            let cached_certs = cache_ssl_path(fs_root_path).join("cert.pem");
            if !cached_certs.exists() {
                try!(fs::create_dir_all(cache_ssl_path(None)));
                debug!("Creating cached cacert.pem at: {}", cached_certs.display());
                let mut file = try!(File::create(&cached_certs));
                try!(file.write_all(CACERT_PEM.as_bytes()));
            }
            debug!("Setting CA file for SSL context to: {}",
                   cached_certs.display());
            try!(ctx.set_CA_file(cached_certs));
        }
        Ok(())
    }
}

#[cfg(not(target_os = "linux"))]
mod ssl {
    use std::path::Path;

    use openssl::ssl::SslContext;

    use error::Result;

    pub fn set_ca(ctx: &mut SslContext, _fs_root_path: Option<&Path>) -> Result<()> {
        try!(ctx.set_default_verify_paths());
        Ok(())
    }
}
<commit_msg>[http-client] Drop support for http_proxy pending upstream support.<commit_after>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

extern crate habitat_core as hab_core;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate log;
extern crate openssl;

pub mod error;

use std::sync::Arc;
use std::path::Path;

use hyper::client::Client;
use hyper::client::pool::{Config, Pool};
use hyper::http::h1::Http11Protocol;
use hyper::net::{HttpsConnector, Openssl};
use hyper::Url;
use openssl::ssl::{SslContext, SslMethod, SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3, SSL_OP_NO_COMPRESSION};

pub use error::{Error, Result};

/// Builds a new hyper HTTP client with appropriate SSL configuration and HTTP/HTTPS proxy support.
///
/// ## Linux Platforms
///
/// We need a set of root certificates when connected to SSL/TLS web endpoints and this usually
/// boild down to using an all-in-one certificate file (such as a `cacert.pem` file) or a directory
/// of files which are certificates. The strategy to location or use a reasonable set of
/// certificates is as follows:
///
/// 1. If the `SSL_CERT_FILE` environment variable is set, then use its value for the certificates.
///    Interally this is triggering default OpenSSL behavior for this environment variable.
/// 2. If the `SSL_CERT_DIR` environment variable is set, then use its value for the directory
///    containing certificates. Like the `SSL_CERT_FILE` case above, this triggers default OpenSSL
///    behavior for this environment variable.
/// 3. If the `core/cacerts` Habitat package is installed locally, then use the latest release's
///    `cacert.pem` file.
/// 4. If none of the conditions above are met, then a `cacert.pem` will be written in an SSL cache
///    directory (by default `/hab/cache/ssl` for a root user and `$HOME/.hab/cache/ssl` for a
///    non-root user) and this will be used. The contents of this file will be inlined in this
///    crate at build time as a fallback insurance policy, meaning that if the a program using this
///    code is operating in a minimal environment which may not contain system certificates, it can
///    still operate. Once a `core/cacerts` Habitat package is present, the logic would fall back
///    to preferring the package version to the cached/inline file version.
///
/// ## Mac Platforms
///
/// The Mac platoform uses a Security Framework to store and find root certificates and the hyper
/// library will default to using this on the Mac. Therefore the behavior on the Mac remains
/// unchanged and will use the system's certificates.
///
pub fn new_hyper_client(_for_domain: Option<&Url>, fs_root_path: Option<&Path>) -> Result<Client> {
    let ctx = try!(ssl_ctx(fs_root_path));
    let connector = HttpsConnector::new(Openssl { context: Arc::new(ctx) });
    let pool = Pool::with_connector(Config::default(), connector);
    Ok(Client::with_protocol(Http11Protocol::with_connector(pool)))
}

fn ssl_ctx(fs_root_path: Option<&Path>) -> Result<SslContext> {
    // The spirit of this implementation is directly from Hyper's default OpensslClient function:
    // https://github.com/hyperium/hyper/blob/v0.9.5/src/net.rs#L653-L661
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ssl::set_ca(&mut ctx, fs_root_path));
    ctx.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
    try!(ctx.set_cipher_list("ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4@STRENGTH"));
    Ok(ctx)
}

#[cfg(target_os = "linux")]
mod ssl {
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::Path;
    use std::str::FromStr;

    use hab_core::env;
    use hab_core::fs::cache_ssl_path;
    use hab_core::package::{PackageIdent, PackageInstall};
    use openssl::ssl::SslContext;

    use error::Result;

    const CACERTS_PKG_IDENT: &'static str = "core/cacerts";
    const CACERT_PEM: &'static str = include_str!(concat!(env!("OUT_DIR"), "/cacert.pem"));

    pub fn set_ca(ctx: &mut SslContext, fs_root_path: Option<&Path>) -> Result<()> {
        let cacerts_ident = try!(PackageIdent::from_str(CACERTS_PKG_IDENT));

        if let Ok(_) = env::var("SSL_CERT_FILE") {
            try!(ctx.set_default_verify_paths());
        } else if let Ok(_) = env::var("SSL_CERT_DIR") {
            try!(ctx.set_default_verify_paths());
        } else if let Ok(pkg_install) = PackageInstall::load(&cacerts_ident, fs_root_path) {
            let pkg_certs = pkg_install.installed_path().join("ssl/cert.pem");
            debug!("Setting CA file for SSL context to: {}",
                   pkg_certs.display());
            try!(ctx.set_CA_file(pkg_certs));
        } else {
            let cached_certs = cache_ssl_path(fs_root_path).join("cert.pem");
            if !cached_certs.exists() {
                try!(fs::create_dir_all(cache_ssl_path(None)));
                debug!("Creating cached cacert.pem at: {}", cached_certs.display());
                let mut file = try!(File::create(&cached_certs));
                try!(file.write_all(CACERT_PEM.as_bytes()));
            }
            debug!("Setting CA file for SSL context to: {}",
                   cached_certs.display());
            try!(ctx.set_CA_file(cached_certs));
        }
        Ok(())
    }
}

#[cfg(not(target_os = "linux"))]
mod ssl {
    use std::path::Path;

    use openssl::ssl::SslContext;

    use error::Result;

    pub fn set_ca(ctx: &mut SslContext, _fs_root_path: Option<&Path>) -> Result<()> {
        try!(ctx.set_default_verify_paths());
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Implements a NATS Streaming-based event stream.

use super::EventStream;
use crate::error::Result;
use futures::{sync::mpsc::unbounded,
              Future,
              Stream};
use nitox::{commands::ConnectCommand,
            streaming::{client::NatsStreamingClient,
                        error::NatsStreamingError},
            NatsClient,
            NatsClientOptions};
use std::{sync::mpsc::sync_channel,
          thread};
use tokio::{executor,
            runtime::current_thread::Runtime as ThreadRuntime};

/// All messages are published under this subject.
static HABITAT_SUBJECT: &'static str = "habitat";

/// All the information needed to establish a connection to a NATS
/// Streaming server.
// TODO: This will change as we firm up what the interaction between
// Habitat and A2 looks like.
pub struct EventConnectionInfo {
    pub name:        String,
    pub verbose:     bool,
    pub cluster_uri: String,
    pub cluster_id:  String,
}

/// Defines default connection information for a NATS Streaming server
/// running on localhost.
// TODO: As we become clear on the interaction between Habitat and A2,
// this implementation *may* disappear. It's useful for testing and
// prototyping, though.
impl Default for EventConnectionInfo {
    fn default() -> Self {
        EventConnectionInfo { name:        String::from("habitat"),
                              verbose:     true,
                              cluster_uri: String::from("127.0.0.1:4223"),
                              cluster_id:  String::from("test-cluster"), }
    }
}

pub(super) fn init_stream(conn_info: EventConnectionInfo) -> Result<EventStream> {
    // TODO (CM): Investigate back-pressure scenarios
    let (event_tx, event_rx) = unbounded();
    let (sync_tx, sync_rx) = sync_channel(0); // rendezvous channel

    // TODO (CM): We could theoretically create this future and spawn
    // it in the Supervisor's Tokio runtime, but there's currently a
    // bug: https://github.com/YellowInnovation/nitox/issues/24

    thread::Builder::new().name("events".to_string())
                          .spawn(move || {
                              let EventConnectionInfo { name,
                                                        verbose,
                                                        cluster_uri,
                                                        cluster_id, } = conn_info;

                              let cc = ConnectCommand::builder()
                // .user(Some("nats".to_string()))
                // .pass(Some("S3Cr3TP@5w0rD".to_string()))
                .name(Some(name))
                .verbose(verbose)
                .build()
                .unwrap();
                              let opts =
                                  NatsClientOptions::builder().connect_command(cc)
                                                              .cluster_uri(cluster_uri.as_str())
                                                              .build()
                                                              .unwrap();

                              let publisher = NatsClient::from_options(opts)
                .map_err(Into::<NatsStreamingError>::into)
                .and_then(|client| {
                    NatsStreamingClient::from(client)
                        .cluster_id(cluster_id)
                        .connect()
                })
                .map_err(|streaming_error| error!("{}", streaming_error))
                .and_then(move |client| {
                    sync_tx.send(()).expect("Couldn't synchronize!");
                    event_rx.for_each(move |event: Vec<u8>| {
                        let publish_event = client
                            .publish(HABITAT_SUBJECT.into(), event.into())
                            .map_err(|e| {
                                error!("Error publishing event: {:?}", e);
                            });
                        executor::spawn(publish_event);
                        Ok(())
                    })
                });

                              ThreadRuntime::new().expect("Couldn't create event stream runtime!")
                                                  .spawn(publisher)
                                                  .run()
                                                  .expect("something seriously wrong has occurred");
                          })
                          .expect("Couldn't start events thread!");

    sync_rx.recv()?; // TODO (CM): nicer error message
    Ok(EventStream(event_tx))
}
<commit_msg>[PR Feedback] Use const instead of static<commit_after>// Copyright (c) 2019 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Implements a NATS Streaming-based event stream.

use super::EventStream;
use crate::error::Result;
use futures::{sync::mpsc::unbounded,
              Future,
              Stream};
use nitox::{commands::ConnectCommand,
            streaming::{client::NatsStreamingClient,
                        error::NatsStreamingError},
            NatsClient,
            NatsClientOptions};
use std::{sync::mpsc::sync_channel,
          thread};
use tokio::{executor,
            runtime::current_thread::Runtime as ThreadRuntime};

/// All messages are published under this subject.
const HABITAT_SUBJECT: &str = "habitat";

/// All the information needed to establish a connection to a NATS
/// Streaming server.
// TODO: This will change as we firm up what the interaction between
// Habitat and A2 looks like.
pub struct EventConnectionInfo {
    pub name:        String,
    pub verbose:     bool,
    pub cluster_uri: String,
    pub cluster_id:  String,
}

/// Defines default connection information for a NATS Streaming server
/// running on localhost.
// TODO: As we become clear on the interaction between Habitat and A2,
// this implementation *may* disappear. It's useful for testing and
// prototyping, though.
impl Default for EventConnectionInfo {
    fn default() -> Self {
        EventConnectionInfo { name:        String::from("habitat"),
                              verbose:     true,
                              cluster_uri: String::from("127.0.0.1:4223"),
                              cluster_id:  String::from("test-cluster"), }
    }
}

pub(super) fn init_stream(conn_info: EventConnectionInfo) -> Result<EventStream> {
    // TODO (CM): Investigate back-pressure scenarios
    let (event_tx, event_rx) = unbounded();
    let (sync_tx, sync_rx) = sync_channel(0); // rendezvous channel

    // TODO (CM): We could theoretically create this future and spawn
    // it in the Supervisor's Tokio runtime, but there's currently a
    // bug: https://github.com/YellowInnovation/nitox/issues/24

    thread::Builder::new().name("events".to_string())
                          .spawn(move || {
                              let EventConnectionInfo { name,
                                                        verbose,
                                                        cluster_uri,
                                                        cluster_id, } = conn_info;

                              let cc = ConnectCommand::builder()
                // .user(Some("nats".to_string()))
                // .pass(Some("S3Cr3TP@5w0rD".to_string()))
                .name(Some(name))
                .verbose(verbose)
                .build()
                .unwrap();
                              let opts =
                                  NatsClientOptions::builder().connect_command(cc)
                                                              .cluster_uri(cluster_uri.as_str())
                                                              .build()
                                                              .unwrap();

                              let publisher = NatsClient::from_options(opts)
                .map_err(Into::<NatsStreamingError>::into)
                .and_then(|client| {
                    NatsStreamingClient::from(client)
                        .cluster_id(cluster_id)
                        .connect()
                })
                .map_err(|streaming_error| error!("{}", streaming_error))
                .and_then(move |client| {
                    sync_tx.send(()).expect("Couldn't synchronize!");
                    event_rx.for_each(move |event: Vec<u8>| {
                        let publish_event = client
                            .publish(HABITAT_SUBJECT.into(), event.into())
                            .map_err(|e| {
                                error!("Error publishing event: {:?}", e);
                            });
                        executor::spawn(publish_event);
                        Ok(())
                    })
                });

                              ThreadRuntime::new().expect("Couldn't create event stream runtime!")
                                                  .spawn(publisher)
                                                  .run()
                                                  .expect("something seriously wrong has occurred");
                          })
                          .expect("Couldn't start events thread!");

    sync_rx.recv()?; // TODO (CM): nicer error message
    Ok(EventStream(event_tx))
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Module which understands C++ constructor synthesis rules.

#[cfg_attr(test, derive(Eq, PartialEq))]
pub(super) struct ImplicitConstructorsNeeded {
    pub(super) default_constructor: bool,
    pub(super) copy_constructor_taking_t: bool,
    pub(super) copy_constructor_taking_const_t: bool,
    pub(super) move_constructor: bool,
}

#[derive(Default)]
pub(super) struct ExplicitItemsFound {
    pub(super) move_constructor: bool,
    pub(super) copy_constructor: bool,
    pub(super) any_other_constructor: bool,
    pub(super) any_bases_or_fields_lack_const_copy_constructors: bool,
    pub(super) any_bases_or_fields_have_deleted_or_inaccessible_copy_constructors: bool,
    pub(super) destructor: bool,
    pub(super) any_bases_have_deleted_or_inaccessible_destructors: bool,
    pub(super) copy_assignment_operator: bool,
    pub(super) move_assignment_operator: bool,
    pub(super) has_rvalue_reference_fields: bool,
}

pub(super) fn determine_implicit_constructors(
    explicits: ExplicitItemsFound,
) -> ImplicitConstructorsNeeded {
    let any_constructor =
        explicits.copy_constructor || explicits.move_constructor || explicits.any_other_constructor;
    // If no user-declared constructors of any kind are provided for a class type (struct, class, or union),
    // the compiler will always declare a default constructor as an inline public member of its class.
    let default_constructor = !any_constructor;

    // If no user-defined copy constructors are provided for a class type (struct, class, or union),
    // the compiler will always declare a copy constructor as a non-explicit inline public member of its class.
    // This implicitly-declared copy constructor has the form T::T(const T&) if all of the following are true:
    //  each direct and virtual base B of T has a copy constructor whose parameters are const B& or const volatile B&;
    //  each non-static data member M of T of class type or array of class type has a copy constructor whose parameters are const M& or const volatile M&.

    // The implicitly-declared or defaulted copy constructor for class T is defined as deleted if any of the following conditions are true:
    // T is a union-like class and has a variant member with non-trivial copy constructor; // we don't support unions anyway
    // T has a user-defined move constructor or move assignment operator (this condition only causes the implicitly-declared, not the defaulted, copy constructor to be deleted).
    // T has non-static data members that cannot be copied (have deleted, inaccessible, or ambiguous copy constructors);
    // T has direct or virtual base class that cannot be copied (has deleted, inaccessible, or ambiguous copy constructors);
    // T has direct or virtual base class with a deleted or inaccessible destructor;
    // T has a data member of rvalue reference type;
    let copy_constructor_is_deleted = explicits.move_constructor
        || explicits.move_assignment_operator
        || explicits.any_bases_or_fields_have_deleted_or_inaccessible_copy_constructors
        || explicits.any_bases_have_deleted_or_inaccessible_destructors
        || explicits.has_rvalue_reference_fields;

    let (copy_constructor_taking_const_t, copy_constructor_taking_t) =
        if explicits.copy_constructor || copy_constructor_is_deleted {
            (false, false)
        } else if explicits.any_bases_or_fields_lack_const_copy_constructors {
            (false, true)
        } else {
            (true, false)
        };

    // If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:
    // there are no user-declared copy constructors;
    // there are no user-declared copy assignment operators;
    // there are no user-declared move assignment operators;
    // there is no user-declared destructor.
    // then the compiler will declare a move constructor
    let move_constructor = !(explicits.move_constructor
        || explicits.copy_constructor
        || explicits.destructor
        || explicits.copy_assignment_operator
        || explicits.move_assignment_operator);

    ImplicitConstructorsNeeded {
        default_constructor,
        copy_constructor_taking_t,
        copy_constructor_taking_const_t,
        move_constructor,
    }
}

#[cfg(test)]
mod tests {
    use super::determine_implicit_constructors;

    use super::ExplicitItemsFound;

    #[test]
    fn test_simple() {
        let inputs = ExplicitItemsFound::default();
        let outputs = determine_implicit_constructors(inputs);
        assert!(outputs.default_constructor);
        assert!(outputs.copy_constructor_taking_const_t);
        assert!(!outputs.copy_constructor_taking_t);
        assert!(outputs.move_constructor);
    }

    #[test]
    fn test_with_destructor() {
        let inputs = ExplicitItemsFound {
            destructor: true,
            ..Default::default()
        };
        let outputs = determine_implicit_constructors(inputs);
        assert!(outputs.default_constructor);
        assert!(outputs.copy_constructor_taking_const_t);
        assert!(!outputs.copy_constructor_taking_t);
        assert!(!outputs.move_constructor);
    }

    #[test]
    fn test_with_pesky_base() {
        let inputs = ExplicitItemsFound {
            any_bases_or_fields_lack_const_copy_constructors: true,
            ..Default::default()
        };
        let outputs = determine_implicit_constructors(inputs);
        assert!(outputs.default_constructor);
        assert!(!outputs.copy_constructor_taking_const_t);
        assert!(outputs.copy_constructor_taking_t);
        assert!(!outputs.move_constructor);
    }

    #[test]
    fn test_with_user_defined_move_constructor() {
        let inputs = ExplicitItemsFound {
            move_constructor: true,
            ..Default::default()
        };
        let outputs = determine_implicit_constructors(inputs);
        assert!(!outputs.default_constructor);
        assert!(!outputs.copy_constructor_taking_const_t);
        assert!(!outputs.copy_constructor_taking_t);
        assert!(!outputs.move_constructor);
    }

    #[test]
    fn test_with_user_defined_misc_constructor() {
        let inputs = ExplicitItemsFound {
            any_other_constructor: true,
            ..Default::default()
        };
        let outputs = determine_implicit_constructors(inputs);
        assert!(!outputs.default_constructor);
        assert!(outputs.copy_constructor_taking_const_t);
        assert!(!outputs.copy_constructor_taking_t);
        assert!(outputs.move_constructor);
    }
}
<commit_msg>correct second dumb boo boo<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Module which understands C++ constructor synthesis rules.

#[cfg_attr(test, derive(Eq, PartialEq))]
pub(super) struct ImplicitConstructorsNeeded {
    pub(super) default_constructor: bool,
    pub(super) copy_constructor_taking_t: bool,
    pub(super) copy_constructor_taking_const_t: bool,
    pub(super) move_constructor: bool,
}

#[derive(Default)]
pub(super) struct ExplicitItemsFound {
    pub(super) move_constructor: bool,
    pub(super) copy_constructor: bool,
    pub(super) any_other_constructor: bool,
    pub(super) any_bases_or_fields_lack_const_copy_constructors: bool,
    pub(super) any_bases_or_fields_have_deleted_or_inaccessible_copy_constructors: bool,
    pub(super) destructor: bool,
    pub(super) any_bases_have_deleted_or_inaccessible_destructors: bool,
    pub(super) copy_assignment_operator: bool,
    pub(super) move_assignment_operator: bool,
    pub(super) has_rvalue_reference_fields: bool,
}

pub(super) fn determine_implicit_constructors(
    explicits: ExplicitItemsFound,
) -> ImplicitConstructorsNeeded {
    let any_constructor =
        explicits.copy_constructor || explicits.move_constructor || explicits.any_other_constructor;
    // If no user-declared constructors of any kind are provided for a class type (struct, class, or union),
    // the compiler will always declare a default constructor as an inline public member of its class.
    let default_constructor = !any_constructor;

    // If no user-defined copy constructors are provided for a class type (struct, class, or union),
    // the compiler will always declare a copy constructor as a non-explicit inline public member of its class.
    // This implicitly-declared copy constructor has the form T::T(const T&) if all of the following are true:
    //  each direct and virtual base B of T has a copy constructor whose parameters are const B& or const volatile B&;
    //  each non-static data member M of T of class type or array of class type has a copy constructor whose parameters are const M& or const volatile M&.

    // The implicitly-declared or defaulted copy constructor for class T is defined as deleted if any of the following conditions are true:
    // T is a union-like class and has a variant member with non-trivial copy constructor; // we don't support unions anyway
    // T has a user-defined move constructor or move assignment operator (this condition only causes the implicitly-declared, not the defaulted, copy constructor to be deleted).
    // T has non-static data members that cannot be copied (have deleted, inaccessible, or ambiguous copy constructors);
    // T has direct or virtual base class that cannot be copied (has deleted, inaccessible, or ambiguous copy constructors);
    // T has direct or virtual base class with a deleted or inaccessible destructor;
    // T has a data member of rvalue reference type;
    let copy_constructor_is_deleted = explicits.move_constructor
        || explicits.move_assignment_operator
        || explicits.any_bases_or_fields_have_deleted_or_inaccessible_copy_constructors
        || explicits.any_bases_have_deleted_or_inaccessible_destructors
        || explicits.has_rvalue_reference_fields;

    let (copy_constructor_taking_const_t, copy_constructor_taking_t) =
        if explicits.copy_constructor || copy_constructor_is_deleted {
            (false, false)
        } else if explicits.any_bases_or_fields_lack_const_copy_constructors {
            (false, true)
        } else {
            (true, false)
        };

    // If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:
    // there are no user-declared copy constructors;
    // there are no user-declared copy assignment operators;
    // there are no user-declared move assignment operators;
    // there is no user-declared destructor.
    // then the compiler will declare a move constructor
    let move_constructor = !(explicits.move_constructor
        || explicits.copy_constructor
        || explicits.destructor
        || explicits.copy_assignment_operator
        || explicits.move_assignment_operator);

    ImplicitConstructorsNeeded {
        default_constructor,
        copy_constructor_taking_t,
        copy_constructor_taking_const_t,
        move_constructor,
    }
}

#[cfg(test)]
mod tests {
    use super::determine_implicit_constructors;

    use super::ExplicitItemsFound;

    #[test]
    fn test_simple() {
        let inputs = ExplicitItemsFound::default();
        let outputs = determine_implicit_constructors(inputs);
        assert!(outputs.default_constructor);
        assert!(outputs.copy_constructor_taking_const_t);
        assert!(!outputs.copy_constructor_taking_t);
        assert!(outputs.move_constructor);
    }

    #[test]
    fn test_with_destructor() {
        let inputs = ExplicitItemsFound {
            destructor: true,
            ..Default::default()
        };
        let outputs = determine_implicit_constructors(inputs);
        assert!(outputs.default_constructor);
        assert!(outputs.copy_constructor_taking_const_t);
        assert!(!outputs.copy_constructor_taking_t);
        assert!(!outputs.move_constructor);
    }

    #[test]
    fn test_with_pesky_base() {
        let inputs = ExplicitItemsFound {
            any_bases_or_fields_lack_const_copy_constructors: true,
            ..Default::default()
        };
        let outputs = determine_implicit_constructors(inputs);
        assert!(outputs.default_constructor);
        assert!(!outputs.copy_constructor_taking_const_t);
        assert!(outputs.copy_constructor_taking_t);
        assert!(outputs.move_constructor);
    }

    #[test]
    fn test_with_user_defined_move_constructor() {
        let inputs = ExplicitItemsFound {
            move_constructor: true,
            ..Default::default()
        };
        let outputs = determine_implicit_constructors(inputs);
        assert!(!outputs.default_constructor);
        assert!(!outputs.copy_constructor_taking_const_t);
        assert!(!outputs.copy_constructor_taking_t);
        assert!(!outputs.move_constructor);
    }

    #[test]
    fn test_with_user_defined_misc_constructor() {
        let inputs = ExplicitItemsFound {
            any_other_constructor: true,
            ..Default::default()
        };
        let outputs = determine_implicit_constructors(inputs);
        assert!(!outputs.default_constructor);
        assert!(outputs.copy_constructor_taking_const_t);
        assert!(!outputs.copy_constructor_taking_t);
        assert!(outputs.move_constructor);
    }
}
<|endoftext|>


<commit_before>use minidump::Module;
pub use symbols_shim::*;

pub trait SymbolProvider {
    fn fill_symbol(&self, module: &dyn Module, frame: &mut dyn FrameSymbolizer);
    fn walk_frame(&self, module: &dyn Module, walker: &mut dyn FrameWalker) -> Option<()>;
}

#[derive(Default)]
pub struct MultiSymbolProvider {
    providers: Vec<Box<dyn SymbolProvider>>,
}

impl MultiSymbolProvider {
    pub fn new() -> MultiSymbolProvider {
        Default::default()
    }

    pub fn add(&mut self, provider: Box<dyn SymbolProvider>) {
        self.providers.push(provider);
    }
}

impl SymbolProvider for MultiSymbolProvider {
    fn fill_symbol(&self, module: &dyn Module, frame: &mut dyn FrameSymbolizer) {
        for p in self.providers.iter() {
            p.fill_symbol(module, frame);
        }
    }

    fn walk_frame(&self, module: &dyn Module, walker: &mut dyn FrameWalker) -> Option<()> {
        for p in self.providers.iter() {
            let result = p.walk_frame(module, walker);
            if result.is_some() {
                return result;
            }
        }
        None
    }
}

#[cfg(feature = "breakpad-syms")]
mod symbols_shim {
    use super::SymbolProvider;
    use minidump::Module;
    use std::collections::HashMap;
    use std::path::PathBuf;

    pub use breakpad_symbols::{FrameSymbolizer, FrameWalker, SymbolSupplier, Symbolizer};

    impl SymbolProvider for Symbolizer {
        fn fill_symbol(&self, module: &dyn Module, frame: &mut dyn FrameSymbolizer) {
            self.fill_symbol(module, frame);
        }
        fn walk_frame(&self, module: &dyn Module, walker: &mut dyn FrameWalker) -> Option<()> {
            self.walk_frame(module, walker)
        }
    }

    /// Gets a SymbolSupplier that looks up symbols by path or with urls.
    ///
    /// May use the `symbols_cache` path to store downloads.
    pub fn http_symbol_supplier(
        symbol_paths: Vec<PathBuf>,
        symbol_urls: Vec<String>,
        symbols_cache: PathBuf,
    ) -> impl SymbolSupplier {
        breakpad_symbols::HttpSymbolSupplier::new(symbol_urls, symbols_cache, symbol_paths)
    }

    /// Gets a SymbolSupplier that looks up symbols by path.
    pub fn simple_symbol_supplier(symbol_paths: Vec<PathBuf>) -> impl SymbolSupplier {
        breakpad_symbols::SimpleSymbolSupplier::new(symbol_paths)
    }

    /// Gets a mock SymbolSupplier that just maps module names
    /// to a string containing an entire breakpad .sym file, for tests.
    pub fn string_symbol_supplier(modules: HashMap<String, String>) -> impl SymbolSupplier {
        breakpad_symbols::StringSymbolSupplier::new(modules)
    }
}

#[cfg(feature = "symbolic-syms")]
mod symbols_shim {
    #![allow(dead_code)]

    use super::SymbolProvider;
    use minidump::Module;
    use std::collections::HashMap;
    use std::path::PathBuf;

    // Import symbolic here

    /// A trait for things that can locate symbols for a given module.
    pub trait SymbolSupplier {
        /// Locate and load a symbol file for `module`.
        ///
        /// Implementations may use any strategy for locating and loading
        /// symbols.
        fn locate_symbols(&self, module: &dyn Module) -> SymbolResult;
    }

    /// A trait for setting symbol information on something like a stack frame.
    pub trait FrameSymbolizer {
        /// Get the program counter value for this frame.
        fn get_instruction(&self) -> u64;
        /// Set the name, base address, and paramter size of the function in
        // which this frame is executing.
        fn set_function(&mut self, name: &str, base: u64, parameter_size: u32);
        /// Set the source file and (1-based) line number this frame represents.
        fn set_source_file(&mut self, file: &str, line: u32, base: u64);
    }

    pub trait FrameWalker {
        /// Get the instruction address that we're trying to unwind from.
        fn get_instruction(&self) -> u64;
        /// Get the number of bytes the callee's callee's parameters take up
        /// on the stack (or 0 if unknown/invalid). This is needed for
        /// STACK WIN unwinding.
        fn get_grand_callee_parameter_size(&self) -> u32;
        /// Get a register-sized value stored at this address.
        fn get_register_at_address(&self, address: u64) -> Option<u64>;
        /// Get the value of a register from the callee's frame.
        fn get_callee_register(&self, name: &str) -> Option<u64>;
        /// Set the value of a register for the caller's frame.
        fn set_caller_register(&mut self, name: &str, val: u64) -> Option<()>;
        /// Explicitly mark one of the caller's registers as invalid.
        fn clear_caller_register(&mut self, name: &str);
        /// Set whatever registers in the caller should be set based on the cfa (e.g. rsp).
        fn set_cfa(&mut self, val: u64) -> Option<()>;
        /// Set whatever registers in the caller should be set based on the return address (e.g. rip).
        fn set_ra(&mut self, val: u64) -> Option<()>;
    }

    /// Possible results of locating symbols. (can be opaque, not used externally)
    #[derive(Debug)]
    pub struct SymbolResult;

    /// Symbolicate stack frames.
    ///
    /// A `Symbolizer` manages loading symbols and looking up symbols in them
    /// including caching so that symbols for a given module are only loaded once.
    ///
    /// Call [`Symbolizer::new`][new] to instantiate a `Symbolizer`. A Symbolizer
    /// requires a [`SymbolSupplier`][supplier] to locate symbols. If you have
    /// symbols on disk in the [customary directory layout][dirlayout], a
    /// [`SimpleSymbolSupplier`][simple] will work.
    ///
    /// Use [`get_symbol_at_address`][get_symbol] or [`fill_symbol`][fill_symbol] to
    /// do symbol lookup.
    ///
    /// [new]: struct.Symbolizer.html#method.new
    /// [supplier]: trait.SymbolSupplier.html
    /// [dirlayout]: fn.relative_symbol_path.html
    /// [simple]: struct.SimpleSymbolSupplier.html
    /// [get_symbol]: struct.Symbolizer.html#method.get_symbol_at_address
    /// [fill_symbol]: struct.Symbolizer.html#method.fill_symbol
    pub struct Symbolizer {
        /// Symbol supplier for locating symbols.
        supplier: Box<dyn SymbolSupplier + 'static>,
    }

    impl Symbolizer {
        /// Create a `Symbolizer` that uses `supplier` to locate symbols.
        pub fn new<T: SymbolSupplier + 'static>(supplier: T) -> Symbolizer {
            Symbolizer {
                supplier: Box::new(supplier),
            }
        }
    }

    impl SymbolProvider for Symbolizer {
        fn fill_symbol(&self, _module: &dyn Module, _frame: &mut dyn FrameSymbolizer) {
            unimplemented!()
        }
        fn walk_frame(&self, _module: &dyn Module, _walker: &mut dyn FrameWalker) -> Option<()> {
            unimplemented!()
        }
    }

    pub struct HttpSymbolSupplier {}

    pub struct SimpleSymbolSupplier {}

    pub struct StringSymbolSupplier {}

    impl SymbolSupplier for HttpSymbolSupplier {
        fn locate_symbols(&self, _module: &dyn Module) -> SymbolResult {
            unimplemented!()
        }
    }

    impl SymbolSupplier for SimpleSymbolSupplier {
        fn locate_symbols(&self, _module: &dyn Module) -> SymbolResult {
            unimplemented!()
        }
    }

    impl SymbolSupplier for StringSymbolSupplier {
        fn locate_symbols(&self, _module: &dyn Module) -> SymbolResult {
            unimplemented!()
        }
    }

    /// Gets a SymbolSupplier that looks up symbols by path or with urls.
    ///
    /// May use the `symbols_cache` path to store downloads.
    pub fn http_symbol_supplier(
        _symbol_paths: Vec<PathBuf>,
        _symbol_urls: Vec<String>,
        _symbols_cache: PathBuf,
    ) -> impl SymbolSupplier {
        HttpSymbolSupplier {}
    }

    /// Gets a SymbolSupplier that looks up symbols by path.
    pub fn simple_symbol_supplier(_symbol_paths: Vec<PathBuf>) -> impl SymbolSupplier {
        SimpleSymbolSupplier {}
    }

    /// Gets a mock SymbolSupplier that just maps module names
    /// to a string containing an entire breakpad .sym file, for tests.
    pub fn string_symbol_supplier(_modules: HashMap<String, String>) -> impl SymbolSupplier {
        StringSymbolSupplier {}
    }
}
<commit_msg>SymbolSupplier::locate_symbol: Take self by mut ref<commit_after>use minidump::Module;
pub use symbols_shim::*;

pub trait SymbolProvider {
    fn fill_symbol(&self, module: &dyn Module, frame: &mut dyn FrameSymbolizer);
    fn walk_frame(&self, module: &dyn Module, walker: &mut dyn FrameWalker) -> Option<()>;
}

#[derive(Default)]
pub struct MultiSymbolProvider {
    providers: Vec<Box<dyn SymbolProvider>>,
}

impl MultiSymbolProvider {
    pub fn new() -> MultiSymbolProvider {
        Default::default()
    }

    pub fn add(&mut self, provider: Box<dyn SymbolProvider>) {
        self.providers.push(provider);
    }
}

impl SymbolProvider for MultiSymbolProvider {
    fn fill_symbol(&self, module: &dyn Module, frame: &mut dyn FrameSymbolizer) {
        for p in self.providers.iter() {
            p.fill_symbol(module, frame);
        }
    }

    fn walk_frame(&self, module: &dyn Module, walker: &mut dyn FrameWalker) -> Option<()> {
        for p in self.providers.iter() {
            let result = p.walk_frame(module, walker);
            if result.is_some() {
                return result;
            }
        }
        None
    }
}

#[cfg(feature = "breakpad-syms")]
mod symbols_shim {
    use super::SymbolProvider;
    use minidump::Module;
    use std::collections::HashMap;
    use std::path::PathBuf;

    pub use breakpad_symbols::{FrameSymbolizer, FrameWalker, SymbolSupplier, Symbolizer};

    impl SymbolProvider for Symbolizer {
        fn fill_symbol(&self, module: &dyn Module, frame: &mut dyn FrameSymbolizer) {
            self.fill_symbol(module, frame);
        }
        fn walk_frame(&self, module: &dyn Module, walker: &mut dyn FrameWalker) -> Option<()> {
            self.walk_frame(module, walker)
        }
    }

    /// Gets a SymbolSupplier that looks up symbols by path or with urls.
    ///
    /// May use the `symbols_cache` path to store downloads.
    pub fn http_symbol_supplier(
        symbol_paths: Vec<PathBuf>,
        symbol_urls: Vec<String>,
        symbols_cache: PathBuf,
    ) -> impl SymbolSupplier {
        breakpad_symbols::HttpSymbolSupplier::new(symbol_urls, symbols_cache, symbol_paths)
    }

    /// Gets a SymbolSupplier that looks up symbols by path.
    pub fn simple_symbol_supplier(symbol_paths: Vec<PathBuf>) -> impl SymbolSupplier {
        breakpad_symbols::SimpleSymbolSupplier::new(symbol_paths)
    }

    /// Gets a mock SymbolSupplier that just maps module names
    /// to a string containing an entire breakpad .sym file, for tests.
    pub fn string_symbol_supplier(modules: HashMap<String, String>) -> impl SymbolSupplier {
        breakpad_symbols::StringSymbolSupplier::new(modules)
    }
}

#[cfg(feature = "symbolic-syms")]
mod symbols_shim {
    #![allow(dead_code)]

    use super::SymbolProvider;
    use minidump::Module;
    use std::collections::HashMap;
    use std::path::PathBuf;

    // Import symbolic here

    /// A trait for things that can locate symbols for a given module.
    pub trait SymbolSupplier {
        /// Locate and load a symbol file for `module`.
        ///
        /// Implementations may use any strategy for locating and loading
        /// symbols.
        fn locate_symbols(&mut self, module: &dyn Module) -> SymbolResult;
    }

    /// A trait for setting symbol information on something like a stack frame.
    pub trait FrameSymbolizer {
        /// Get the program counter value for this frame.
        fn get_instruction(&self) -> u64;
        /// Set the name, base address, and paramter size of the function in
        // which this frame is executing.
        fn set_function(&mut self, name: &str, base: u64, parameter_size: u32);
        /// Set the source file and (1-based) line number this frame represents.
        fn set_source_file(&mut self, file: &str, line: u32, base: u64);
    }

    pub trait FrameWalker {
        /// Get the instruction address that we're trying to unwind from.
        fn get_instruction(&self) -> u64;
        /// Get the number of bytes the callee's callee's parameters take up
        /// on the stack (or 0 if unknown/invalid). This is needed for
        /// STACK WIN unwinding.
        fn get_grand_callee_parameter_size(&self) -> u32;
        /// Get a register-sized value stored at this address.
        fn get_register_at_address(&self, address: u64) -> Option<u64>;
        /// Get the value of a register from the callee's frame.
        fn get_callee_register(&self, name: &str) -> Option<u64>;
        /// Set the value of a register for the caller's frame.
        fn set_caller_register(&mut self, name: &str, val: u64) -> Option<()>;
        /// Explicitly mark one of the caller's registers as invalid.
        fn clear_caller_register(&mut self, name: &str);
        /// Set whatever registers in the caller should be set based on the cfa (e.g. rsp).
        fn set_cfa(&mut self, val: u64) -> Option<()>;
        /// Set whatever registers in the caller should be set based on the return address (e.g. rip).
        fn set_ra(&mut self, val: u64) -> Option<()>;
    }

    /// Possible results of locating symbols. (can be opaque, not used externally)
    #[derive(Debug)]
    pub struct SymbolResult;

    /// Symbolicate stack frames.
    ///
    /// A `Symbolizer` manages loading symbols and looking up symbols in them
    /// including caching so that symbols for a given module are only loaded once.
    ///
    /// Call [`Symbolizer::new`][new] to instantiate a `Symbolizer`. A Symbolizer
    /// requires a [`SymbolSupplier`][supplier] to locate symbols. If you have
    /// symbols on disk in the [customary directory layout][dirlayout], a
    /// [`SimpleSymbolSupplier`][simple] will work.
    ///
    /// Use [`get_symbol_at_address`][get_symbol] or [`fill_symbol`][fill_symbol] to
    /// do symbol lookup.
    ///
    /// [new]: struct.Symbolizer.html#method.new
    /// [supplier]: trait.SymbolSupplier.html
    /// [dirlayout]: fn.relative_symbol_path.html
    /// [simple]: struct.SimpleSymbolSupplier.html
    /// [get_symbol]: struct.Symbolizer.html#method.get_symbol_at_address
    /// [fill_symbol]: struct.Symbolizer.html#method.fill_symbol
    pub struct Symbolizer {
        /// Symbol supplier for locating symbols.
        supplier: Box<dyn SymbolSupplier + 'static>,
    }

    impl Symbolizer {
        /// Create a `Symbolizer` that uses `supplier` to locate symbols.
        pub fn new<T: SymbolSupplier + 'static>(supplier: T) -> Symbolizer {
            Symbolizer {
                supplier: Box::new(supplier),
            }
        }
    }

    impl SymbolProvider for Symbolizer {
        fn fill_symbol(&self, _module: &dyn Module, _frame: &mut dyn FrameSymbolizer) {
            unimplemented!()
        }
        fn walk_frame(&self, _module: &dyn Module, _walker: &mut dyn FrameWalker) -> Option<()> {
            unimplemented!()
        }
    }

    pub struct HttpSymbolSupplier {}

    pub struct SimpleSymbolSupplier {}

    pub struct StringSymbolSupplier {}

    impl SymbolSupplier for HttpSymbolSupplier {
        fn locate_symbols(&self, _module: &dyn Module) -> SymbolResult {
            unimplemented!()
        }
    }

    impl SymbolSupplier for SimpleSymbolSupplier {
        fn locate_symbols(&self, _module: &dyn Module) -> SymbolResult {
            unimplemented!()
        }
    }

    impl SymbolSupplier for StringSymbolSupplier {
        fn locate_symbols(&self, _module: &dyn Module) -> SymbolResult {
            unimplemented!()
        }
    }

    /// Gets a SymbolSupplier that looks up symbols by path or with urls.
    ///
    /// May use the `symbols_cache` path to store downloads.
    pub fn http_symbol_supplier(
        _symbol_paths: Vec<PathBuf>,
        _symbol_urls: Vec<String>,
        _symbols_cache: PathBuf,
    ) -> impl SymbolSupplier {
        HttpSymbolSupplier {}
    }

    /// Gets a SymbolSupplier that looks up symbols by path.
    pub fn simple_symbol_supplier(_symbol_paths: Vec<PathBuf>) -> impl SymbolSupplier {
        SimpleSymbolSupplier {}
    }

    /// Gets a mock SymbolSupplier that just maps module names
    /// to a string containing an entire breakpad .sym file, for tests.
    pub fn string_symbol_supplier(_modules: HashMap<String, String>) -> impl SymbolSupplier {
        StringSymbolSupplier {}
    }
}
<|endoftext|>