<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::ptr;
use std::rc::Rc;
use std::str;

use super::flat_pairs::{self, FlatPairs};
use super::pair::{self, Pair};
use super::queueable_token::QueueableToken;
use super::tokens::{self, Tokens};
use RuleType;

/// An iterator over [`Pair`]s. It is created by [`pest::state`] and [`Pair::into_inner`].
///
/// [`Pair`]: struct.Pair.html
/// [`pest::state`]: ../fn.state.html
/// [`Pair::into_inner`]: struct.Pair.html#method.into_inner
#[derive(Clone)]
pub struct Pairs<'i, R> {
    queue: Rc<Vec<QueueableToken<R>>>,
    input: &'i [u8],
    start: usize,
    end: usize
}

pub fn new<R: RuleType>(
    queue: Rc<Vec<QueueableToken<R>>>,
    input: &[u8],
    start: usize,
    end: usize
) -> Pairs<R> {
    Pairs {
        queue,
        input,
        start,
        end
    }
}

impl<'i, R: RuleType> Pairs<'i, R> {
    /// Captures a slice from the `&str` defined by the starting position of the first token `Pair`
    /// and the ending position of the last token `Pair` of the `Pairs`. This also captures
    /// the input between those two token `Pair`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "a b";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pairs with Rule::a and Rule::b ...
    /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
    /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
    /// }).unwrap();
    ///
    /// assert_eq!(pairs.as_str(), "a b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        let start = self.pos(self.start);
        let end = self.pos(self.end - 1);

        // Generated positions always come from Positions and are UTF-8 borders.
        unsafe { str::from_utf8_unchecked(&self.input[start..end]) }
    }

    /// Captures inner token `Pair`s and concatenates resulting `&str`s. This does not capture
    /// the input between token `Pair`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "a b";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pairs with Rule::a and Rule::b ...
    /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
    /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
    /// }).unwrap();
    ///
    /// assert_eq!(pairs.concat(), "ab");
    /// ```
    #[inline]
    pub fn concat(&self) -> String {
        self.clone().fold(String::new(), |string, pair| string + pair.as_str())
    }

    /// Flattens the `Pairs`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "";
    /// let pairs = pest::state(input, |state| {
    ///     // generating nested Token pair with Rule::b inside Rule::a
    /// #     state.rule(Rule::a, |state| {
    /// #         state.rule(Rule::b, |s| Ok(s))
    /// #     })
    /// }).unwrap();
    /// let tokens: Vec<_> = pairs.flatten().tokens().collect();
    ///
    /// assert_eq!(tokens.len(), 4);
    /// ```
    #[inline]
    pub fn flatten(self) -> FlatPairs<'i, R> {
        flat_pairs::new(self.queue, self.input, self.start, self.end)
    }

    /// Returns the `Tokens` for the `Pairs`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a
    /// }
    ///
    /// let input = "";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pair with Rule::a ...
    /// #     state.rule(Rule::a, |s| Ok(s))
    /// }).unwrap();
    /// let tokens: Vec<_> = pairs.tokens().collect();
    ///
    /// assert_eq!(tokens.len(), 2);
    /// ```
    #[inline]
    pub fn tokens(self) -> Tokens<'i, R> {
        tokens::new(self.queue, self.input, self.start, self.end)
    }

    fn pair(&self) -> usize {
        match self.queue[self.start] {
            QueueableToken::Start {
                end_token_index, ..
            } => end_token_index,
            _ => unreachable!()
        }
    }

    fn pair_from_end(&self) -> usize {
        match self.queue[self.end - 1] {
            QueueableToken::End {
                start_token_index, ..
            } => start_token_index,
            _ => unreachable!()
        }
    }

    fn pos(&self, index: usize) -> usize {
        match self.queue[index] {
            QueueableToken::Start { input_pos, .. } | QueueableToken::End { input_pos, .. } => {
                input_pos
            }
        }
    }
}

impl<'i, R: RuleType> Iterator for Pairs<'i, R> {
    type Item = Pair<'i, R>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.start >= self.end {
            return None;
        }

        let pair = pair::new(Rc::clone(&self.queue), self.input, self.start);

        self.start = self.pair() + 1;

        Some(pair)
    }
}

impl<'i, R: RuleType> DoubleEndedIterator for Pairs<'i, R> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.end <= self.start {
            return None;
        }

        self.end = self.pair_from_end();

        let pair = pair::new(Rc::clone(&self.queue), self.input, self.end);

        Some(pair)
    }
}

impl<'i, R: RuleType> fmt::Debug for Pairs<'i, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_list().entries(self.clone()).finish()
    }
}

impl<'i, R: RuleType> fmt::Display for Pairs<'i, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "[{}]",
            self.clone()
                .map(|pair| format!("{}", pair))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }
}

impl<'i, R: PartialEq> PartialEq for Pairs<'i, R> {
    fn eq(&self, other: &Pairs<'i, R>) -> bool {
        Rc::ptr_eq(&self.queue, &other.queue) && ptr::eq(self.input, other.input)
            && self.start == other.start && self.end == other.end
    }
}

impl<'i, R: Eq> Eq for Pairs<'i, R> {}

impl<'i, R: Hash> Hash for Pairs<'i, R> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (&*self.queue as *const Vec<QueueableToken<R>>).hash(state);
        (self.input as *const [u8]).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

#[cfg(test)]
mod tests {
    use super::super::super::Parser;
    use super::super::super::macros::tests::*;

    #[test]
    fn as_str() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(pairs.as_str(), "abcde");
    }

    #[test]
    fn concat() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(pairs.concat(), "abce");
    }

    #[test]
    fn pairs_debug() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(
            format!("{:?}", pairs),
            "[\
                Pair { rule: a, span: Span { str: \"abc\", start: 0, end: 3 }, inner: [\
                    Pair { rule: b, span: Span { str: \"b\", start: 1, end: 2 }, inner: [] }\
                ] }, \
                Pair { rule: c, span: Span { str: \"e\", start: 4, end: 5 }, inner: [] }\
            ]"
        .to_owned()
        );
    }

    #[test]
    fn pairs_display() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(
            format!("{}", pairs),
            "[a(0, 3, [b(1, 2)]), c(4, 5)]".to_owned()
        );
    }

    #[test]
    fn iter_for_pairs() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
        assert_eq!(
            pairs.map(|p| p.as_rule()).collect::<Vec<Rule>>(),
            vec![Rule::a, Rule::c]
        );
    }

    #[test]
    fn double_ended_iter_for_pairs() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
        assert_eq!(
            pairs.rev().map(|p| p.as_rule()).collect::<Vec<Rule>>(),
            vec![Rule::c, Rule::a]
        );
    }
}
<commit_msg>peek_front<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::ptr;
use std::rc::Rc;
use std::str;

use super::flat_pairs::{self, FlatPairs};
use super::pair::{self, Pair};
use super::queueable_token::QueueableToken;
use super::tokens::{self, Tokens};
use RuleType;

/// An iterator over [`Pair`]s. It is created by [`pest::state`] and [`Pair::into_inner`].
///
/// [`Pair`]: struct.Pair.html
/// [`pest::state`]: ../fn.state.html
/// [`Pair::into_inner`]: struct.Pair.html#method.into_inner
#[derive(Clone)]
pub struct Pairs<'i, R> {
    queue: Rc<Vec<QueueableToken<R>>>,
    input: &'i [u8],
    start: usize,
    end: usize
}

pub fn new<R: RuleType>(
    queue: Rc<Vec<QueueableToken<R>>>,
    input: &[u8],
    start: usize,
    end: usize
) -> Pairs<R> {
    Pairs {
        queue,
        input,
        start,
        end
    }
}

impl<'i, R: RuleType> Pairs<'i, R> {
    /// Captures a slice from the `&str` defined by the starting position of the first token `Pair`
    /// and the ending position of the last token `Pair` of the `Pairs`. This also captures
    /// the input between those two token `Pair`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "a b";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pairs with Rule::a and Rule::b ...
    /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
    /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
    /// }).unwrap();
    ///
    /// assert_eq!(pairs.as_str(), "a b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        let start = self.pos(self.start);
        let end = self.pos(self.end - 1);

        // Generated positions always come from Positions and are UTF-8 borders.
        unsafe { str::from_utf8_unchecked(&self.input[start..end]) }
    }

    /// Captures inner token `Pair`s and concatenates resulting `&str`s. This does not capture
    /// the input between token `Pair`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "a b";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pairs with Rule::a and Rule::b ...
    /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
    /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
    /// }).unwrap();
    ///
    /// assert_eq!(pairs.concat(), "ab");
    /// ```
    #[inline]
    pub fn concat(&self) -> String {
        self.clone().fold(String::new(), |string, pair| string + pair.as_str())
    }

    /// Flattens the `Pairs`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a,
    ///     b
    /// }
    ///
    /// let input = "";
    /// let pairs = pest::state(input, |state| {
    ///     // generating nested Token pair with Rule::b inside Rule::a
    /// #     state.rule(Rule::a, |state| {
    /// #         state.rule(Rule::b, |s| Ok(s))
    /// #     })
    /// }).unwrap();
    /// let tokens: Vec<_> = pairs.flatten().tokens().collect();
    ///
    /// assert_eq!(tokens.len(), 4);
    /// ```
    #[inline]
    pub fn flatten(self) -> FlatPairs<'i, R> {
        flat_pairs::new(self.queue, self.input, self.start, self.end)
    }

    /// Returns the `Tokens` for the `Pairs`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::rc::Rc;
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {
    ///     a
    /// }
    ///
    /// let input = "";
    /// let pairs = pest::state(input, |state| {
    ///     // generating Token pair with Rule::a ...
    /// #     state.rule(Rule::a, |s| Ok(s))
    /// }).unwrap();
    /// let tokens: Vec<_> = pairs.tokens().collect();
    ///
    /// assert_eq!(tokens.len(), 2);
    /// ```
    #[inline]
    pub fn tokens(self) -> Tokens<'i, R> {
        tokens::new(self.queue, self.input, self.start, self.end)
    }

    #[inline]
    pub fn peek(&mut self) -> Option<<Self as Iterator>::Item> {
        if self.start < self.end {
            Some(pair::new(Rc::clone(&self.queue), self.input, self.start))
        } else {
            None
        }
        if self.start >= self.end {
            return None;
        }
    }

    fn pair(&self) -> usize {
        match self.queue[self.start] {
            QueueableToken::Start {
                end_token_index, ..
            } => end_token_index,
            _ => unreachable!()
        }
    }

    fn pair_from_end(&self) -> usize {
        match self.queue[self.end - 1] {
            QueueableToken::End {
                start_token_index, ..
            } => start_token_index,
            _ => unreachable!()
        }
    }

    fn pos(&self, index: usize) -> usize {
        match self.queue[index] {
            QueueableToken::Start { input_pos, .. } | QueueableToken::End { input_pos, .. } => {
                input_pos
            }
        }
    }
}

impl<'i, R: RuleType> Iterator for Pairs<'i, R> {
    type Item = Pair<'i, R>;

    fn next(&mut self) -> Option<Self::Item> {
        let pair = self.peek()?;
        self.start = self.pair() + 1;
        Some(pair)
    }
}

impl<'i, R: RuleType> DoubleEndedIterator for Pairs<'i, R> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.end <= self.start {
            return None;
        }

        self.end = self.pair_from_end();

        let pair = pair::new(Rc::clone(&self.queue), self.input, self.end);

        Some(pair)
    }
}

impl<'i, R: RuleType> fmt::Debug for Pairs<'i, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_list().entries(self.clone()).finish()
    }
}

impl<'i, R: RuleType> fmt::Display for Pairs<'i, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "[{}]",
            self.clone()
                .map(|pair| format!("{}", pair))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }
}

impl<'i, R: PartialEq> PartialEq for Pairs<'i, R> {
    fn eq(&self, other: &Pairs<'i, R>) -> bool {
        Rc::ptr_eq(&self.queue, &other.queue) && ptr::eq(self.input, other.input)
            && self.start == other.start && self.end == other.end
    }
}

impl<'i, R: Eq> Eq for Pairs<'i, R> {}

impl<'i, R: Hash> Hash for Pairs<'i, R> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (&*self.queue as *const Vec<QueueableToken<R>>).hash(state);
        (self.input as *const [u8]).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

#[cfg(test)]
mod tests {
    use super::super::super::Parser;
    use super::super::super::macros::tests::*;

    #[test]
    fn as_str() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(pairs.as_str(), "abcde");
    }

    #[test]
    fn concat() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(pairs.concat(), "abce");
    }

    #[test]
    fn pairs_debug() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(
            format!("{:?}", pairs),
            "[\
                Pair { rule: a, span: Span { str: \"abc\", start: 0, end: 3 }, inner: [\
                    Pair { rule: b, span: Span { str: \"b\", start: 1, end: 2 }, inner: [] }\
                ] }, \
                Pair { rule: c, span: Span { str: \"e\", start: 4, end: 5 }, inner: [] }\
            ]"
        .to_owned()
        );
    }

    #[test]
    fn pairs_display() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();

        assert_eq!(
            format!("{}", pairs),
            "[a(0, 3, [b(1, 2)]), c(4, 5)]".to_owned()
        );
    }

    #[test]
    fn iter_for_pairs() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
        assert_eq!(
            pairs.map(|p| p.as_rule()).collect::<Vec<Rule>>(),
            vec![Rule::a, Rule::c]
        );
    }

    #[test]
    fn double_ended_iter_for_pairs() {
        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
        assert_eq!(
            pairs.rev().map(|p| p.as_rule()).collect::<Vec<Rule>>(),
            vec![Rule::c, Rule::a]
        );
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

pub mod account;
pub mod common;
pub mod config;
pub mod genesis;
pub mod move_tool;
pub mod node;
pub mod op;
pub mod test;

use crate::common::types::{CliCommand, CliResult};
use clap::Parser;

/// CLI tool for interacting with the Aptos blockchain and nodes
///
#[derive(Parser)]
#[clap(name = "aptos", author, version, propagate_version = true)]
pub enum Tool {
    #[clap(subcommand)]
    Account(account::AccountTool),
    #[clap(subcommand)]
    Config(config::ConfigTool),
    #[clap(subcommand)]
    Genesis(genesis::GenesisTool),
    Init(common::init::InitTool),
    #[clap(subcommand)]
    Key(op::key::KeyTool),
    #[clap(subcommand)]
    Move(move_tool::MoveTool),
    #[clap(subcommand)]
    Node(node::NodeTool),
}

impl Tool {
    pub async fn execute(self) -> CliResult {
        use Tool::*;
        match self {
            Account(tool) => tool.execute().await,
            Config(tool) => tool.execute().await,
            Genesis(tool) => tool.execute().await,
            // TODO: Replace entirely with config init
            Init(tool) => tool.execute_serialized_success().await,
            Key(tool) => tool.execute().await,
            Move(tool) => tool.execute().await,
            Node(tool) => tool.execute().await,
        }
    }
}
<commit_msg>[aptos-cli] Add ability to show build information<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

pub mod account;
pub mod common;
pub mod config;
pub mod genesis;
pub mod move_tool;
pub mod node;
pub mod op;
pub mod test;

use crate::common::types::{CliCommand, CliResult, CliTypedResult};
use async_trait::async_trait;
use clap::Parser;
use std::collections::BTreeMap;

shadow_rs::shadow!(build);

/// CLI tool for interacting with the Aptos blockchain and nodes
///
#[derive(Parser)]
#[clap(name = "aptos", author, version, propagate_version = true)]
pub enum Tool {
    #[clap(subcommand)]
    Account(account::AccountTool),
    #[clap(subcommand)]
    Config(config::ConfigTool),
    #[clap(subcommand)]
    Genesis(genesis::GenesisTool),
    Info(InfoTool),
    Init(common::init::InitTool),
    #[clap(subcommand)]
    Key(op::key::KeyTool),
    #[clap(subcommand)]
    Move(move_tool::MoveTool),
    #[clap(subcommand)]
    Node(node::NodeTool),
}

impl Tool {
    pub async fn execute(self) -> CliResult {
        use Tool::*;
        match self {
            Account(tool) => tool.execute().await,
            Config(tool) => tool.execute().await,
            Genesis(tool) => tool.execute().await,
            Info(tool) => tool.execute_serialized().await,
            // TODO: Replace entirely with config init
            Init(tool) => tool.execute_serialized_success().await,
            Key(tool) => tool.execute().await,
            Move(tool) => tool.execute().await,
            Node(tool) => tool.execute().await,
        }
    }
}

/// Show information about the build of the CLI
///
/// This is useful for debugging as well as determining what versions are compatible with the CLI
#[derive(Parser)]
pub struct InfoTool {}

#[async_trait]
impl CliCommand<BTreeMap<String, String>> for InfoTool {
    fn command_name(&self) -> &'static str {
        "GetCLIInfo"
    }

    async fn execute(self) -> CliTypedResult<BTreeMap<String, String>> {
        let mut build_information: std::collections::BTreeMap<String, String> = BTreeMap::new();
        build_information.insert(
            aptos_telemetry::build_information::BUILD_BRANCH.into(),
            build::BRANCH.into(),
        );
        build_information.insert(
            aptos_telemetry::build_information::BUILD_CARGO_VERSION.into(),
            build::CARGO_VERSION.into(),
        );
        build_information.insert(
            aptos_telemetry::build_information::BUILD_COMMIT_HASH.into(),
            build::COMMIT_HASH.into(),
        );
        build_information.insert(
            aptos_telemetry::build_information::BUILD_OS.into(),
            build::BUILD_OS.into(),
        );
        build_information.insert(
            aptos_telemetry::build_information::BUILD_PKG_VERSION.into(),
            build::PKG_VERSION.into(),
        );
        build_information.insert(
            aptos_telemetry::build_information::BUILD_RUST_CHANNEL.into(),
            build::RUST_CHANNEL.into(),
        );
        build_information.insert(
            aptos_telemetry::build_information::BUILD_RUST_VERSION.into(),
            build::RUST_VERSION.into(),
        );
        Ok(build_information)
    }
}

pub fn build_commit_hash() -> String {
    build::COMMIT_HASH.to_string()
}
<|endoftext|>


<commit_before>use super::RootMove;
use super::super::MAX_THREADS;
use super::root_moves_list::{RootMoveList,RawRootMoveList};

use std::heap::{Alloc, Layout, Heap};
use std::ptr::Unique;
use std::sync::Arc;
use std::sync::atomic::{Ordering,AtomicUsize,fence,compiler_fence};
use std::mem;

use std::iter::{Iterator,IntoIterator};

use pleco::Board;
use pleco::board::movegen::{MoveGen,Legal};
use pleco::core::mono_traits::AllGenType;

struct RawRmManager {
    pub rms: [RawRootMoveList; MAX_THREADS]
}

impl RawRmManager {
    pub fn new() -> Unique<RawRmManager> {
        unsafe {
            println!("Raw RMManager create: start");
            let ptr = Heap.alloc_zeroed(Layout::array::<RawRootMoveList>(MAX_THREADS).unwrap());
            println!("Raw RMManager create: created ptr");
            let new_ptr = match ptr {
                Ok(ptr) => ptr,
                Err(err) => Heap.oom(err),
            };
            println!("Raw RMManager create: created new_ptr");
            let raw = Unique::new(new_ptr as *mut RawRmManager).unwrap();
            println!("Raw RMManager create: created raw Unique");
            println!("Creating up to {} RMs...",MAX_THREADS );
//            for x in 0..MAX_THREADS {
//                print!("Attempt {} :", x);
//                let mut list = mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(raw.as_ptr())
//                    .offset(x as isize);
//
////                let raw_list: &mut RawRootMoveList = (*raw.as_ptr()).rms.get_unchecked_mut(x);
//                print!(" raw_list ... ");
//                (*list).init();
////                raw_list.init();
//                println!("Made raw list");
//            }
//            println!("Raw RMManager create: Done!");
            raw
        }
    }
}

pub struct RmManager {
    threads: Arc<AtomicUsize>,
    moves: Unique<RawRmManager>,
    ref_count: Arc<AtomicUsize>
}

unsafe impl Send for RmManager {}

impl Clone for RmManager {
    fn clone(&self) -> Self {
        let ref_count: Arc<AtomicUsize> = self.ref_count.clone();
        ref_count.fetch_add(1, Ordering::SeqCst);
        RmManager {
            threads: self.threads.clone(),
            moves: self.moves.clone(),
            ref_count
        }
    }
}

impl RmManager {
    pub fn new() -> Self {
        println!("Creating RmManager");
        let mut rms = RmManager {
            threads: Arc::new(AtomicUsize::new(0)),
            moves: RawRmManager::new(),
            ref_count: Arc::new(AtomicUsize::new(1))
        };
        for thread in 0..MAX_THREADS {
            unsafe {
                let mut rm = rms.get_list_unchecked(thread);
                rm.init();
            }
        }
        rms
    }

    pub fn threads(&self) -> usize {
        self.threads.load(Ordering::Relaxed)
    }

    pub fn add_thread(&mut self) -> Option<RootMoveList> {
        if self.threads() >= MAX_THREADS {
            None
        } else {
            let thread_idx = self.threads.fetch_add(1, Ordering::SeqCst);
            unsafe {
                Some(self.get_list_unchecked(thread_idx))
            }
        }
    }

    pub fn get_list(&self, num: usize) -> Option<RootMoveList> {
        if num >= self.threads() {
            None
        } else {
            unsafe {
                Some(self.get_list_unchecked(num))
            }
        }
    }

    pub unsafe fn get_list_unchecked(&self, num: usize) -> RootMoveList {
        RootMoveList {
            moves: self.as_raw_ptr().offset(num as isize)
        }
    }

    pub unsafe fn replace_moves(&mut self, board: &Board) {
        let legal_moves = MoveGen::generate::<Legal, AllGenType>(&board);
        let mut first = self.as_ptr();
        first.replace(&legal_moves);
        let num = self.threads();
        for i in 1..num {
            self.get_list_unchecked(i).clone_from_other(&first);
        }
    }

    pub unsafe fn as_ptr(&self) -> RootMoveList {
        RootMoveList {
            moves: mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(self.moves.as_ptr())
        }
    }

    unsafe fn as_raw_ptr(&self) -> *mut RawRootMoveList {
        mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(self.moves.as_ptr())
    }

    pub fn wait_for_finish(&self) {
        unsafe {
            for i in 0..self.threads() {
                fence(Ordering::AcqRel);
                compiler_fence(Ordering::AcqRel);
                let root_moves = self.get_list_unchecked(i).moves;
                (*root_moves).finished.await(true);
            }
        }
    }
    pub fn wait_for_start(&self) {
        unsafe {
            let num_threads = self.threads();
            for i in 0..num_threads {
                fence(Ordering::AcqRel);
                compiler_fence(Ordering::AcqRel);
                let root_moves = self.get_list_unchecked(i).moves;
                (*root_moves).finished.await(false);
            }
        }
    }

    pub fn reset_depths(&self) {
        unsafe {
            for i in 0..self.threads() {
                self.get_list_unchecked(i).set_depth_completed(0);
            }
        }
    }

    pub fn thread_best_move_and_depth(&self, thread_id: usize) -> (RootMove, u16) {
        unsafe {
            let mut thread = self.get_list_unchecked(thread_id);
            (thread.first().clone(), thread.depth_completed())
        }

    }

    pub fn best_rootmove(&self, use_stdout: bool) -> RootMove {
        let (mut best_root_move, mut depth_reached): (RootMove, u16) = self.thread_best_move_and_depth(0);
        if use_stdout {
            println!("id: 0, value: {}, prev_value: {}, depth: {}, depth_comp: {}, mov: {}", best_root_move.score, best_root_move.prev_score, best_root_move.depth_reached,depth_reached, best_root_move.bit_move);
        }

        for x in 1..self.threads() {
            let (thread_move, thread_depth): (RootMove, u16)  = self.thread_best_move_and_depth(x);
            let depth_diff = thread_depth as i32 - depth_reached as i32;
            let value_diff = thread_move.score - best_root_move.score;
            if x != 0 {
                // If it has a bigger value and greater or equal depth
                if value_diff > 0 && depth_diff >= 0 {
                    best_root_move = thread_move;
                    depth_reached = thread_depth;
                }
            }

            if use_stdout {
                println!("id: {}, value: {}, prev_value: {}, depth: {}, depth_comp: {}, mov: {}",x, thread_move.score, thread_move.prev_score, thread_move.depth_reached,thread_depth, thread_move.bit_move);
            }
        }
        best_root_move
    }
}

pub struct RootMovesIter<'a> {
    root_moves: &'a RmManager,
    threads: usize,
    idx: usize,
}

impl<'a> Iterator for RootMovesIter<'a> {
    type Item = RootMoveList;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.idx >= self.threads {
            None
        } else {
            unsafe {
                Some(self.root_moves.get_list_unchecked(self.idx))
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.threads - self.idx, Some(self.threads - self.idx))
    }
}

impl<'a> IntoIterator for &'a RmManager {
    type Item = RootMoveList;
    type IntoIter = RootMovesIter<'a>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        RootMovesIter {
            root_moves: &self,
            threads: self.threads(),
            idx: 0,
        }
    }
}

impl Drop for RmManager {
    fn drop(&mut self) {
        let num = self.ref_count.fetch_sub(1, Ordering::SeqCst);
        if num == 1 {
            unsafe {
                Heap.dealloc(self.as_raw_ptr() as *mut _,
                             Layout::array::<RawRootMoveList>(MAX_THREADS).unwrap());
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn rm_basic() {
        let mut rms = RmManager::new();
        assert_eq!(rms.threads(), 0);
        let moves_1 = rms.add_thread().unwrap();
        assert_eq!(rms.threads(), 1);
        assert_eq!(moves_1.len(), 0);
        let board = Board::default();
        unsafe {
            rms.replace_moves(&board);
            let moves_1_clone = rms.get_list_unchecked(0);
            assert_eq!(moves_1.len(), moves_1_clone.len());
            let moves_2 = rms.add_thread().unwrap();
            assert_eq!(rms.threads(), 2);
            rms.replace_moves(&board);
            let moves_2_clone = rms.get_list_unchecked(0);
            assert_eq!(moves_2.len(), moves_2_clone.len());
            assert_eq!(moves_1.len(), moves_2_clone.len());
        }
    }

    #[test]
    fn rm_cloning() {
        let mut rms = RmManager::new();
        let rmsc = rms.clone();
        rms.add_thread();
        rms.add_thread();
        assert_eq!(rms.threads(), rmsc.threads());
    }
}<commit_msg>More attempssdd<commit_after>use super::RootMove;
use super::super::MAX_THREADS;
use super::root_moves_list::{RootMoveList,RawRootMoveList};

use std::heap::{Alloc, Layout, Heap};
use std::ptr::Unique;
use std::sync::Arc;
use std::sync::atomic::{Ordering,AtomicUsize,fence,compiler_fence};
use std::mem;

use std::iter::{Iterator,IntoIterator};

use pleco::Board;
use pleco::board::movegen::{MoveGen,Legal};
use pleco::core::mono_traits::AllGenType;

struct RawRmManager {
    pub rms: [RawRootMoveList; MAX_THREADS]
}

impl RawRmManager {
    pub fn new() -> Unique<RawRmManager> {
        unsafe {
            println!("Raw RMManager create: start");
            let ptr = Heap.alloc_zeroed(Layout::array::<RawRootMoveList>(MAX_THREADS).unwrap());
            println!("Raw RMManager create: created ptr");
            let new_ptr = match ptr {
                Ok(ptr) => ptr,
                Err(err) => Heap.oom(err),
            };
            println!("Raw RMManager create: created new_ptr");
            let raw = Unique::new(new_ptr as *mut RawRmManager).unwrap();
//            for x in 0..MAX_THREADS {
//                print!("Attempt {} :", x);
//                let mut list = mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(raw.as_ptr())
//                    .offset(x as isize);
//
//                let raw_list: &mut RawRootMoveList = (*raw.as_ptr()).rms.get_unchecked_mut(x);
//                print!(" raw_list ... ");
//                (*list).init();
//                raw_list.init();
//                println!("Made raw list");
//            }
//            println!("Raw RMManager create: Done!");
            println!("Raw RMManager created raw ptr! Success");
            raw
        }
    }
}

pub struct RmManager {
    threads: Arc<AtomicUsize>,
    moves: Unique<RawRmManager>,
    ref_count: Arc<AtomicUsize>
}

unsafe impl Send for RmManager {}

impl Clone for RmManager {
    fn clone(&self) -> Self {
        let ref_count: Arc<AtomicUsize> = self.ref_count.clone();
        ref_count.fetch_add(1, Ordering::SeqCst);
        RmManager {
            threads: self.threads.clone(),
            moves: self.moves.clone(),
            ref_count
        }
    }
}

impl RmManager {
    pub fn new() -> Self {
        println!("Creating RmManager");
        let mut rms = RmManager {
            threads: Arc::new(AtomicUsize::new(0)),
            moves: RawRmManager::new(),
            ref_count: Arc::new(AtomicUsize::new(1))
        };
        println!("Created RM Manager");
        for thread in 0..MAX_THREADS {
            unsafe {
                println!("Made raw list");
                let mut rm = rms.get_list_unchecked(thread);
                print!(" raw_list ... ");
                rm.init();
                println!("Made raw list");
            }
        }
        rms
    }

    pub fn threads(&self) -> usize {
        self.threads.load(Ordering::Relaxed)
    }

    pub fn add_thread(&mut self) -> Option<RootMoveList> {
        if self.threads() >= MAX_THREADS {
            None
        } else {
            let thread_idx = self.threads.fetch_add(1, Ordering::SeqCst);
            unsafe {
                Some(self.get_list_unchecked(thread_idx))
            }
        }
    }

    pub fn get_list(&self, num: usize) -> Option<RootMoveList> {
        if num >= self.threads() {
            None
        } else {
            unsafe {
                Some(self.get_list_unchecked(num))
            }
        }
    }

    pub unsafe fn get_list_unchecked(&self, num: usize) -> RootMoveList {
        RootMoveList {
            moves: self.as_raw_ptr().offset(num as isize)
        }
    }

    pub unsafe fn replace_moves(&mut self, board: &Board) {
        let legal_moves = MoveGen::generate::<Legal, AllGenType>(&board);
        let mut first = self.as_ptr();
        first.replace(&legal_moves);
        let num = self.threads();
        for i in 1..num {
            self.get_list_unchecked(i).clone_from_other(&first);
        }
    }

    pub unsafe fn as_ptr(&self) -> RootMoveList {
        RootMoveList {
            moves: mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(self.moves.as_ptr())
        }
    }

    unsafe fn as_raw_ptr(&self) -> *mut RawRootMoveList {
        mem::transmute::<*mut RawRmManager, *mut RawRootMoveList>(self.moves.as_ptr())
    }

    pub fn wait_for_finish(&self) {
        unsafe {
            for i in 0..self.threads() {
                fence(Ordering::AcqRel);
                compiler_fence(Ordering::AcqRel);
                let root_moves = self.get_list_unchecked(i).moves;
                (*root_moves).finished.await(true);
            }
        }
    }
    pub fn wait_for_start(&self) {
        unsafe {
            let num_threads = self.threads();
            for i in 0..num_threads {
                fence(Ordering::AcqRel);
                compiler_fence(Ordering::AcqRel);
                let root_moves = self.get_list_unchecked(i).moves;
                (*root_moves).finished.await(false);
            }
        }
    }

    pub fn reset_depths(&self) {
        unsafe {
            for i in 0..self.threads() {
                self.get_list_unchecked(i).set_depth_completed(0);
            }
        }
    }

    pub fn thread_best_move_and_depth(&self, thread_id: usize) -> (RootMove, u16) {
        unsafe {
            let mut thread = self.get_list_unchecked(thread_id);
            (thread.first().clone(), thread.depth_completed())
        }

    }

    pub fn best_rootmove(&self, use_stdout: bool) -> RootMove {
        let (mut best_root_move, mut depth_reached): (RootMove, u16) = self.thread_best_move_and_depth(0);
        if use_stdout {
            println!("id: 0, value: {}, prev_value: {}, depth: {}, depth_comp: {}, mov: {}", best_root_move.score, best_root_move.prev_score, best_root_move.depth_reached,depth_reached, best_root_move.bit_move);
        }

        for x in 1..self.threads() {
            let (thread_move, thread_depth): (RootMove, u16)  = self.thread_best_move_and_depth(x);
            let depth_diff = thread_depth as i32 - depth_reached as i32;
            let value_diff = thread_move.score - best_root_move.score;
            if x != 0 {
                // If it has a bigger value and greater or equal depth
                if value_diff > 0 && depth_diff >= 0 {
                    best_root_move = thread_move;
                    depth_reached = thread_depth;
                }
            }

            if use_stdout {
                println!("id: {}, value: {}, prev_value: {}, depth: {}, depth_comp: {}, mov: {}",x, thread_move.score, thread_move.prev_score, thread_move.depth_reached,thread_depth, thread_move.bit_move);
            }
        }
        best_root_move
    }
}

pub struct RootMovesIter<'a> {
    root_moves: &'a RmManager,
    threads: usize,
    idx: usize,
}

impl<'a> Iterator for RootMovesIter<'a> {
    type Item = RootMoveList;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.idx >= self.threads {
            None
        } else {
            unsafe {
                Some(self.root_moves.get_list_unchecked(self.idx))
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.threads - self.idx, Some(self.threads - self.idx))
    }
}

impl<'a> IntoIterator for &'a RmManager {
    type Item = RootMoveList;
    type IntoIter = RootMovesIter<'a>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        RootMovesIter {
            root_moves: &self,
            threads: self.threads(),
            idx: 0,
        }
    }
}

impl Drop for RmManager {
    fn drop(&mut self) {
        let num = self.ref_count.fetch_sub(1, Ordering::SeqCst);
        if num == 1 {
            unsafe {
                Heap.dealloc(self.as_raw_ptr() as *mut _,
                             Layout::array::<RawRootMoveList>(MAX_THREADS).unwrap());
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn rm_basic() {
        let mut rms = RmManager::new();
        assert_eq!(rms.threads(), 0);
        let moves_1 = rms.add_thread().unwrap();
        assert_eq!(rms.threads(), 1);
        assert_eq!(moves_1.len(), 0);
        let board = Board::default();
        unsafe {
            rms.replace_moves(&board);
            let moves_1_clone = rms.get_list_unchecked(0);
            assert_eq!(moves_1.len(), moves_1_clone.len());
            let moves_2 = rms.add_thread().unwrap();
            assert_eq!(rms.threads(), 2);
            rms.replace_moves(&board);
            let moves_2_clone = rms.get_list_unchecked(0);
            assert_eq!(moves_2.len(), moves_2_clone.len());
            assert_eq!(moves_1.len(), moves_2_clone.len());
        }
    }

    #[test]
    fn rm_cloning() {
        let mut rms = RmManager::new();
        let rmsc = rms.clone();
        rms.add_thread();
        rms.add_thread();
        assert_eq!(rms.threads(), rmsc.threads());
    }
}<|endoftext|>


<commit_before>#![allow(unused_variables,unused_must_use)]
extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate tiny_http;
extern crate ureq;

use std::thread;
use sozu_command::proxy;
use sozu_command::channel::Channel;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::logging::{Logger,LoggerBackend};
use tiny_http::{Server, Response};
use std::{
    io::{stdout, Read, Write},
    net::{TcpListener,TcpStream,ToSocketAddrs},
    time::Duration,
    sync::{Arc, Barrier},
    str
};

#[test]
fn test() {
    Logger::init("EXAMPLE".to_string(), "debug", LoggerBackend::Stdout(stdout()), None);

    info!("starting up");

    let config = proxy::HttpListener {
        front: "127.0.0.1:8080".parse().expect("could not parse address"),
        ..Default::default()
    };

    let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");

    let jg = thread::spawn(move || {
        Logger::init("SOZU".to_string(), "trace", LoggerBackend::Stdout(stdout()), None);
        let max_buffers = 20;
        let buffer_size = 16384;
        sozu::http::start(config, channel, max_buffers, buffer_size);
    });

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_Status"),
        order: proxy::ProxyRequestData::Status
    });

    // wait for sozu to start and answer
    info!("Status -> {:?}", command.read_message());

    let agent = ureq::AgentBuilder::new()
        .resolver(|addr: &str| match addr {
            "example.com:8080" => Ok(vec![([127,0,0,1], 8080).into()]),
            addr => addr.to_socket_addrs().map(Iterator::collect),
        })
    .build();

    info!("expecting 404");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(404, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_front = proxy::HttpFront {
        app_id:     String::from("test"),
        address:    "127.0.0.1:8080".parse().unwrap(),
        hostname:   String::from("example.com"),
        path_begin: String::from("/"),
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_ABCD"),
        order: proxy::ProxyRequestData::AddHttpFront(http_front)
    });
    println!("HTTP -> {:?}", command.read_message());

    info!("expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    println!("HTTP -> {:?}", command.read_message());

    info!("sending invalid request, expecting 400");
    let mut client = TcpStream::connect(("127.0.0.1", 8080)).expect("could not parse address");
    // 1 seconds of timeout
    client.set_read_timeout(Some(Duration::new(1,0)));

    let w = client.write(&b"HELLO\r\n\r\n"[..]);
    println!("http client write: {:?}", w);

    let expected_answer = "HTTP/1.1 400 Bad Request\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n";
    let mut buffer = [0;4096];
    let mut index = 0;

    let r = client.read(&mut buffer[..]);
    println!("http client read: {:?}", r);
    match r {
        Err(e)      => assert!(false, "client request should not fail. Error: {:?}",e),
        Ok(sz) => {
            index += sz;
            let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
            println!("Response: {}", answer);
        }
    }

    let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
    println!("Response: {}", answer);
    assert_eq!(answer, expected_answer);

    let barrier = Arc::new(Barrier::new(2));
    let barrier2 = barrier.clone();

    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"TEST\r\n\r\n";
        stream.write(&response[..]).unwrap();
    });

    barrier.wait();
    info!("expecting 502");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(502, res) => {
                assert_eq!(res.status_text(), "Bad Gateway");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"HTTP/1.1 200 Ok\r\nConnection: close\r\nContent-Length: 5\r\n\r\nHello";
        stream.write(&response[..]).unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("expecting 200 then close");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.status_text(), "Ok");
    assert_eq!(res.header("Content-Length"), Some("5"));
    assert_eq!(res.into_string().unwrap(), "Hello");

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let stream = listener.incoming().next().unwrap().unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("server closes, expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                println!("res: {:?}", res);
                assert_eq!(res.status_text(), "Service Unavailable");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    start_server(2048, barrier.clone());

    barrier.wait();
    info!("expecting 200");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);

    //let _ = jg.join();
    info!("good bye");
}

fn start_server(port: u16, barrier: Arc<Barrier>) {
    thread::spawn(move|| {
        let server = Server::http(&format!("127.0.0.1:{}", port)).expect("could not create server");
        info!("starting web server in port {}", port);

        barrier.wait();
        for request in server.incoming_requests() {
            println!("backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
                     request.method(),
                     request.url(),
                     request.headers()
                    );

            let response = Response::from_string("hello world");
            request.respond(response).unwrap();
            println!("backend web server sent response");
            println!("server session stopped");
        }

        println!("server on port {} closed", port);
    });
}
<commit_msg>test for Expect: 100-Continue requests<commit_after>#![allow(unused_variables,unused_must_use)]
extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate tiny_http;
extern crate ureq;

use std::thread;
use sozu_command::proxy;
use sozu_command::channel::Channel;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::logging::{Logger,LoggerBackend};
use tiny_http::{Server, Response};
use std::{
    io::{stdout, Read, Write},
    net::{TcpListener,TcpStream,ToSocketAddrs},
    time::Duration,
    sync::{Arc, Barrier},
    str
};

#[test]
fn test() {
    Logger::init("EXAMPLE".to_string(), "debug", LoggerBackend::Stdout(stdout()), None);

    info!("starting up");

    let config = proxy::HttpListener {
        front: "127.0.0.1:8080".parse().expect("could not parse address"),
        ..Default::default()
    };

    let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");

    let jg = thread::spawn(move || {
        Logger::init("SOZU".to_string(), "trace", LoggerBackend::Stdout(stdout()), None);
        let max_buffers = 20;
        let buffer_size = 16384;
        sozu::http::start(config, channel, max_buffers, buffer_size);
    });

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_Status"),
        order: proxy::ProxyRequestData::Status
    });

    // wait for sozu to start and answer
    info!("Status -> {:?}", command.read_message());

    let agent = ureq::AgentBuilder::new()
        .resolver(|addr: &str| match addr {
            "example.com:8080" => Ok(vec![([127,0,0,1], 8080).into()]),
            addr => addr.to_socket_addrs().map(Iterator::collect),
        })
    .build();

    info!("expecting 404");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(404, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_front = proxy::HttpFront {
        app_id:     String::from("test"),
        address:    "127.0.0.1:8080".parse().unwrap(),
        hostname:   String::from("example.com"),
        path_begin: String::from("/"),
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_ABCD"),
        order: proxy::ProxyRequestData::AddHttpFront(http_front)
    });
    println!("HTTP -> {:?}", command.read_message());

    info!("expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    println!("HTTP -> {:?}", command.read_message());

    info!("sending invalid request, expecting 400");
    let mut client = TcpStream::connect(("127.0.0.1", 8080)).expect("could not parse address");
    // 1 seconds of timeout
    client.set_read_timeout(Some(Duration::new(1,0)));

    let w = client.write(&b"HELLO\r\n\r\n"[..]);
    println!("http client write: {:?}", w);

    let expected_answer = "HTTP/1.1 400 Bad Request\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n";
    let mut buffer = [0;4096];
    let mut index = 0;

    let r = client.read(&mut buffer[..]);
    println!("http client read: {:?}", r);
    match r {
        Err(e)      => assert!(false, "client request should not fail. Error: {:?}",e),
        Ok(sz) => {
            index += sz;
            let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
            println!("Response: {}", answer);
        }
    }

    let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
    println!("Response: {}", answer);
    assert_eq!(answer, expected_answer);

    let barrier = Arc::new(Barrier::new(2));
    let barrier2 = barrier.clone();

    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"TEST\r\n\r\n";
        stream.write(&response[..]).unwrap();
    });

    barrier.wait();
    info!("expecting 502");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(502, res) => {
                assert_eq!(res.status_text(), "Bad Gateway");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"HTTP/1.1 200 Ok\r\nConnection: close\r\nContent-Length: 5\r\n\r\nHello";
        stream.write(&response[..]).unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("expecting 200 then close");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.status_text(), "Ok");
    assert_eq!(res.header("Content-Length"), Some("5"));
    assert_eq!(res.into_string().unwrap(), "Hello");

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let stream = listener.incoming().next().unwrap().unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("server closes, expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                println!("res: {:?}", res);
                assert_eq!(res.status_text(), "Service Unavailable");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    start_server(2048, barrier.clone());

    barrier.wait();
    info!("expecting 200");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.into_string().unwrap(), "hello world");

    //let _ = jg.join();
    //barrier.wait();
    info!("expecting 200");
    let res = agent
        .get("http://example.com:8080/100")
        .set("Expect", "100-continue")
        .call().unwrap();
    assert_eq!(res.status(), 100);
    assert_eq!(res.header("Content-Length"), Some("1024"));

    // check that there's no actual body
    /*let mut reader = res.into_reader();
    let mut buf = [0u8; 1024];
    // we should do that in async, to add a short timeout
    assert!(reader.read(&mut buf).is_err());
    */

    info!("good bye");
}

fn start_server(port: u16, barrier: Arc<Barrier>) {
    thread::spawn(move|| {
        let server = Server::http(&format!("127.0.0.1:{}", port)).expect("could not create server");
        info!("starting web server in port {}", port);

        barrier.wait();
        for request in server.incoming_requests() {
            eprintln!("backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
                     request.method(),
                     request.url(),
                     request.headers()
                    );
            eprintln!("url: {:?}", request.url());

            if request.url() == "/100" {
                let response = Response::new(
                    tiny_http::StatusCode(100),
                    vec![tiny_http::Header::from_bytes(&b"Content-Length"[..], &b"1024"[..]).unwrap()],
                    &b""[..],
                    None,
                    None);
                request.respond(response).unwrap();
            } else {
                let response = Response::from_string("hello world");
                request.respond(response).unwrap();
            }

            eprintln!("backend web server sent response");
            eprintln!("server session stopped");
        }

        eprintln!("server on port {} closed", port);
    });
}
<|endoftext|>


<commit_before>#![allow(unused_variables,unused_must_use)]
extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate tiny_http;
extern crate ureq;

use std::thread;
use sozu_command::proxy;
use sozu_command::channel::Channel;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::logging::{Logger,LoggerBackend};
use tiny_http::{Server, Response};
use std::{
    io::{stdout, Read, Write},
    net::{TcpListener,TcpStream,ToSocketAddrs},
    time::Duration,
    sync::{Arc, Barrier},
    str
};

#[test]
fn test() {
    Logger::init("EXAMPLE".to_string(), "debug", LoggerBackend::Stdout(stdout()), None);

    info!("starting up");

    let config = proxy::HttpListener {
        front: "127.0.0.1:8080".parse().expect("could not parse address"),
        ..Default::default()
    };

    let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");

    let jg = thread::spawn(move || {
        Logger::init("SOZU".to_string(), "trace", LoggerBackend::Stdout(stdout()), None);
        let max_buffers = 20;
        let buffer_size = 16384;
        sozu::http::start(config, channel, max_buffers, buffer_size);
    });

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_Status"),
        order: proxy::ProxyRequestData::Status
    });

    // wait for sozu to start and answer
    info!("Status -> {:?}", command.read_message());

    let agent = ureq::AgentBuilder::new()
        .resolver(|addr: &str| match addr {
            "example.com:8080" => Ok(vec![([127,0,0,1], 8080).into()]),
            addr => addr.to_socket_addrs().map(Iterator::collect),
        })
    .build();

    info!("expecting 404");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(404, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_front = proxy::HttpFront {
        app_id:     String::from("test"),
        address:    "127.0.0.1:8080".parse().unwrap(),
        hostname:   String::from("example.com"),
        path_begin: String::from("/"),
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_ABCD"),
        order: proxy::ProxyRequestData::AddHttpFront(http_front)
    });
    println!("HTTP -> {:?}", command.read_message());

    info!("expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    println!("HTTP -> {:?}", command.read_message());

    info!("sending invalid request, expecting 400");
    let mut client = TcpStream::connect(("127.0.0.1", 8080)).expect("could not parse address");
    // 1 seconds of timeout
    client.set_read_timeout(Some(Duration::new(1,0)));

    let w = client.write(&b"HELLO\r\n\r\n"[..]);
    println!("http client write: {:?}", w);

    let expected_answer = "HTTP/1.1 400 Bad Request\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n";
    let mut buffer = [0;4096];
    let mut index = 0;

    let r = client.read(&mut buffer[..]);
    println!("http client read: {:?}", r);
    match r {
        Err(e)      => assert!(false, "client request should not fail. Error: {:?}",e),
        Ok(sz) => {
            index += sz;
            let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
            println!("Response: {}", answer);
        }
    }

    let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
    println!("Response: {}", answer);
    assert_eq!(answer, expected_answer);

    let barrier = Arc::new(Barrier::new(2));
    let barrier2 = barrier.clone();

    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"TEST\r\n\r\n";
        stream.write(&response[..]).unwrap();
    });

    barrier.wait();
    info!("expecting 502");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(502, res) => {
                assert_eq!(res.status_text(), "Bad Gateway");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"HTTP/1.1 200 Ok\r\nConnection: close\r\nContent-Length: 5\r\n\r\nHello";
        stream.write(&response[..]).unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("expecting 200 then close");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.status_text(), "Ok");
    assert_eq!(res.header("Content-Length"), Some("5"));
    assert_eq!(res.into_string().unwrap(), "Hello");

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\nHello world!";
        stream.write(&response[..]).unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("expecting 200 then close, without content length");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.status_text(), "Ok");
    assert_eq!(res.into_string().unwrap(), "Hello world!");

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let stream = listener.incoming().next().unwrap().unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("server closes, expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                println!("res: {:?}", res);
                assert_eq!(res.status_text(), "Service Unavailable");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    start_server(2048, barrier.clone());

    barrier.wait();
    info!("expecting 200");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.into_string().unwrap(), "hello world");

    //let _ = jg.join();
    //barrier.wait();
    info!("expecting 100");
    let res = agent
        .get("http://example.com:8080/100")
        .set("Expect", "100-continue")
        .call().unwrap();
    assert_eq!(res.status(), 100);
    assert_eq!(res.header("Content-Length"), Some("1024"));

    // check that there's no actual body
    /*let mut reader = res.into_reader();
    let mut buf = [0u8; 1024];
    // we should do that in async, to add a short timeout
    assert!(reader.read(&mut buf).is_err());
    */

    info!("good bye");
}

fn start_server(port: u16, barrier: Arc<Barrier>) {
    thread::spawn(move|| {
        let server = Server::http(&format!("127.0.0.1:{}", port)).expect("could not create server");
        info!("starting web server in port {}", port);

        barrier.wait();
        for request in server.incoming_requests() {
            eprintln!("backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
                     request.method(),
                     request.url(),
                     request.headers()
                    );
            eprintln!("url: {:?}", request.url());

            if request.url() == "/100" {
                let response = Response::new(
                    tiny_http::StatusCode(100),
                    vec![tiny_http::Header::from_bytes(&b"Content-Length"[..], &b"1024"[..]).unwrap()],
                    &b""[..],
                    None,
                    None);
                request.respond(response).unwrap();
            } else {
                let response = Response::from_string("hello world");
                request.respond(response).unwrap();
            }

            eprintln!("backend web server sent response");
            eprintln!("server session stopped");
        }

        eprintln!("server on port {} closed", port);
    });
}
<commit_msg>add a test for protocol upgrades<commit_after>#![allow(unused_variables,unused_must_use)]
extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate tiny_http;
extern crate ureq;

use std::thread;
use sozu_command::proxy;
use sozu_command::channel::Channel;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::logging::{Logger,LoggerBackend};
use tiny_http::{Server, Response};
use std::{
    io::{stdout, Read, Write},
    net::{TcpListener,TcpStream,ToSocketAddrs},
    time::Duration,
    sync::{Arc, Barrier},
    str
};

#[test]
fn test() {
    Logger::init("EXAMPLE".to_string(), "debug", LoggerBackend::Stdout(stdout()), None);

    info!("starting up");

    let config = proxy::HttpListener {
        front: "127.0.0.1:8080".parse().expect("could not parse address"),
        ..Default::default()
    };

    let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");

    let jg = thread::spawn(move || {
        Logger::init("SOZU".to_string(), "trace", LoggerBackend::Stdout(stdout()), None);
        let max_buffers = 20;
        let buffer_size = 16384;
        sozu::http::start(config, channel, max_buffers, buffer_size);
    });

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_Status"),
        order: proxy::ProxyRequestData::Status
    });

    // wait for sozu to start and answer
    info!("Status -> {:?}", command.read_message());

    let agent = ureq::AgentBuilder::new()
        .resolver(|addr: &str| match addr {
            "example.com:8080" => Ok(vec![([127,0,0,1], 8080).into()]),
            addr => addr.to_socket_addrs().map(Iterator::collect),
        })
    .build();

    info!("expecting 404");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(404, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_front = proxy::HttpFront {
        app_id:     String::from("test"),
        address:    "127.0.0.1:8080".parse().unwrap(),
        hostname:   String::from("example.com"),
        path_begin: String::from("/"),
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_ABCD"),
        order: proxy::ProxyRequestData::AddHttpFront(http_front)
    });
    println!("HTTP -> {:?}", command.read_message());

    info!("expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    println!("HTTP -> {:?}", command.read_message());

    info!("sending invalid request, expecting 400");
    let mut client = TcpStream::connect(("127.0.0.1", 8080)).expect("could not parse address");
    // 1 seconds of timeout
    client.set_read_timeout(Some(Duration::new(1,0)));

    let w = client.write(&b"HELLO\r\n\r\n"[..]);
    println!("http client write: {:?}", w);

    let expected_answer = "HTTP/1.1 400 Bad Request\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n";
    let mut buffer = [0;4096];
    let mut index = 0;

    let r = client.read(&mut buffer[..]);
    println!("http client read: {:?}", r);
    match r {
        Err(e)      => assert!(false, "client request should not fail. Error: {:?}",e),
        Ok(sz) => {
            index += sz;
            let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
            println!("Response: {}", answer);
        }
    }

    let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
    println!("Response: {}", answer);
    assert_eq!(answer, expected_answer);

    let barrier = Arc::new(Barrier::new(2));
    let barrier2 = barrier.clone();

    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"TEST\r\n\r\n";
        stream.write(&response[..]).unwrap();
    });

    barrier.wait();
    info!("expecting 502");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(502, res) => {
                assert_eq!(res.status_text(), "Bad Gateway");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"HTTP/1.1 200 Ok\r\nConnection: close\r\nContent-Length: 5\r\n\r\nHello";
        stream.write(&response[..]).unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("expecting 200 then close");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.status_text(), "Ok");
    assert_eq!(res.header("Content-Length"), Some("5"));
    assert_eq!(res.into_string().unwrap(), "Hello");

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\nHello world!";
        stream.write(&response[..]).unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("expecting 200 then close, without content length");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.status_text(), "Ok");
    assert_eq!(res.into_string().unwrap(), "Hello world!");

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let stream = listener.incoming().next().unwrap().unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("server closes, expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                println!("res: {:?}", res);
                assert_eq!(res.status_text(), "Service Unavailable");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: WebSocket\r\n\r\n";
        stream.write(&response[..]).unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("expecting upgrade (101 switching protocols)");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    println!("res: {:?}", res);
    assert_eq!(res.status(), 101);
    assert_eq!(res.header("Upgrade"), Some("WebSocket"));
    assert_eq!(res.header("Connection"), Some("Upgrade"));
    info!("good bye");

    start_server(2048, barrier.clone());

    barrier.wait();
    info!("expecting 200");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.into_string().unwrap(), "hello world");

    //let _ = jg.join();
    //barrier.wait();
    info!("expecting 100");
    let res = agent
        .get("http://example.com:8080/100")
        .set("Expect", "100-continue")
        .call().unwrap();
    assert_eq!(res.status(), 100);
    assert_eq!(res.header("Content-Length"), Some("1024"));

    // check that there's no actual body
    /*let mut reader = res.into_reader();
    let mut buf = [0u8; 1024];
    // we should do that in async, to add a short timeout
    assert!(reader.read(&mut buf).is_err());
    */

    info!("good bye");
}

fn start_server(port: u16, barrier: Arc<Barrier>) {
    thread::spawn(move|| {
        let server = Server::http(&format!("127.0.0.1:{}", port)).expect("could not create server");
        info!("starting web server in port {}", port);

        barrier.wait();
        for request in server.incoming_requests() {
            eprintln!("backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
                     request.method(),
                     request.url(),
                     request.headers()
                    );
            eprintln!("url: {:?}", request.url());

            if request.url() == "/100" {
                let response = Response::new(
                    tiny_http::StatusCode(100),
                    vec![tiny_http::Header::from_bytes(&b"Content-Length"[..], &b"1024"[..]).unwrap()],
                    &b""[..],
                    None,
                    None);
                request.respond(response).unwrap();
            } else {
                let response = Response::from_string("hello world");
                request.respond(response).unwrap();
            }

            eprintln!("backend web server sent response");
            eprintln!("server session stopped");
        }

        eprintln!("server on port {} closed", port);
    });
}
<|endoftext|>


<commit_before>#![feature(test)]
#![feature(clone_from_slice)]

extern crate test;
extern crate collenchyma as co;
extern crate rblas;
extern crate rand;

use test::Bencher;
use co::backend::{Backend, BackendConfig};
use co::frameworks::Native;
use co::framework::IFramework;
use co::shared_memory::{SharedMemory, ITensor, TensorR0, TensorR1};
use co::libraries::blas::IBlas;
use rblas::Dot;

use rand::{thread_rng, Rng};

fn backend() -> Backend<Native> {
    let framework = Native::new();
    let hardwares = framework.hardwares();
    let backend_config = BackendConfig::new(framework, hardwares);
    Backend::new(backend_config).unwrap()
}

#[bench]
fn bench_1000_dot_100_rblas(b: &mut Bencher) {
    let mut rng = thread_rng();
    let slice_a = rng.gen_iter::<f32>().take(100).collect::<Vec<f32>>();
    let slice_b = rng.gen_iter::<f32>().take(100).collect::<Vec<f32>>();

    b.iter(|| {
        for _ in 0..1000 {
            let res = Dot::dot(&slice_a, &slice_b);
            test::black_box(res);
        }
    });
}

#[bench]
fn bench_1000_dot_100_collenchyma(b: &mut Bencher) {
    let mut rng = thread_rng();
    let slice_a = rng.gen_iter::<f32>().take(100).collect::<Vec<f32>>();
    let slice_b = rng.gen_iter::<f32>().take(100).collect::<Vec<f32>>();

    let backend = backend();
    let shared_a = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([100])).unwrap();
    let shared_b = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([100])).unwrap();
    let shared_res = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR0::new()).unwrap();
    shared_a.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_a);
    shared_b.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_b);
    let _ = backend.dot(shared_a, shared_b, shared_res);
    bench_1000_dot_100_collenchyma_profile(b, &backend, shared_a, shared_b, shared_res);
}

#[inline(never)]
fn bench_1000_dot_100_collenchyma_profile(
    b: &mut Bencher,
    backend: &Backend<Native>,
    shared_a: &mut SharedMemory<f32, TensorR1>,
    shared_b: &mut SharedMemory<f32, TensorR1>,
    shared_res: &mut SharedMemory<f32, TensorR0>
) {
    b.iter(|| {
        for _ in 0..1000 {
            let _ = backend.dot(shared_a, shared_b, shared_res);
        }
    });
}

#[bench]
fn bench_100_dot_1000_rblas(b: &mut Bencher) {
    let mut rng = thread_rng();
    let slice_a = rng.gen_iter::<f32>().take(1000).collect::<Vec<f32>>();
    let slice_b = rng.gen_iter::<f32>().take(1000).collect::<Vec<f32>>();

    b.iter(|| {
        for _ in 0..100 {
            let res = Dot::dot(&slice_a, &slice_b);
            test::black_box(res);
        }
    });
}

#[bench]
fn bench_100_dot_1000_collenchyma(b: &mut Bencher) {
    let mut rng = thread_rng();
    let slice_a = rng.gen_iter::<f32>().take(1000).collect::<Vec<f32>>();
    let slice_b = rng.gen_iter::<f32>().take(1000).collect::<Vec<f32>>();

    let backend = backend();
    let shared_a = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([1000])).unwrap();
    let shared_b = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([1000])).unwrap();
    let shared_res = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR0::new()).unwrap();
    shared_a.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_a);
    shared_b.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_b);
    let _ = backend.dot(shared_a, shared_b, shared_res);
    bench_100_dot_1000_collenchyma_profile(b, &backend, shared_a, shared_b, shared_res);
}

#[inline(never)]
fn bench_100_dot_1000_collenchyma_profile(
    b: &mut Bencher,
    backend: &Backend<Native>,
    shared_a: &mut SharedMemory<f32, TensorR1>,
    shared_b: &mut SharedMemory<f32, TensorR1>,
    shared_res: &mut SharedMemory<f32, TensorR0>
) {
    b.iter(|| {
        for _ in 0..100 {
            let _ = backend.dot(shared_a, shared_b, shared_res);
        }
    });
}

#[bench]
fn bench_50_dot_2000_collenchyma(b: &mut Bencher) {
    let mut rng = thread_rng();
    let slice_a = rng.gen_iter::<f32>().take(2000).collect::<Vec<f32>>();
    let slice_b = rng.gen_iter::<f32>().take(2000).collect::<Vec<f32>>();

    let backend = backend();
    let shared_a = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([2000])).unwrap();
    let shared_b = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([2000])).unwrap();
    let shared_res = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR0::new()).unwrap();
    shared_a.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_a);
    shared_b.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_b);
    let _ = backend.dot(shared_a, shared_b, shared_res);
    bench_50_dot_2000_collenchyma_profile(b, &backend, shared_a, shared_b, shared_res);
}

#[inline(never)]
fn bench_50_dot_2000_collenchyma_profile(
    b: &mut Bencher,
    backend: &Backend<Native>,
    shared_a: &mut SharedMemory<f32, TensorR1>,
    shared_b: &mut SharedMemory<f32, TensorR1>,
    shared_res: &mut SharedMemory<f32, TensorR0>
) {
    b.iter(|| {
        for _ in 0..50 {
            let _ = backend.dot(shared_a, shared_b, shared_res);
        }
    });
}

#[bench]
fn bench_10_dot_10000_rblas(b: &mut Bencher) {
    let mut rng = thread_rng();
    let slice_a = rng.gen_iter::<f32>().take(10000).collect::<Vec<f32>>();
    let slice_b = rng.gen_iter::<f32>().take(10000).collect::<Vec<f32>>();

    b.iter(|| {
        for _ in 0..10 {
            let res = Dot::dot(&slice_a, &slice_b);
            test::black_box(res);
        }
    });
}

#[bench]
fn bench_10_dot_10000_collenchyma(b: &mut Bencher) {
    let mut rng = thread_rng();
    let slice_a = rng.gen_iter::<f32>().take(10000).collect::<Vec<f32>>();
    let slice_b = rng.gen_iter::<f32>().take(10000).collect::<Vec<f32>>();

    let backend = backend();
    let shared_a = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([10000])).unwrap();
    let shared_b = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([10000])).unwrap();
    let shared_res = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR0::new()).unwrap();
    shared_a.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_a);
    shared_b.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_b);
    let _ = backend.dot(shared_a, shared_b, shared_res);
    bench_10_dot_10000_collenchyma_profile(b, &backend, shared_a, shared_b, shared_res);
}

#[inline(never)]
fn bench_10_dot_10000_collenchyma_profile(
    b: &mut Bencher,
    backend: &Backend<Native>,
    shared_a: &mut SharedMemory<f32, TensorR1>,
    shared_b: &mut SharedMemory<f32, TensorR1>,
    shared_res: &mut SharedMemory<f32, TensorR0>
) {
    b.iter(|| {
        for _ in 0..10 {
            let _ = backend.dot(shared_a, shared_b, shared_res);
        }
    });
}

#[bench]
fn bench_5_dot_20000_rblas(b: &mut Bencher) {
    let mut rng = thread_rng();
    let slice_a = rng.gen_iter::<f32>().take(20000).collect::<Vec<f32>>();
    let slice_b = rng.gen_iter::<f32>().take(20000).collect::<Vec<f32>>();

    b.iter(|| {
        for _ in 0..5 {
            let res = Dot::dot(&slice_a, &slice_b);
            test::black_box(res);
        }
    });
}

#[bench]
fn bench_5_dot_20000_collenchyma(b: &mut Bencher) {
    let mut rng = thread_rng();
    let slice_a = rng.gen_iter::<f32>().take(20000).collect::<Vec<f32>>();
    let slice_b = rng.gen_iter::<f32>().take(20000).collect::<Vec<f32>>();

    let backend = backend();
    let shared_a = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([20000])).unwrap();
    let shared_b = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR1::new([20000])).unwrap();
    let shared_res = &mut SharedMemory::<f32, _>::new(backend.device(), TensorR0::new()).unwrap();
    shared_a.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_a);
    shared_b.get_mut(backend.device()).unwrap().as_mut_native().unwrap().as_mut_slice().clone_from_slice(&slice_b);
    let _ = backend.dot(shared_a, shared_b, shared_res);
    bench_5_dot_20000_collenchyma_profile(b, &backend, shared_a, shared_b, shared_res);
}

#[inline(never)]
fn bench_5_dot_20000_collenchyma_profile(
    b: &mut Bencher,
    backend: &Backend<Native>,
    shared_a: &mut SharedMemory<f32, TensorR1>,
    shared_b: &mut SharedMemory<f32, TensorR1>,
    shared_res: &mut SharedMemory<f32, TensorR0>
) {
    b.iter(|| {
        for _ in 0..5 {
            let _ = backend.dot(shared_a, shared_b, shared_res);
        }
    });
}
<commit_msg>chore/bench: move rblas bench to collenchyma-blas<commit_after><|endoftext|>