<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/ecc/mbs_error_vector_trap.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file mbs_error_vector_trap.H
/// @brief Subroutines for the MC MBS error vector trap registers (MBSEVR*Q)
///
// *HWP HWP Owner: Louis Stermole <stermole@us.ibm.com>
// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_MBS_ERROR_VECTOR_TRAP_H_
#define _MSS_MBS_ERROR_VECTOR_TRAP_H_

#include <fapi2.H>
#include <lib/utils/scom.H>
#include <lib/utils/find.H>
#include <lib/ecc/ecc_traits.H>

namespace mss
{

namespace ecc
{

namespace mbs_error_vector_trap
{

///
/// @brief Read MBS Error Vector Trap (MBSEVR*Q) register
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[out] o_data the value of the register
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline fapi2::ReturnCode read( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& o_data )
{
    const auto& l_mcbist_target = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target);
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    FAPI_TRY( mss::getScom(l_mcbist_target, (TT::ERROR_VECTOR_REGS[l_port]), o_data) );
    FAPI_INF("read: 0x%016lx", o_data);
fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Write MBS Error Vector Trap (MBSEVR*Q) register
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the value to write to the register
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline fapi2::ReturnCode write( const fapi2::Target<T>& i_target, const fapi2::buffer<uint64_t>& i_data )
{
    const auto& l_mcbist_target = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target);
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    FAPI_TRY( mss::putScom(l_mcbist_target, (TT::ERROR_VECTOR_REGS[l_port]), i_data) );
    FAPI_INF("write: 0x%016lx", i_data);
fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief set_nce_galois
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in, out] io_data the register value
/// @param[in] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void set_nce_galois( const fapi2::Target<T>& i_target,
                            fapi2::buffer<uint64_t>& io_data,
                            const uint64_t i_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        io_data.insertFromRight<TT::P0_NCE_GALOIS, TT::P0_NCE_GALOIS_LEN>(i_value);
    }
    else
    {
        io_data.insertFromRight<TT::P1_NCE_GALOIS, TT::P1_NCE_GALOIS_LEN>(i_value);
    }

    FAPI_INF("set_nce_galois: 0x%016lx", i_value);
}

///
/// @brief get_nce_galois
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the register value
/// @param[out] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void get_nce_galois( const fapi2::Target<T>& i_target,
                            const fapi2::buffer<uint64_t>& i_data,
                            uint64_t& o_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        i_data.extractToRight<TT::P0_NCE_GALOIS, TT::P0_NCE_GALOIS_LEN>(o_value);
    }
    else
    {
        i_data.extractToRight<TT::P1_NCE_GALOIS, TT::P1_NCE_GALOIS_LEN>(o_value);
    }

    FAPI_INF("get_nce_galois: 0x%016lx", o_value);
}

///
/// @brief set_nce_magnitude
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in, out] io_data the register value
/// @param[in] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void set_nce_magnitude( const fapi2::Target<T>& i_target,
                               fapi2::buffer<uint64_t>& io_data,
                               const uint64_t i_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        io_data.insertFromRight<TT::P0_NCE_MAGNITUDE, TT::P0_NCE_MAGNITUDE_LEN>(i_value);
    }
    else
    {
        io_data.insertFromRight<TT::P1_NCE_MAGNITUDE, TT::P1_NCE_MAGNITUDE_LEN>(i_value);
    }

    FAPI_INF("set_nce_magnitude: 0x%016lx", i_value);
}

///
/// @brief get_nce_magnitude
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the register value
/// @param[out] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void get_nce_magnitude( const fapi2::Target<T>& i_target,
                               const fapi2::buffer<uint64_t>& i_data,
                               uint64_t& o_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        i_data.extractToRight<TT::P0_NCE_MAGNITUDE, TT::P0_NCE_MAGNITUDE_LEN>(o_value);
    }
    else
    {
        i_data.extractToRight<TT::P1_NCE_MAGNITUDE, TT::P1_NCE_MAGNITUDE_LEN>(o_value);
    }

    FAPI_INF("get_nce_magnitude: 0x%016lx", o_value);
}

///
/// @brief set_tce_galois
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in, out] io_data the register value
/// @param[in] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void set_tce_galois( const fapi2::Target<T>& i_target,
                            fapi2::buffer<uint64_t>& io_data,
                            const uint64_t i_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        io_data.insertFromRight<TT::P0_TCE_GALOIS, TT::P0_TCE_GALOIS_LEN>(i_value);
    }
    else
    {
        io_data.insertFromRight<TT::P1_TCE_GALOIS, TT::P1_TCE_GALOIS_LEN>(i_value);
    }

    FAPI_INF("set_tce_galois: 0x%016lx", i_value);
}

///
/// @brief get_tce_galois
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the register value
/// @param[out] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void get_tce_galois( const fapi2::Target<T>& i_target,
                            const fapi2::buffer<uint64_t>& i_data,
                            uint64_t& o_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        i_data.extractToRight<TT::P0_TCE_GALOIS, TT::P0_TCE_GALOIS_LEN>(o_value);
    }
    else
    {
        i_data.extractToRight<TT::P1_TCE_GALOIS, TT::P1_TCE_GALOIS_LEN>(o_value);
    }

    FAPI_INF("get_tce_galois: 0x%016lx", o_value);
}

///
/// @brief set_tce_magnitude
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in, out] io_data the register value
/// @param[in] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void set_tce_magnitude( const fapi2::Target<T>& i_target,
                               fapi2::buffer<uint64_t>& io_data,
                               const uint64_t i_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        io_data.insertFromRight<TT::P0_TCE_MAGNITUDE, TT::P0_TCE_MAGNITUDE_LEN>(i_value);
    }
    else
    {
        io_data.insertFromRight<TT::P1_TCE_MAGNITUDE, TT::P1_TCE_MAGNITUDE_LEN>(i_value);
    }

    FAPI_INF("set_tce_magnitude: 0x%016lx", i_value);
}

///
/// @brief get_tce_magnitude
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the register value
/// @param[out] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void get_tce_magnitude( const fapi2::Target<T>& i_target,
                               const fapi2::buffer<uint64_t>& i_data,
                               uint64_t& o_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        i_data.extractToRight<TT::P0_TCE_MAGNITUDE, TT::P0_TCE_MAGNITUDE_LEN>(o_value);
    }
    else
    {
        i_data.extractToRight<TT::P1_TCE_MAGNITUDE, TT::P1_TCE_MAGNITUDE_LEN>(o_value);
    }

    FAPI_INF("get_tce_magnitude: 0x%016lx", o_value);
}

} // close namespace mbs_error_vector_trap

} // close namespace ecc

} // close namespace mss

#endif
<commit_msg>Move scom API to share among controllers<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/ecc/mbs_error_vector_trap.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file mbs_error_vector_trap.H
/// @brief Subroutines for the MC MBS error vector trap registers (MBSEVR*Q)
///
// *HWP HWP Owner: Louis Stermole <stermole@us.ibm.com>
// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_MBS_ERROR_VECTOR_TRAP_H_
#define _MSS_MBS_ERROR_VECTOR_TRAP_H_

#include <fapi2.H>
#include <generic/memory/lib/utils/scom.H>
#include <lib/utils/find.H>
#include <lib/ecc/ecc_traits.H>

namespace mss
{

namespace ecc
{

namespace mbs_error_vector_trap
{

///
/// @brief Read MBS Error Vector Trap (MBSEVR*Q) register
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[out] o_data the value of the register
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline fapi2::ReturnCode read( const fapi2::Target<T>& i_target, fapi2::buffer<uint64_t>& o_data )
{
    const auto& l_mcbist_target = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target);
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    FAPI_TRY( mss::getScom(l_mcbist_target, (TT::ERROR_VECTOR_REGS[l_port]), o_data) );
    FAPI_INF("read: 0x%016lx", o_data);
fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Write MBS Error Vector Trap (MBSEVR*Q) register
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the value to write to the register
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline fapi2::ReturnCode write( const fapi2::Target<T>& i_target, const fapi2::buffer<uint64_t>& i_data )
{
    const auto& l_mcbist_target = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target);
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    FAPI_TRY( mss::putScom(l_mcbist_target, (TT::ERROR_VECTOR_REGS[l_port]), i_data) );
    FAPI_INF("write: 0x%016lx", i_data);
fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief set_nce_galois
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in, out] io_data the register value
/// @param[in] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void set_nce_galois( const fapi2::Target<T>& i_target,
                            fapi2::buffer<uint64_t>& io_data,
                            const uint64_t i_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        io_data.insertFromRight<TT::P0_NCE_GALOIS, TT::P0_NCE_GALOIS_LEN>(i_value);
    }
    else
    {
        io_data.insertFromRight<TT::P1_NCE_GALOIS, TT::P1_NCE_GALOIS_LEN>(i_value);
    }

    FAPI_INF("set_nce_galois: 0x%016lx", i_value);
}

///
/// @brief get_nce_galois
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the register value
/// @param[out] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void get_nce_galois( const fapi2::Target<T>& i_target,
                            const fapi2::buffer<uint64_t>& i_data,
                            uint64_t& o_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        i_data.extractToRight<TT::P0_NCE_GALOIS, TT::P0_NCE_GALOIS_LEN>(o_value);
    }
    else
    {
        i_data.extractToRight<TT::P1_NCE_GALOIS, TT::P1_NCE_GALOIS_LEN>(o_value);
    }

    FAPI_INF("get_nce_galois: 0x%016lx", o_value);
}

///
/// @brief set_nce_magnitude
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in, out] io_data the register value
/// @param[in] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void set_nce_magnitude( const fapi2::Target<T>& i_target,
                               fapi2::buffer<uint64_t>& io_data,
                               const uint64_t i_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        io_data.insertFromRight<TT::P0_NCE_MAGNITUDE, TT::P0_NCE_MAGNITUDE_LEN>(i_value);
    }
    else
    {
        io_data.insertFromRight<TT::P1_NCE_MAGNITUDE, TT::P1_NCE_MAGNITUDE_LEN>(i_value);
    }

    FAPI_INF("set_nce_magnitude: 0x%016lx", i_value);
}

///
/// @brief get_nce_magnitude
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the register value
/// @param[out] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void get_nce_magnitude( const fapi2::Target<T>& i_target,
                               const fapi2::buffer<uint64_t>& i_data,
                               uint64_t& o_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        i_data.extractToRight<TT::P0_NCE_MAGNITUDE, TT::P0_NCE_MAGNITUDE_LEN>(o_value);
    }
    else
    {
        i_data.extractToRight<TT::P1_NCE_MAGNITUDE, TT::P1_NCE_MAGNITUDE_LEN>(o_value);
    }

    FAPI_INF("get_nce_magnitude: 0x%016lx", o_value);
}

///
/// @brief set_tce_galois
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in, out] io_data the register value
/// @param[in] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void set_tce_galois( const fapi2::Target<T>& i_target,
                            fapi2::buffer<uint64_t>& io_data,
                            const uint64_t i_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        io_data.insertFromRight<TT::P0_TCE_GALOIS, TT::P0_TCE_GALOIS_LEN>(i_value);
    }
    else
    {
        io_data.insertFromRight<TT::P1_TCE_GALOIS, TT::P1_TCE_GALOIS_LEN>(i_value);
    }

    FAPI_INF("set_tce_galois: 0x%016lx", i_value);
}

///
/// @brief get_tce_galois
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the register value
/// @param[out] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void get_tce_galois( const fapi2::Target<T>& i_target,
                            const fapi2::buffer<uint64_t>& i_data,
                            uint64_t& o_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        i_data.extractToRight<TT::P0_TCE_GALOIS, TT::P0_TCE_GALOIS_LEN>(o_value);
    }
    else
    {
        i_data.extractToRight<TT::P1_TCE_GALOIS, TT::P1_TCE_GALOIS_LEN>(o_value);
    }

    FAPI_INF("get_tce_galois: 0x%016lx", o_value);
}

///
/// @brief set_tce_magnitude
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in, out] io_data the register value
/// @param[in] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void set_tce_magnitude( const fapi2::Target<T>& i_target,
                               fapi2::buffer<uint64_t>& io_data,
                               const uint64_t i_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        io_data.insertFromRight<TT::P0_TCE_MAGNITUDE, TT::P0_TCE_MAGNITUDE_LEN>(i_value);
    }
    else
    {
        io_data.insertFromRight<TT::P1_TCE_MAGNITUDE, TT::P1_TCE_MAGNITUDE_LEN>(i_value);
    }

    FAPI_INF("set_tce_magnitude: 0x%016lx", i_value);
}

///
/// @brief get_tce_magnitude
/// @tparam T fapi2 Target Type - derived from i_target's type
/// @tparam TT traits type defaults to eccTraits<T>
/// @param[in] i_target the fapi2 target of the mc
/// @param[in] i_data the register value
/// @param[out] i_value the value of the field
///
template< fapi2::TargetType T, typename TT = eccTraits<T> >
inline void get_tce_magnitude( const fapi2::Target<T>& i_target,
                               const fapi2::buffer<uint64_t>& i_data,
                               uint64_t& o_value)
{
    const auto& l_port = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_target);

    // check for even/odd since each register holds info for a pair of ports
    if (!mss::is_odd(l_port))
    {
        i_data.extractToRight<TT::P0_TCE_MAGNITUDE, TT::P0_TCE_MAGNITUDE_LEN>(o_value);
    }
    else
    {
        i_data.extractToRight<TT::P1_TCE_MAGNITUDE, TT::P1_TCE_MAGNITUDE_LEN>(o_value);
    }

    FAPI_INF("get_tce_magnitude: 0x%016lx", o_value);
}

} // close namespace mbs_error_vector_trap

} // close namespace ecc

} // close namespace mss

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Test.h"
#include "SkAAClip.h"
#include "SkPath.h"

static void test_trim_bounds(skiatest::Reporter* reporter) {
    SkPath path;
    SkAAClip clip;
    const int height = 40;
    const SkScalar sheight = SkIntToScalar(height);

    path.addOval(SkRect::MakeWH(sheight, sheight));
    REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
    clip.setPath(path, NULL, true);
    REPORTER_ASSERT(reporter, height == clip.getBounds().height());

    // this is the trimmed height of this cubic (with aa). The critical thing
    // for this test is that it is less than height, which represents just
    // the bounds of the path's control-points.
    //
    // This used to fail until we tracked the MinY in the BuilderBlitter.
    //
    const int teardrop_height = 12;
    path.reset();
    path.moveTo(0, 20);
    path.cubicTo(40, 40, 40, 0, 0, 20);
    REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
    clip.setPath(path, NULL, true);
    REPORTER_ASSERT(reporter, teardrop_height == clip.getBounds().height());
}

static void TestAAClip(skiatest::Reporter* reporter) {
    test_trim_bounds(reporter);
}

#include "TestClassDef.h"
DEFINE_TESTCLASS("AAClip", AAClipTestClass, TestAAClip)
<commit_msg>fix new test to work in fixed-point<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Test.h"
#include "SkAAClip.h"
#include "SkPath.h"

static void imoveTo(SkPath& path, int x, int y) {
    path.moveTo(SkIntToScalar(x), SkIntToScalar(y));
}

static void icubicTo(SkPath& path, int x0, int y0, int x1, int y1, int x2, int y2) {
    path.cubicTo(SkIntToScalar(x0), SkIntToScalar(y0),
                 SkIntToScalar(x1), SkIntToScalar(y1),
                 SkIntToScalar(x2), SkIntToScalar(y2));
}

static void test_trim_bounds(skiatest::Reporter* reporter) {
    SkPath path;
    SkAAClip clip;
    const int height = 40;
    const SkScalar sheight = SkIntToScalar(height);

    path.addOval(SkRect::MakeWH(sheight, sheight));
    REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
    clip.setPath(path, NULL, true);
    REPORTER_ASSERT(reporter, height == clip.getBounds().height());

    // this is the trimmed height of this cubic (with aa). The critical thing
    // for this test is that it is less than height, which represents just
    // the bounds of the path's control-points.
    //
    // This used to fail until we tracked the MinY in the BuilderBlitter.
    //
    const int teardrop_height = 12;
    path.reset();
    imoveTo(path, 0, 20);
    icubicTo(path, 40, 40, 40, 0, 0, 20);
    REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
    clip.setPath(path, NULL, true);
    REPORTER_ASSERT(reporter, teardrop_height == clip.getBounds().height());
}

static void TestAAClip(skiatest::Reporter* reporter) {
    test_trim_bounds(reporter);
}

#include "TestClassDef.h"
DEFINE_TESTCLASS("AAClip", AAClipTestClass, TestAAClip)
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// Antioch - A Gas Dynamics Thermochemistry Library
//
// Copyright (C) 2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-
//
// $Id$
//
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

// C++
#include <iostream>
#include <cmath>

// Antioch
// Declare metaprogramming overloads before they're used
#include "antioch/eigen_utils_decl.h"
#include "antioch/metaphysicl_utils_decl.h"
#include "antioch/valarray_utils_decl.h"

#include "antioch/chemical_mixture.h"
#include "antioch/stat_mech_thermo.h"
#include "antioch/eucken_thermal_conductivity.h"
#include "antioch/blottner_viscosity.h"
#include "antioch/wilke_mixture.h"
#include "antioch/wilke_evaluator.h"
#include "antioch/blottner_parsing.h"

#include "antioch/eigen_utils.h"
#include "antioch/metaphysicl_utils.h"
#include "antioch/valarray_utils.h"

template <typename Scalar, typename PairScalars>
int test_val( const PairScalars val, const PairScalars val_exact,
              const Scalar tol, const std::string& val_name )
{
  using std::abs;

  int return_flag = 0;

  const PairScalars rel_error = (val - val_exact)/val_exact;
  const PairScalars abs_rel_error = abs(rel_error);

  if( Antioch::max(abs_rel_error)  > tol )
    {
      std::cerr << "Error: Mismatch in " << val_name << std::endl
		<< val_name << "    = " << val << std::endl
		<< val_name+"_exact = " << val_exact << std::endl
		<< "abs_rel_error = " << abs_rel_error << std::endl
		<< "tol = " << tol << std::endl;
      return_flag = 1;
    }

  return return_flag;
}

template <typename PairScalars>
int tester(const PairScalars& example)
{
  using std::pow;
  using std::sqrt;

  typedef typename Antioch::value_type<PairScalars>::type Scalar;

  std::vector<std::string> species_str_list;
  const unsigned int n_species = 5;
  species_str_list.reserve(n_species);
  species_str_list.push_back( "N2" );
  species_str_list.push_back( "O2" );
  species_str_list.push_back( "N" );
  species_str_list.push_back( "O" );
  species_str_list.push_back( "NO" );

  Antioch::ChemicalMixture<Scalar> chem_mixture( species_str_list );

  Antioch::WilkeMixture<Scalar> wilke_mixture( chem_mixture );

  Antioch::StatMechThermodynamics<Scalar> thermo( chem_mixture );

  Antioch::EuckenThermalConductivity<Antioch::StatMechThermodynamics<Scalar> > k( thermo );

  Antioch::MixtureViscosity<Antioch::BlottnerViscosity<Scalar>, Scalar> mu( chem_mixture );

  Antioch::read_blottner_data_ascii_default( mu );

  Antioch::WilkeEvaluator< Antioch::MixtureViscosity<Antioch::BlottnerViscosity<Scalar>, Scalar>,
                           Antioch::EuckenThermalConductivity<Antioch::StatMechThermodynamics<Scalar> >,
                           Scalar > wilke( wilke_mixture, mu, k );

  int return_flag = 0;

  const Scalar tol = std::numeric_limits<Scalar>::epsilon() * 2;

  // First check phi calculation
  // phi_s = sum_r (chi_r*(1+sqrt(mu_s/mu_r)*(Mr/Ms)^(1/4))^2)/sqrt(8*(1+Ms/Mr))
  {
    std::vector<PairScalars> mu(5, example);
    mu[0][0] = 0.1L;
    mu[1][0] = 0.2L;
    mu[2][0] = 0.3L;
    mu[3][0] = 0.15L;
    mu[4][0] = 0.25L;
    mu[0][1] = 0.25L;
    mu[1][1] = 0.15L;
    mu[2][1] = 0.3L;
    mu[3][1] = 0.2L;
    mu[4][1] = 0.1L;

    std::vector<PairScalars> chi(5, example);
    chi[0][0] = 0.1L;
    chi[1][0] = 0.2L;
    chi[2][0] = 0.3L;
    chi[3][0] = 0.15L;
    chi[4][0] = 0.25L;
    chi[0][1] = 0.25L;
    chi[1][1] = 0.15L;
    chi[2][1] = 0.3L;
    chi[3][1] = 0.2L;
    chi[4][1] = 0.1L;

    PairScalars phi_N_exact = Antioch::zero_clone(example);
    unsigned int N_index = 2;
    const Scalar M_N = chem_mixture.M(N_index);

    for( unsigned int r = 0; r < 5; r++ )
      {
        Scalar M_r = chem_mixture.M(r);
        PairScalars dummy = 1.0L + sqrt(mu[N_index]/mu[r])*pow( M_r/M_N, Scalar(0.25L) );
        phi_N_exact += chi[r]*dummy*dummy/sqrt(8.0L*( 1.0L + M_N/M_r ) );
      }

    const PairScalars phi_N = wilke.compute_phi( mu, chi, N_index );

    return_flag = test_val( phi_N, phi_N_exact, tol, std::string("phi") );
  }

  PairScalars T = example;
  T[0] = 1000.0L;
  T[1] = 1200.0L;

  PairScalars each_mass = example;
  each_mass[0] = 0.2L;
  each_mass[1] = 0.2L;
  std::vector<PairScalars> mass_fractions( 5, each_mass);

  // Currently dummy
  //const Scalar mu_exact = ;

  PairScalars wilke_mu = wilke.mu(T, mass_fractions );
  PairScalars wilke_k = wilke.k(T, mass_fractions );

  int return_flag_temp = 0;
  //return_flag_temp = test_mu( wilke.mu(T, mass_fractions ), mu_exact, tol );
  if( return_flag_temp != 0 ) return_flag = 1;

  return return_flag;
}

int main()
{
  int returnval = 0;

  returnval = returnval ||
    tester (std::valarray<float>(2));
  returnval = returnval ||
    tester (std::valarray<double>(2));
  returnval = returnval ||
    tester (std::valarray<long double>(2));
#ifdef ANTIOCH_HAVE_EIGEN
  returnval = returnval ||
    tester (Eigen::Array2f());
  returnval = returnval ||
    tester (Eigen::Array2d());
  returnval = returnval ||
    tester (Eigen::Array<long double, 2, 1>());
#endif
#ifdef ANTIOCH_HAVE_METAPHYSICL
  returnval = returnval ||
    tester (MetaPhysicL::NumberArray<2, float> (0));
  returnval = returnval ||
    tester (MetaPhysicL::NumberArray<2, double> (0));
  returnval = returnval ||
    tester (MetaPhysicL::NumberArray<2, long double> (0));
#endif

  return returnval;
}
<commit_msg>Add config/Eigen/metaphysicl includes<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// Antioch - A Gas Dynamics Thermochemistry Library
//
// Copyright (C) 2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-
//
// $Id$
//
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

#include "antioch_config.h"

// C++
#include <iostream>
#include <cmath>

#ifdef ANTIOCH_HAVE_EIGEN
#include "Eigen/Dense"
#endif

#ifdef ANTIOCH_HAVE_METAPHYSICL
#include "metaphysicl/numberarray.h"
#endif

// Antioch
// Declare metaprogramming overloads before they're used
#include "antioch/eigen_utils_decl.h"
#include "antioch/metaphysicl_utils_decl.h"
#include "antioch/valarray_utils_decl.h"

#include "antioch/chemical_mixture.h"
#include "antioch/stat_mech_thermo.h"
#include "antioch/eucken_thermal_conductivity.h"
#include "antioch/blottner_viscosity.h"
#include "antioch/wilke_mixture.h"
#include "antioch/wilke_evaluator.h"
#include "antioch/blottner_parsing.h"

#include "antioch/eigen_utils.h"
#include "antioch/metaphysicl_utils.h"
#include "antioch/valarray_utils.h"

template <typename Scalar, typename PairScalars>
int test_val( const PairScalars val, const PairScalars val_exact,
              const Scalar tol, const std::string& val_name )
{
  using std::abs;

  int return_flag = 0;

  const PairScalars rel_error = (val - val_exact)/val_exact;
  const PairScalars abs_rel_error = abs(rel_error);

  if( Antioch::max(abs_rel_error)  > tol )
    {
      std::cerr << "Error: Mismatch in " << val_name << std::endl
		<< val_name << "    = " << val << std::endl
		<< val_name+"_exact = " << val_exact << std::endl
		<< "abs_rel_error = " << abs_rel_error << std::endl
		<< "tol = " << tol << std::endl;
      return_flag = 1;
    }

  return return_flag;
}

template <typename PairScalars>
int tester(const PairScalars& example)
{
  using std::pow;
  using std::sqrt;

  typedef typename Antioch::value_type<PairScalars>::type Scalar;

  std::vector<std::string> species_str_list;
  const unsigned int n_species = 5;
  species_str_list.reserve(n_species);
  species_str_list.push_back( "N2" );
  species_str_list.push_back( "O2" );
  species_str_list.push_back( "N" );
  species_str_list.push_back( "O" );
  species_str_list.push_back( "NO" );

  Antioch::ChemicalMixture<Scalar> chem_mixture( species_str_list );

  Antioch::WilkeMixture<Scalar> wilke_mixture( chem_mixture );

  Antioch::StatMechThermodynamics<Scalar> thermo( chem_mixture );

  Antioch::EuckenThermalConductivity<Antioch::StatMechThermodynamics<Scalar> > k( thermo );

  Antioch::MixtureViscosity<Antioch::BlottnerViscosity<Scalar>, Scalar> mu( chem_mixture );

  Antioch::read_blottner_data_ascii_default( mu );

  Antioch::WilkeEvaluator< Antioch::MixtureViscosity<Antioch::BlottnerViscosity<Scalar>, Scalar>,
                           Antioch::EuckenThermalConductivity<Antioch::StatMechThermodynamics<Scalar> >,
                           Scalar > wilke( wilke_mixture, mu, k );

  int return_flag = 0;

  const Scalar tol = std::numeric_limits<Scalar>::epsilon() * 2;

  // First check phi calculation
  // phi_s = sum_r (chi_r*(1+sqrt(mu_s/mu_r)*(Mr/Ms)^(1/4))^2)/sqrt(8*(1+Ms/Mr))
  {
    std::vector<PairScalars> mu(5, example);
    mu[0][0] = 0.1L;
    mu[1][0] = 0.2L;
    mu[2][0] = 0.3L;
    mu[3][0] = 0.15L;
    mu[4][0] = 0.25L;
    mu[0][1] = 0.25L;
    mu[1][1] = 0.15L;
    mu[2][1] = 0.3L;
    mu[3][1] = 0.2L;
    mu[4][1] = 0.1L;

    std::vector<PairScalars> chi(5, example);
    chi[0][0] = 0.1L;
    chi[1][0] = 0.2L;
    chi[2][0] = 0.3L;
    chi[3][0] = 0.15L;
    chi[4][0] = 0.25L;
    chi[0][1] = 0.25L;
    chi[1][1] = 0.15L;
    chi[2][1] = 0.3L;
    chi[3][1] = 0.2L;
    chi[4][1] = 0.1L;

    PairScalars phi_N_exact = Antioch::zero_clone(example);
    unsigned int N_index = 2;
    const Scalar M_N = chem_mixture.M(N_index);

    for( unsigned int r = 0; r < 5; r++ )
      {
        Scalar M_r = chem_mixture.M(r);
        PairScalars dummy = 1.0L + sqrt(mu[N_index]/mu[r])*pow( M_r/M_N, Scalar(0.25L) );
        phi_N_exact += chi[r]*dummy*dummy/sqrt(8.0L*( 1.0L + M_N/M_r ) );
      }

    const PairScalars phi_N = wilke.compute_phi( mu, chi, N_index );

    return_flag = test_val( phi_N, phi_N_exact, tol, std::string("phi") );
  }

  PairScalars T = example;
  T[0] = 1000.0L;
  T[1] = 1200.0L;

  PairScalars each_mass = example;
  each_mass[0] = 0.2L;
  each_mass[1] = 0.2L;
  std::vector<PairScalars> mass_fractions( 5, each_mass);

  // Currently dummy
  //const Scalar mu_exact = ;

  PairScalars wilke_mu = wilke.mu(T, mass_fractions );
  PairScalars wilke_k = wilke.k(T, mass_fractions );

  int return_flag_temp = 0;
  //return_flag_temp = test_mu( wilke.mu(T, mass_fractions ), mu_exact, tol );
  if( return_flag_temp != 0 ) return_flag = 1;

  return return_flag;
}

int main()
{
  int returnval = 0;

  returnval = returnval ||
    tester (std::valarray<float>(2));
  returnval = returnval ||
    tester (std::valarray<double>(2));
  returnval = returnval ||
    tester (std::valarray<long double>(2));
#ifdef ANTIOCH_HAVE_EIGEN
  returnval = returnval ||
    tester (Eigen::Array2f());
  returnval = returnval ||
    tester (Eigen::Array2d());
  returnval = returnval ||
    tester (Eigen::Array<long double, 2, 1>());
#endif
#ifdef ANTIOCH_HAVE_METAPHYSICL
  returnval = returnval ||
    tester (MetaPhysicL::NumberArray<2, float> (0));
  returnval = returnval ||
    tester (MetaPhysicL::NumberArray<2, double> (0));
  returnval = returnval ||
    tester (MetaPhysicL::NumberArray<2, long double> (0));
#endif

  return returnval;
}
<|endoftext|>


<commit_before>/***********************************************************************
 datetime.cpp - Implements date and time classes compatible with MySQL's
	various date and time column types.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#define MYSQLPP_NOT_HEADER
#include "platform.h"

#include "datetime.h"

#include <iomanip>

using namespace std;

namespace mysqlpp {

std::ostream& operator <<(std::ostream& os, const Date& d)
{
	char fill = os.fill('0');
	ios::fmtflags flags = os.setf(ios::right);
	os		<< setw(4) << d.year << '-'
			<< setw(2) << d.month << '-'
			<< setw(2) << d.day;
	os.flags(flags);
	os.fill(fill);
	return os;
}

std::ostream& operator <<(std::ostream& os, const Time& t)
{
	char fill = os.fill('0');
	ios::fmtflags flags = os.setf(ios::right);
	os		<< setw(2) << t.hour << ':'
			<< setw(2) << t.minute << ':'
			<< setw(2) << t.second;
	os.flags(flags);
	os.fill(fill);
	return os;
}

std::ostream& operator <<(std::ostream& os, const DateTime& dt)
{
	operator <<(os, Date(dt));
	os << ' ';
	return operator <<(os, Time(dt));
}

cchar* Date::convert(cchar* str)
{
	char num[5];

	num[0] = *str++;
	num[1] = *str++;
	num[2] = *str++;
	num[3] = *str++;
	num[4] = 0;
	year = short(strtol(num, 0, 10));
	if (*str == '-') str++;

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	month = short(strtol(num, 0, 10));
	if (*str == '-') str++;

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	day = short(strtol(num, 0, 10));

	return str;
}

cchar* Time::convert(cchar* str)
{
	char num[5];

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	hour = short(strtol(num,0,10));
	if (*str == ':') str++;

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	minute = short(strtol(num,0,10));
	if (*str == ':') str++;

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	second = short(strtol(num,0,10));

	return str;
}

cchar* DateTime::convert(cchar* str)
{
	Date d;
	str = d.convert(str);
	year = d.year;
	month = d.month;
	day = d.day;

	if (*str == ' ') ++str;

	Time t;
	str = t.convert(str);
	hour = t.hour;
	minute = t.minute;
	second = t.second;

	return str;
}

short int Date::compare(const Date& other) const
{
	if (year != other.year) return year - other.year;
	if (month != other.month) return month - other.month;
	return day - other.day;
}

short int Time::compare(const Time& other) const
{
	if (hour != other.hour) return hour - other.hour;
	if (minute != other.minute) return minute - other.minute;
	return second - other.second;
}

short int DateTime::compare(const DateTime& other) const
{
	Date d(*this), od(other);
	Time t(*this), ot(other);

	if (int x = d.compare(od)) {
		return x;
	}
	else {
		return t.compare(ot);
	}
}

DateTime::operator time_t() const
{
	struct tm tm;
	tm.tm_sec = second;
	tm.tm_min = minute;
	tm.tm_hour = hour;
	tm.tm_mday = day;
	tm.tm_mon = month - (tiny_int)1;
	tm.tm_year = year - 1900;

	return mktime(&tm);
};

DateTime::DateTime(time_t t)
{
	struct tm tm;
	localtime_r(&t, &tm);

	year = tm.tm_year + 1900;
	month = tm.tm_mon + 1;
	day = tm.tm_mday;
	hour = tm.tm_hour;
	minute = tm.tm_min;
	second = tm.tm_sec;
}

} // end namespace mysqlpp

<commit_msg>A recent patch changed a localtime() call to the safer localtime_r(), but that's pretty much POSIX-specific.  Added a workaround for VC++, using their localtime_s(), which is the same thing, just with the arguments reversed.  (What, you expected something different from Microsoft??)<commit_after>/***********************************************************************
 datetime.cpp - Implements date and time classes compatible with MySQL's
	various date and time column types.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#define MYSQLPP_NOT_HEADER
#include "common.h"

#include "datetime.h"

#include <iomanip>

using namespace std;

namespace mysqlpp {

std::ostream& operator <<(std::ostream& os, const Date& d)
{
	char fill = os.fill('0');
	ios::fmtflags flags = os.setf(ios::right);
	os		<< setw(4) << d.year << '-'
			<< setw(2) << d.month << '-'
			<< setw(2) << d.day;
	os.flags(flags);
	os.fill(fill);
	return os;
}

std::ostream& operator <<(std::ostream& os, const Time& t)
{
	char fill = os.fill('0');
	ios::fmtflags flags = os.setf(ios::right);
	os		<< setw(2) << t.hour << ':'
			<< setw(2) << t.minute << ':'
			<< setw(2) << t.second;
	os.flags(flags);
	os.fill(fill);
	return os;
}

std::ostream& operator <<(std::ostream& os, const DateTime& dt)
{
	operator <<(os, Date(dt));
	os << ' ';
	return operator <<(os, Time(dt));
}

cchar* Date::convert(cchar* str)
{
	char num[5];

	num[0] = *str++;
	num[1] = *str++;
	num[2] = *str++;
	num[3] = *str++;
	num[4] = 0;
	year = short(strtol(num, 0, 10));
	if (*str == '-') str++;

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	month = short(strtol(num, 0, 10));
	if (*str == '-') str++;

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	day = short(strtol(num, 0, 10));

	return str;
}

cchar* Time::convert(cchar* str)
{
	char num[5];

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	hour = short(strtol(num,0,10));
	if (*str == ':') str++;

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	minute = short(strtol(num,0,10));
	if (*str == ':') str++;

	num[0] = *str++;
	num[1] = *str++;
	num[2] = 0;
	second = short(strtol(num,0,10));

	return str;
}

cchar* DateTime::convert(cchar* str)
{
	Date d;
	str = d.convert(str);
	year = d.year;
	month = d.month;
	day = d.day;

	if (*str == ' ') ++str;

	Time t;
	str = t.convert(str);
	hour = t.hour;
	minute = t.minute;
	second = t.second;

	return str;
}

short int Date::compare(const Date& other) const
{
	if (year != other.year) return year - other.year;
	if (month != other.month) return month - other.month;
	return day - other.day;
}

short int Time::compare(const Time& other) const
{
	if (hour != other.hour) return hour - other.hour;
	if (minute != other.minute) return minute - other.minute;
	return second - other.second;
}

short int DateTime::compare(const DateTime& other) const
{
	Date d(*this), od(other);
	Time t(*this), ot(other);

	if (int x = d.compare(od)) {
		return x;
	}
	else {
		return t.compare(ot);
	}
}

DateTime::operator time_t() const
{
	struct tm tm;
	tm.tm_sec = second;
	tm.tm_min = minute;
	tm.tm_hour = hour;
	tm.tm_mday = day;
	tm.tm_mon = month - (tiny_int)1;
	tm.tm_year = year - 1900;

	return mktime(&tm);
};

DateTime::DateTime(time_t t)
{
	struct tm tm;
#if defined(_MSC_VER)
	localtime_s(&tm, &t);
#else
	localtime_r(&t, &tm);
#endif

	year = tm.tm_year + 1900;
	month = tm.tm_mon + 1;
	day = tm.tm_mday;
	hour = tm.tm_hour;
	minute = tm.tm_min;
	second = tm.tm_sec;
}

} // end namespace mysqlpp

<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// logging_test.cpp
//
// Identification: tests/logging/logging_test.cpp
//
// Copyright (c) 2016, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <dirent.h>

#include "harness.h"

#include "backend/concurrency/transaction_manager_factory.h"
#include "backend/executor/logical_tile_factory.h"
#include "backend/storage/data_table.h"
#include "backend/storage/tile.h"
#include "backend/logging/loggers/wal_frontend_logger.h"
#include "backend/storage/table_factory.h"
#include "backend/logging/log_manager.h"
#include "backend/index/index.h"

#include "backend/logging/logging_util.h"

#include "logging/logging_tests_util.h"

#include "executor/mock_executor.h"
#include "executor/executor_tests_util.h"

#define DEFAULT_RECOVERY_CID 15

using ::testing::NotNull;
using ::testing::Return;
using ::testing::InSequence;

namespace peloton {
namespace test {

//===--------------------------------------------------------------------===//
// Recovery Tests
//===--------------------------------------------------------------------===//

class RecoveryTests : public PelotonTest {};

std::vector<storage::Tuple *> BuildLoggingTuples(storage::DataTable *table,
                                                 int num_rows, bool mutate,
                                                 bool random) {
  std::vector<storage::Tuple *> tuples;
  LOG_INFO("build a vector of %d tuples", num_rows);

  // Random values
  std::srand(std::time(nullptr));
  const catalog::Schema *schema = table->GetSchema();
  // Ensure that the tile group is as expected.
  assert(schema->GetColumnCount() == 4);

  // Insert tuples into tile_group.
  const bool allocate = true;
  auto testing_pool = TestingHarness::GetInstance().GetTestingPool();

  for (int rowid = 0; rowid < num_rows; rowid++) {
    int populate_value = rowid;
    if (mutate) populate_value *= 3;

    storage::Tuple *tuple = new storage::Tuple(schema, allocate);

    // First column is unique in this case
    tuple->SetValue(0,
                    ValueFactory::GetIntegerValue(
                        ExecutorTestsUtil::PopulatedValue(populate_value, 0)),
                    testing_pool);

    // In case of random, make sure this column has duplicated values
    tuple->SetValue(
        1, ValueFactory::GetIntegerValue(ExecutorTestsUtil::PopulatedValue(
               random ? std::rand() % (num_rows / 3) : populate_value, 1)),
        testing_pool);

    tuple->SetValue(
        2, ValueFactory::GetDoubleValue(ExecutorTestsUtil::PopulatedValue(
               random ? std::rand() : populate_value, 2)),
        testing_pool);

    // In case of random, make sure this column has duplicated values
    Value string_value = ValueFactory::GetStringValue(
        std::to_string(ExecutorTestsUtil::PopulatedValue(
            random ? std::rand() % (num_rows / 3) : populate_value, 3)));
    tuple->SetValue(3, string_value, testing_pool);
    tuples.push_back(tuple);
  }
  return tuples;
}

TEST_F(RecoveryTests, RestartTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();

  size_t tile_group_size = 5;
  size_t table_tile_group_count = 3;
  int num_files = 3;

  auto mutate = true;
  auto random = false;
  cid_t default_commit_id = INVALID_CID;
  cid_t default_delimiter = INVALID_CID;

  std::string dir_name = "pl_log0";
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  int num_rows = tile_group_size * table_tile_group_count;
  std::vector<std::shared_ptr<storage::Tuple>> tuples =
      LoggingTestsUtil::BuildTuples(recovery_table, num_rows, mutate, random);
  std::vector<logging::TupleRecord> records =
      LoggingTestsUtil::BuildTupleRecordsForRestartTest(tuples, tile_group_size,
                                                        table_tile_group_count);

  auto status = logging::LoggingUtil::CreateDirectory(dir_name.c_str(), 0700);
  EXPECT_EQ(status, true);

  for (int i = 0; i < num_files; i++) {
    std::string file_name = dir_name + "/" + std::string("peloton_log_") +
                            std::to_string(i) + std::string(".log");
    FILE *fp = fopen(file_name.c_str(), "wb");

    // now set the first 8 bytes to 0 - this is for the max_log id in this file
    fwrite((void *)&default_commit_id, sizeof(default_commit_id), 1, fp);

    // now set the next 8 bytes to 0 - this is for the max delimiter in this
    // file
    fwrite((void *)&default_delimiter, sizeof(default_delimiter), 1, fp);

    // First write a begin record
    CopySerializeOutput output_buffer_begin;
    logging::TransactionRecord record_begin(LOGRECORD_TYPE_TRANSACTION_BEGIN,
                                            i + 2);
    record_begin.Serialize(output_buffer_begin);

    fwrite(record_begin.GetMessage(), sizeof(char),
           record_begin.GetMessageLength(), fp);

    // Now write 5 insert tuple records into this file
    for (int j = 0; j < (int)tile_group_size; j++) {
      int num_record = i * tile_group_size + j;
      CopySerializeOutput output_buffer;
      records[num_record].Serialize(output_buffer);

      fwrite(records[num_record].GetMessage(), sizeof(char),
             records[num_record].GetMessageLength(), fp);
    }

    // Now write commit
    logging::TransactionRecord record_commit(LOGRECORD_TYPE_TRANSACTION_COMMIT,
                                             i + 2);

    CopySerializeOutput output_buffer_commit;
    record_commit.Serialize(output_buffer_commit);

    fwrite(record_commit.GetMessage(), sizeof(char),
           record_commit.GetMessageLength(), fp);

    // Now write delimiter
    CopySerializeOutput output_buffer_delim;
    logging::TransactionRecord record_delim(LOGRECORD_TYPE_ITERATION_DELIMITER,
                                            i + 2);

    record_delim.Serialize(output_buffer_delim);

    fwrite(record_delim.GetMessage(), sizeof(char),
           record_delim.GetMessageLength(), fp);

    fclose(fp);
  }

  int index_count = recovery_table->GetIndexCount();
  LOG_INFO("Number of indexes on this table: %d", (int)index_count);

  for (int index_itr = index_count - 1; index_itr >= 0; --index_itr) {
    auto index = recovery_table->GetIndex(index_itr);
    EXPECT_EQ(index->GetNumberOfTuples(), 0);
  }

  logging::WriteAheadFrontendLogger wal_fel(std::string("pl_log"));

  EXPECT_EQ(wal_fel.GetMaxDelimiterForRecovery(), num_files + 1);
  EXPECT_EQ(wal_fel.GetLogFileCounter(), num_files);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);

  auto &log_manager = logging::LogManager::GetInstance();
  log_manager.SetGlobalMaxFlushedIdForRecovery(num_files + 1);

  wal_fel.DoRecovery();

  EXPECT_EQ(recovery_table->GetNumberOfTuples(),
            tile_group_size * table_tile_group_count);
  EXPECT_EQ(wal_fel.GetLogFileCursor(), num_files);

  wal_fel.RecoverIndex();
  for (int index_itr = index_count - 1; index_itr >= 0; --index_itr) {
    auto index = recovery_table->GetIndex(index_itr);
    EXPECT_EQ(index->GetNumberOfTuples(),
              tile_group_size * table_tile_group_count);
  }

  for (int i = 0; i < num_files; i++) {
    int return_val = remove((dir_name + "/" + std::string("peloton_log_") +
                             std::to_string(i) + (".log")).c_str());
    EXPECT_EQ(return_val, 0);
  }
  status = logging::LoggingUtil::RemoveDirectory("pl_log0", false);
  EXPECT_EQ(status, true);
}

TEST_F(RecoveryTests, BasicInsertTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  auto tuples = BuildLoggingTuples(recovery_table, 1, false, false);
  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 1);
  EXPECT_EQ(tuples.size(), 1);
  logging::WriteAheadFrontendLogger fel(true);
  //  auto bel = logging::WriteAheadBackendLogger::GetInstance();
  cid_t test_commit_id = 10;

  Value val0 = tuples[0]->GetValue(0);
  Value val1 = tuples[0]->GetValue(1);
  Value val2 = tuples[0]->GetValue(2);
  Value val3 = tuples[0]->GetValue(3);
  auto curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_INSERT, test_commit_id, recovery_table->GetOid(),
      ItemPointer(100, 5), INVALID_ITEMPOINTER, tuples[0], DEFAULT_DB_ID);
  curr_rec->SetTuple(tuples[0]);
  fel.InsertTuple(curr_rec);
  delete curr_rec;

  auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader();
  EXPECT_TRUE(tg_header->GetBeginCommitId(5) <= test_commit_id);
  EXPECT_EQ(tg_header->GetEndCommitId(5), MAX_CID);

  EXPECT_TRUE(
      val0.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 0)) == 0);
  EXPECT_TRUE(
      val1.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 1)) == 0);
  EXPECT_TRUE(
      val2.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 2)) == 0);
  EXPECT_TRUE(
      val3.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 3)) == 0);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 1);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);
}

TEST_F(RecoveryTests, BasicUpdateTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  auto tuples = BuildLoggingTuples(recovery_table, 1, false, false);
  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 1);
  EXPECT_EQ(tuples.size(), 1);
  logging::WriteAheadFrontendLogger fel(true);
  //  auto bel = logging::WriteAheadBackendLogger::GetInstance();
  cid_t test_commit_id = 10;

  Value val0 = tuples[0]->GetValue(0);
  Value val1 = tuples[0]->GetValue(1);
  Value val2 = tuples[0]->GetValue(2);
  Value val3 = tuples[0]->GetValue(3);

  auto curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_UPDATE, test_commit_id, recovery_table->GetOid(),
      ItemPointer(100, 5), ItemPointer(100, 4), tuples[0], DEFAULT_DB_ID);
  curr_rec->SetTuple(tuples[0]);
  fel.UpdateTuple(curr_rec);
  delete curr_rec;

  auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader();
  EXPECT_TRUE(tg_header->GetBeginCommitId(5) <= test_commit_id);
  EXPECT_EQ(tg_header->GetEndCommitId(5), MAX_CID);
  EXPECT_EQ(tg_header->GetEndCommitId(4), test_commit_id);

  EXPECT_TRUE(
      val0.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 0)) == 0);
  EXPECT_TRUE(
      val1.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 1)) == 0);
  EXPECT_TRUE(
      val2.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 2)) == 0);
  EXPECT_TRUE(
      val3.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 3)) == 0);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);
}

/* (From Joy) TODO FIX this
TEST_F(RecoveryTests, BasicDeleteTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 1);
  logging::WriteAheadFrontendLogger fel(true);

  cid_t test_commit_id = 10;

  auto curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_UPDATE, test_commit_id, recovery_table->GetOid(),
      INVALID_ITEMPOINTER, ItemPointer(100, 4), nullptr, DEFAULT_DB_ID);
  fel.DeleteTuple(curr_rec);

  delete curr_rec;

  auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader();
  EXPECT_EQ(tg_header->GetEndCommitId(4), test_commit_id);

  //  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 1);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);
}*/

TEST_F(RecoveryTests, OutOfOrderCommitTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  auto tuples = BuildLoggingTuples(recovery_table, 1, false, false);
  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 1);
  EXPECT_EQ(tuples.size(), 1);
  logging::WriteAheadFrontendLogger fel(true);
  //  auto bel = logging::WriteAheadBackendLogger::GetInstance();
  cid_t test_commit_id = 10;

  auto curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_UPDATE, test_commit_id + 1, recovery_table->GetOid(),
      INVALID_ITEMPOINTER, ItemPointer(100, 5), nullptr, DEFAULT_DB_ID);
  fel.DeleteTuple(curr_rec);
  delete curr_rec;

  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);

  curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_INSERT, test_commit_id, recovery_table->GetOid(),
      ItemPointer(100, 5), INVALID_ITEMPOINTER, tuples[0], DEFAULT_DB_ID);

  curr_rec->SetTuple(tuples[0]);
  fel.InsertTuple(curr_rec);

  delete curr_rec;

  auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader();
  EXPECT_EQ(tg_header->GetEndCommitId(5), test_commit_id + 1);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);
}

}  // End test namespace
}  // End peloton namespace
<commit_msg>test CreateNewLogFile<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// logging_test.cpp
//
// Identification: tests/logging/logging_test.cpp
//
// Copyright (c) 2016, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <dirent.h>

#include "harness.h"

#include "backend/concurrency/transaction_manager_factory.h"
#include "backend/executor/logical_tile_factory.h"
#include "backend/storage/data_table.h"
#include "backend/storage/tile.h"
#include "backend/logging/loggers/wal_frontend_logger.h"
#include "backend/storage/table_factory.h"
#include "backend/logging/log_manager.h"
#include "backend/index/index.h"

#include "backend/logging/logging_util.h"

#include "logging/logging_tests_util.h"

#include "executor/mock_executor.h"
#include "executor/executor_tests_util.h"

#define DEFAULT_RECOVERY_CID 15

using ::testing::NotNull;
using ::testing::Return;
using ::testing::InSequence;

namespace peloton {
namespace test {

//===--------------------------------------------------------------------===//
// Recovery Tests
//===--------------------------------------------------------------------===//

class RecoveryTests : public PelotonTest {};

std::vector<storage::Tuple *> BuildLoggingTuples(storage::DataTable *table,
                                                 int num_rows, bool mutate,
                                                 bool random) {
  std::vector<storage::Tuple *> tuples;
  LOG_INFO("build a vector of %d tuples", num_rows);

  // Random values
  std::srand(std::time(nullptr));
  const catalog::Schema *schema = table->GetSchema();
  // Ensure that the tile group is as expected.
  assert(schema->GetColumnCount() == 4);

  // Insert tuples into tile_group.
  const bool allocate = true;
  auto testing_pool = TestingHarness::GetInstance().GetTestingPool();

  for (int rowid = 0; rowid < num_rows; rowid++) {
    int populate_value = rowid;
    if (mutate) populate_value *= 3;

    storage::Tuple *tuple = new storage::Tuple(schema, allocate);

    // First column is unique in this case
    tuple->SetValue(0,
                    ValueFactory::GetIntegerValue(
                        ExecutorTestsUtil::PopulatedValue(populate_value, 0)),
                    testing_pool);

    // In case of random, make sure this column has duplicated values
    tuple->SetValue(
        1, ValueFactory::GetIntegerValue(ExecutorTestsUtil::PopulatedValue(
               random ? std::rand() % (num_rows / 3) : populate_value, 1)),
        testing_pool);

    tuple->SetValue(
        2, ValueFactory::GetDoubleValue(ExecutorTestsUtil::PopulatedValue(
               random ? std::rand() : populate_value, 2)),
        testing_pool);

    // In case of random, make sure this column has duplicated values
    Value string_value = ValueFactory::GetStringValue(
        std::to_string(ExecutorTestsUtil::PopulatedValue(
            random ? std::rand() % (num_rows / 3) : populate_value, 3)));
    tuple->SetValue(3, string_value, testing_pool);
    tuples.push_back(tuple);
  }
  return tuples;
}

TEST_F(RecoveryTests, RestartTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();

  size_t tile_group_size = 5;
  size_t table_tile_group_count = 3;
  int num_files = 3;

  auto mutate = true;
  auto random = false;
  cid_t default_commit_id = INVALID_CID;
  cid_t default_delimiter = INVALID_CID;

  std::string dir_name = "pl_log0";
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  int num_rows = tile_group_size * table_tile_group_count;
  std::vector<std::shared_ptr<storage::Tuple>> tuples =
      LoggingTestsUtil::BuildTuples(recovery_table, num_rows, mutate, random);
  std::vector<logging::TupleRecord> records =
      LoggingTestsUtil::BuildTupleRecordsForRestartTest(tuples, tile_group_size,
                                                        table_tile_group_count);

  auto status = logging::LoggingUtil::CreateDirectory(dir_name.c_str(), 0700);
  EXPECT_EQ(status, true);

  for (int i = 0; i < num_files; i++) {
    std::string file_name = dir_name + "/" + std::string("peloton_log_") +
                            std::to_string(i) + std::string(".log");
    FILE *fp = fopen(file_name.c_str(), "wb");

    // now set the first 8 bytes to 0 - this is for the max_log id in this file
    fwrite((void *)&default_commit_id, sizeof(default_commit_id), 1, fp);

    // now set the next 8 bytes to 0 - this is for the max delimiter in this
    // file
    fwrite((void *)&default_delimiter, sizeof(default_delimiter), 1, fp);

    // First write a begin record
    CopySerializeOutput output_buffer_begin;
    logging::TransactionRecord record_begin(LOGRECORD_TYPE_TRANSACTION_BEGIN,
                                            i + 2);
    record_begin.Serialize(output_buffer_begin);

    fwrite(record_begin.GetMessage(), sizeof(char),
           record_begin.GetMessageLength(), fp);

    // Now write 5 insert tuple records into this file
    for (int j = 0; j < (int)tile_group_size; j++) {
      int num_record = i * tile_group_size + j;
      CopySerializeOutput output_buffer;
      records[num_record].Serialize(output_buffer);

      fwrite(records[num_record].GetMessage(), sizeof(char),
             records[num_record].GetMessageLength(), fp);
    }

    // Now write commit
    logging::TransactionRecord record_commit(LOGRECORD_TYPE_TRANSACTION_COMMIT,
                                             i + 2);

    CopySerializeOutput output_buffer_commit;
    record_commit.Serialize(output_buffer_commit);

    fwrite(record_commit.GetMessage(), sizeof(char),
           record_commit.GetMessageLength(), fp);

    // Now write delimiter
    CopySerializeOutput output_buffer_delim;
    logging::TransactionRecord record_delim(LOGRECORD_TYPE_ITERATION_DELIMITER,
                                            i + 2);

    record_delim.Serialize(output_buffer_delim);

    fwrite(record_delim.GetMessage(), sizeof(char),
           record_delim.GetMessageLength(), fp);

    fclose(fp);
  }

  int index_count = recovery_table->GetIndexCount();
  LOG_INFO("Number of indexes on this table: %d", (int)index_count);

  for (int index_itr = index_count - 1; index_itr >= 0; --index_itr) {
    auto index = recovery_table->GetIndex(index_itr);
    EXPECT_EQ(index->GetNumberOfTuples(), 0);
  }

  logging::WriteAheadFrontendLogger wal_fel(std::string("pl_log"));

  EXPECT_EQ(wal_fel.GetMaxDelimiterForRecovery(), num_files + 1);
  EXPECT_EQ(wal_fel.GetLogFileCounter(), num_files);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);

  auto &log_manager = logging::LogManager::GetInstance();
  log_manager.SetGlobalMaxFlushedIdForRecovery(num_files + 1);

  wal_fel.DoRecovery();

  EXPECT_EQ(recovery_table->GetNumberOfTuples(),
            tile_group_size * table_tile_group_count);
  EXPECT_EQ(wal_fel.GetLogFileCursor(), num_files);

  wal_fel.RecoverIndex();
  for (int index_itr = index_count - 1; index_itr >= 0; --index_itr) {
    auto index = recovery_table->GetIndex(index_itr);
    EXPECT_EQ(index->GetNumberOfTuples(),
              tile_group_size * table_tile_group_count);
  }

  // TODO check a few more invariants here
  wal_fel.CreateNewLogFile(false);

  EXPECT_EQ(wal_fel.GetLogFileCounter(), num_files + 1);

  wal_fel.CreateNewLogFile(true);

  EXPECT_EQ(wal_fel.GetLogFileCounter(), num_files + 2);

  status = logging::LoggingUtil::RemoveDirectory("pl_log0", false);
  EXPECT_EQ(status, true);
}

TEST_F(RecoveryTests, BasicInsertTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  auto tuples = BuildLoggingTuples(recovery_table, 1, false, false);
  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 1);
  EXPECT_EQ(tuples.size(), 1);
  logging::WriteAheadFrontendLogger fel(true);
  //  auto bel = logging::WriteAheadBackendLogger::GetInstance();
  cid_t test_commit_id = 10;

  Value val0 = tuples[0]->GetValue(0);
  Value val1 = tuples[0]->GetValue(1);
  Value val2 = tuples[0]->GetValue(2);
  Value val3 = tuples[0]->GetValue(3);
  auto curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_INSERT, test_commit_id, recovery_table->GetOid(),
      ItemPointer(100, 5), INVALID_ITEMPOINTER, tuples[0], DEFAULT_DB_ID);
  curr_rec->SetTuple(tuples[0]);
  fel.InsertTuple(curr_rec);
  delete curr_rec;

  auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader();
  EXPECT_TRUE(tg_header->GetBeginCommitId(5) <= test_commit_id);
  EXPECT_EQ(tg_header->GetEndCommitId(5), MAX_CID);

  EXPECT_TRUE(
      val0.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 0)) == 0);
  EXPECT_TRUE(
      val1.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 1)) == 0);
  EXPECT_TRUE(
      val2.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 2)) == 0);
  EXPECT_TRUE(
      val3.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 3)) == 0);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 1);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);
}

TEST_F(RecoveryTests, BasicUpdateTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  auto tuples = BuildLoggingTuples(recovery_table, 1, false, false);
  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 1);
  EXPECT_EQ(tuples.size(), 1);
  logging::WriteAheadFrontendLogger fel(true);
  //  auto bel = logging::WriteAheadBackendLogger::GetInstance();
  cid_t test_commit_id = 10;

  Value val0 = tuples[0]->GetValue(0);
  Value val1 = tuples[0]->GetValue(1);
  Value val2 = tuples[0]->GetValue(2);
  Value val3 = tuples[0]->GetValue(3);

  auto curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_UPDATE, test_commit_id, recovery_table->GetOid(),
      ItemPointer(100, 5), ItemPointer(100, 4), tuples[0], DEFAULT_DB_ID);
  curr_rec->SetTuple(tuples[0]);
  fel.UpdateTuple(curr_rec);
  delete curr_rec;

  auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader();
  EXPECT_TRUE(tg_header->GetBeginCommitId(5) <= test_commit_id);
  EXPECT_EQ(tg_header->GetEndCommitId(5), MAX_CID);
  EXPECT_EQ(tg_header->GetEndCommitId(4), test_commit_id);

  EXPECT_TRUE(
      val0.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 0)) == 0);
  EXPECT_TRUE(
      val1.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 1)) == 0);
  EXPECT_TRUE(
      val2.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 2)) == 0);
  EXPECT_TRUE(
      val3.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 3)) == 0);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);
}

/* (From Joy) TODO FIX this
TEST_F(RecoveryTests, BasicDeleteTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 1);
  logging::WriteAheadFrontendLogger fel(true);

  cid_t test_commit_id = 10;

  auto curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_UPDATE, test_commit_id, recovery_table->GetOid(),
      INVALID_ITEMPOINTER, ItemPointer(100, 4), nullptr, DEFAULT_DB_ID);
  fel.DeleteTuple(curr_rec);

  delete curr_rec;

  auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader();
  EXPECT_EQ(tg_header->GetEndCommitId(4), test_commit_id);

  //  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 1);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);
}*/

TEST_F(RecoveryTests, OutOfOrderCommitTest) {
  auto recovery_table = ExecutorTestsUtil::CreateTable(1024);
  auto &manager = catalog::Manager::GetInstance();
  storage::Database db(DEFAULT_DB_ID);
  manager.AddDatabase(&db);
  db.AddTable(recovery_table);

  auto tuples = BuildLoggingTuples(recovery_table, 1, false, false);
  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 1);
  EXPECT_EQ(tuples.size(), 1);
  logging::WriteAheadFrontendLogger fel(true);
  //  auto bel = logging::WriteAheadBackendLogger::GetInstance();
  cid_t test_commit_id = 10;

  auto curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_UPDATE, test_commit_id + 1, recovery_table->GetOid(),
      INVALID_ITEMPOINTER, ItemPointer(100, 5), nullptr, DEFAULT_DB_ID);
  fel.DeleteTuple(curr_rec);
  delete curr_rec;

  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);

  curr_rec = new logging::TupleRecord(
      LOGRECORD_TYPE_TUPLE_INSERT, test_commit_id, recovery_table->GetOid(),
      ItemPointer(100, 5), INVALID_ITEMPOINTER, tuples[0], DEFAULT_DB_ID);

  curr_rec->SetTuple(tuples[0]);
  fel.InsertTuple(curr_rec);

  delete curr_rec;

  auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader();
  EXPECT_EQ(tg_header->GetEndCommitId(5), test_commit_id + 1);

  EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0);
  EXPECT_EQ(recovery_table->GetTileGroupCount(), 2);
}

}  // End test namespace
}  // End peloton namespace
<|endoftext|>


<commit_before>/*
 * SMGObjectTest.cxx
 *
 *  Created on: Dec 3, 2015
 *      Author: pmuller
 */

/*
 *  This file is part of SMG, a symbolic memory graph Java library
 *  Originally developed as part of CPAChecker, the configurable software verification platform
 *
 *  Copyright (C) 2011-2015  Petr Muller
 *  Copyright (C) 2007-2014  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

#include <gtest/gtest.h>
#include <SMGObject.hh>

int SIZE8 = 8;
int SIZE12 = 12;

class TestingObject : public SMGObject {
  public:
    TestingObject(const int pSize, const std::string pLabel): SMGObject(pSize, pLabel) {}
    ~TestingObject() {};
    TestingObject(const TestingObject&) = default;
    virtual bool isAbstract() const override { return false; }
    void accept(SMGObjectVisitor & visitor) const override { (void)visitor; }
    virtual bool isMoreGeneral(const SMGObject &) const override { return false; };
    virtual const SMGObject &join(const SMGObject &) const override { return *this; }
    virtual bool notNull() const {return true;}
};

TestingObject object8 = TestingObject(8, "label");
TestingObject object12 = TestingObject(12, "another label");

TEST(SMGObject, getNullObjectTest) {
  const SMGObject &nullObject = SMGObject::getNullObject();
  EXPECT_FALSE(nullObject.notNull());
  EXPECT_TRUE(object8.notNull());
  EXPECT_FALSE(nullObject.isAbstract());
  EXPECT_FALSE(nullObject.isMoreGeneral(object8));
  EXPECT_FALSE(nullObject.isMoreGeneral(nullObject));
  EXPECT_EQ(&nullObject, &nullObject.join(nullObject));
  EXPECT_EQ(&object8, &nullObject.join(object8));
}

//	public final void testSMGObjectIntString() {
//    Assert.assertEquals(SIZE8, object8.getSize());
//    Assert.assertEquals("label", object8.getLabel());
//    Assert.assertEquals(SIZE12, object12.getSize());
//    Assert.assertEquals("another label", object12.getLabel());
//    SMGObject object12copy = new TestingObject(object12);
//    Assert.assertEquals(SIZE12, object12copy.getSize());
//    Assert.assertEquals("another label", object12copy.getLabel());
//  }

TEST(SMGObject, PropertySanity){
  EXPECT_EQ(SIZE8, object8.getSize());
  EXPECT_STREQ("label", object8.getLabel().c_str());
  EXPECT_EQ(SIZE12, object12.getSize());
  EXPECT_STREQ("another label", object12.getLabel().c_str());
  SMGObject* object12Copy = new TestingObject(object12);
  EXPECT_EQ(SIZE12, object12Copy->getSize());
  EXPECT_STREQ("another label", object12Copy->getLabel().c_str());
}

//  private static class TestingObject extends SMGObject {
//
//    protected TestingObject(final int pSize, final String pLabel) {
//      super(pSize, pLabel);
//    }
//
//    protected TestingObject(final TestingObject pOther) {
//      super(pOther);
//    }
//
//    @Override
//    public boolean isAbstract() {
//      return false;
//    }
//
//    @Override
//    public void accept(final SMGObjectVisitor pVisitor) {
//      pVisitor.visit(this);
//    }
//
//    @Override
//    public boolean isMoreGeneral(final SMGObject pOther) {
//      return false;
//    }
//
//    @Override
//    public SMGObject join(final SMGObject pOther) {
//      return pOther;
//    }
//  }
//
//  @Test
//	public final void testVisitorOnNull() {
//    SMGObject nullObject = SMGObject.getNullObject();
//    SMGObjectVisitor visitor = new SMGObjectVisitor() {
//      @Override
//      public void visit(final SMGObject pObject) {
//        Assert.assertFalse(pObject.notNull());
//      }
//    };
//    nullObject.accept(visitor);
//  }
//}
<commit_msg>Make formatting consistent. Also, fix a memory leak.<commit_after>/*
 * SMGObjectTest.cxx
 *
 *  Created on: Dec 3, 2015
 *      Author: pmuller
 */

/*
 *  This file is part of SMG, a symbolic memory graph Java library
 *  Originally developed as part of CPAChecker, the configurable software verification platform
 *
 *  Copyright (C) 2011-2015  Petr Muller
 *  Copyright (C) 2007-2014  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

#include <gtest/gtest.h>
#include <SMGObject.hh>

int SIZE8 = 8;
int SIZE12 = 12;

class TestingObject: public SMGObject {
public:
    TestingObject(const int pSize, const std::string pLabel) :
            SMGObject(pSize, pLabel) {
    }
    ~TestingObject() {
    }
    ;
    TestingObject(const TestingObject&) = default;
    virtual bool isAbstract() const override {
        return false;
    }
    void accept(SMGObjectVisitor & visitor) const override {
        (void) visitor;
    }
    virtual bool isMoreGeneral(const SMGObject &) const override {
        return false;
    }
    ;
    virtual const SMGObject &join(const SMGObject &) const override {
        return *this;
    }
    virtual bool notNull() const {
        return true;
    }
};

TestingObject object8 = TestingObject(8, "label");
TestingObject object12 = TestingObject(12, "another label");

TEST(SMGObject, getNullObjectTest) {
    const SMGObject &nullObject = SMGObject::getNullObject();
    EXPECT_FALSE(nullObject.notNull());
    EXPECT_TRUE(object8.notNull());
    EXPECT_FALSE(nullObject.isAbstract());
    EXPECT_FALSE(nullObject.isMoreGeneral(object8));
    EXPECT_FALSE(nullObject.isMoreGeneral(nullObject));
    EXPECT_EQ(&nullObject, &nullObject.join(nullObject));
    EXPECT_EQ(&object8, &nullObject.join(object8));
}

//	public final void testSMGObjectIntString() {
//    Assert.assertEquals(SIZE8, object8.getSize());
//    Assert.assertEquals("label", object8.getLabel());
//    Assert.assertEquals(SIZE12, object12.getSize());
//    Assert.assertEquals("another label", object12.getLabel());
//    SMGObject object12copy = new TestingObject(object12);
//    Assert.assertEquals(SIZE12, object12copy.getSize());
//    Assert.assertEquals("another label", object12copy.getLabel());
//  }

TEST(SMGObject, PropertySanity) {
    EXPECT_EQ(SIZE8, object8.getSize());
    EXPECT_STREQ("label", object8.getLabel().c_str());
    EXPECT_EQ(SIZE12, object12.getSize());
    EXPECT_STREQ("another label", object12.getLabel().c_str());
    SMGObject* object12Copy = new TestingObject(object12);
    EXPECT_EQ(SIZE12, object12Copy->getSize());
    EXPECT_STREQ("another label", object12Copy->getLabel().c_str());
    delete object12Copy;
}

//  private static class TestingObject extends SMGObject {
//
//    protected TestingObject(final int pSize, final String pLabel) {
//      super(pSize, pLabel);
//    }
//
//    protected TestingObject(final TestingObject pOther) {
//      super(pOther);
//    }
//
//    @Override
//    public boolean isAbstract() {
//      return false;
//    }
//
//    @Override
//    public void accept(final SMGObjectVisitor pVisitor) {
//      pVisitor.visit(this);
//    }
//
//    @Override
//    public boolean isMoreGeneral(final SMGObject pOther) {
//      return false;
//    }
//
//    @Override
//    public SMGObject join(final SMGObject pOther) {
//      return pOther;
//    }
//  }
//
//  @Test
//	public final void testVisitorOnNull() {
//    SMGObject nullObject = SMGObject.getNullObject();
//    SMGObjectVisitor visitor = new SMGObjectVisitor() {
//      @Override
//      public void visit(final SMGObject pObject) {
//        Assert.assertFalse(pObject.notNull());
//      }
//    };
//    nullObject.accept(visitor);
//  }
//}
<|endoftext|>


<commit_before>#include <memory>

#include "extensions/filters/http/well_known_names.h"

#include "test/integration/http_integration.h"

#include "gtest/gtest.h"

namespace Envoy {
namespace {

using SkipEncodingEmptyTrailers = bool;
using TestParams =
    std::tuple<Network::Address::IpVersion, Http::CodecClient::Type, SkipEncodingEmptyTrailers>;

class GrpcWebFilterIntegrationTest : public testing::TestWithParam<TestParams>,
                                     public HttpIntegrationTest {
public:
  GrpcWebFilterIntegrationTest()
      : HttpIntegrationTest(std::get<1>(GetParam()), std::get<0>(GetParam())) {}

  void SetUp() override {
    setUpstreamProtocol(FakeHttpConnection::Type::HTTP2);
    config_helper_.addFilter("name: envoy.filters.http.grpc_web");
  }

  void skipEncodingEmptyTrailers(SkipEncodingEmptyTrailers http2_skip_encoding_empty_trailers) {
    config_helper_.addRuntimeOverride(
        "envoy.reloadable_features.http2_skip_encoding_empty_trailers",
        http2_skip_encoding_empty_trailers ? "true" : "false");
  }

  static std::string testParamsToString(const testing::TestParamInfo<TestParams> params) {
    return fmt::format(
        "{}_{}_{}",
        TestUtility::ipTestParamsToString(testing::TestParamInfo<Network::Address::IpVersion>(
            std::get<0>(params.param), params.index)),
        std::get<1>(params.param) == Http::CodecClient::Type::HTTP2 ? "Http2" : "Http",
        std::get<2>(params.param) ? "SkipEncodingEmptyTrailers" : "SubmitEncodingEmptyTrailers");
  }
};

INSTANTIATE_TEST_SUITE_P(
    Params, GrpcWebFilterIntegrationTest,
    testing::Combine(
        testing::ValuesIn(TestEnvironment::getIpVersionsForTest()),
        testing::Values(Http::CodecClient::Type::HTTP1, Http::CodecClient::Type::HTTP2),
        testing::Values(SkipEncodingEmptyTrailers{true}, SkipEncodingEmptyTrailers{false})),
    GrpcWebFilterIntegrationTest::testParamsToString);

TEST_P(GrpcWebFilterIntegrationTest, GrpcWebTrailersNotDuplicated) {
  const auto downstream_protocol = std::get<1>(GetParam());
  const bool http2_skip_encoding_empty_trailers = std::get<2>(GetParam());

  if (downstream_protocol == Http::CodecClient::Type::HTTP1) {
    config_helper_.addConfigModifier(setEnableDownstreamTrailersHttp1());
  } else {
    skipEncodingEmptyTrailers(http2_skip_encoding_empty_trailers);
  }

  setUpstreamProtocol(FakeHttpConnection::Type::HTTP2);

  Http::TestRequestTrailerMapImpl request_trailers{{"request1", "trailer1"},
                                                   {"request2", "trailer2"}};
  Http::TestResponseTrailerMapImpl response_trailers{{"response1", "trailer1"},
                                                     {"response2", "trailer2"}};

  initialize();
  codec_client_ = makeHttpConnection(lookupPort("http"));
  auto encoder_decoder = codec_client_->startRequest(
      Http::TestRequestHeaderMapImpl{{":method", "POST"},
                                     {":path", "/test/long/url"},
                                     {":scheme", "http"},
                                     {"content-type", "application/grpc-web"},
                                     {":authority", "host"}});
  request_encoder_ = &encoder_decoder.first;
  auto response = std::move(encoder_decoder.second);
  codec_client_->sendData(*request_encoder_, 1, false);
  codec_client_->sendTrailers(*request_encoder_, request_trailers);
  waitForNextUpstreamRequest();
  upstream_request_->encodeHeaders(default_response_headers_, false);
  upstream_request_->encodeData(1, false);
  upstream_request_->encodeTrailers(response_trailers);
  response->waitForEndStream();

  EXPECT_TRUE(upstream_request_->complete());
  EXPECT_EQ(1, upstream_request_->bodyLength());
  EXPECT_THAT(*upstream_request_->trailers(), HeaderMapEqualRef(&request_trailers));

  EXPECT_TRUE(response->complete());
  EXPECT_EQ("200", response->headers().getStatusValue());
  EXPECT_TRUE(absl::StrContains(response->body(), "response1:trailer1"));
  EXPECT_TRUE(absl::StrContains(response->body(), "response2:trailer2"));

  if (downstream_protocol == Http::CodecClient::Type::HTTP1) {
    // When the downstream protocol is HTTP/1.1 we expect the trailers to be in the response-body.
    EXPECT_EQ(nullptr, response->trailers());
  }

  if (downstream_protocol == Http::CodecClient::Type::HTTP2) {
    if (http2_skip_encoding_empty_trailers) {
      // When the downstream protocol is HTTP/2 and the feature-flag to skip encoding empty trailers
      // is turned on, expect that the trailers are included in the response-body.
      EXPECT_EQ(nullptr, response->trailers());
    } else {
      // Otherwise, we send empty trailers.
      ASSERT_NE(nullptr, response->trailers());
      EXPECT_TRUE(response->trailers()->empty());
    }
  }
}

} // namespace
} // namespace Envoy
<commit_msg>grpc: upstream disconnect test (#13898)<commit_after>#include <memory>

#include "extensions/filters/http/well_known_names.h"

#include "test/integration/http_integration.h"

#include "gtest/gtest.h"

namespace Envoy {
namespace {

using SkipEncodingEmptyTrailers = bool;
using TestParams =
    std::tuple<Network::Address::IpVersion, Http::CodecClient::Type, SkipEncodingEmptyTrailers>;

class GrpcWebFilterIntegrationTest : public testing::TestWithParam<TestParams>,
                                     public HttpIntegrationTest {
public:
  GrpcWebFilterIntegrationTest()
      : HttpIntegrationTest(std::get<1>(GetParam()), std::get<0>(GetParam())) {}

  void SetUp() override {
    setUpstreamProtocol(FakeHttpConnection::Type::HTTP2);
    config_helper_.addFilter("name: envoy.filters.http.grpc_web");
  }

  void skipEncodingEmptyTrailers(SkipEncodingEmptyTrailers http2_skip_encoding_empty_trailers) {
    config_helper_.addRuntimeOverride(
        "envoy.reloadable_features.http2_skip_encoding_empty_trailers",
        http2_skip_encoding_empty_trailers ? "true" : "false");
  }

  static std::string testParamsToString(const testing::TestParamInfo<TestParams> params) {
    return fmt::format(
        "{}_{}_{}",
        TestUtility::ipTestParamsToString(testing::TestParamInfo<Network::Address::IpVersion>(
            std::get<0>(params.param), params.index)),
        std::get<1>(params.param) == Http::CodecClient::Type::HTTP2 ? "Http2" : "Http",
        std::get<2>(params.param) ? "SkipEncodingEmptyTrailers" : "SubmitEncodingEmptyTrailers");
  }
};

INSTANTIATE_TEST_SUITE_P(
    Params, GrpcWebFilterIntegrationTest,
    testing::Combine(
        testing::ValuesIn(TestEnvironment::getIpVersionsForTest()),
        testing::Values(Http::CodecClient::Type::HTTP1, Http::CodecClient::Type::HTTP2),
        testing::Values(SkipEncodingEmptyTrailers{true}, SkipEncodingEmptyTrailers{false})),
    GrpcWebFilterIntegrationTest::testParamsToString);

TEST_P(GrpcWebFilterIntegrationTest, GrpcWebTrailersNotDuplicated) {
  const auto downstream_protocol = std::get<1>(GetParam());
  const bool http2_skip_encoding_empty_trailers = std::get<2>(GetParam());

  if (downstream_protocol == Http::CodecClient::Type::HTTP1) {
    config_helper_.addConfigModifier(setEnableDownstreamTrailersHttp1());
  } else {
    skipEncodingEmptyTrailers(http2_skip_encoding_empty_trailers);
  }

  setUpstreamProtocol(FakeHttpConnection::Type::HTTP2);

  Http::TestRequestTrailerMapImpl request_trailers{{"request1", "trailer1"},
                                                   {"request2", "trailer2"}};
  Http::TestResponseTrailerMapImpl response_trailers{{"response1", "trailer1"},
                                                     {"response2", "trailer2"}};

  initialize();
  codec_client_ = makeHttpConnection(lookupPort("http"));
  auto encoder_decoder = codec_client_->startRequest(
      Http::TestRequestHeaderMapImpl{{":method", "POST"},
                                     {":path", "/test/long/url"},
                                     {":scheme", "http"},
                                     {"content-type", "application/grpc-web"},
                                     {":authority", "host"}});
  request_encoder_ = &encoder_decoder.first;
  auto response = std::move(encoder_decoder.second);
  codec_client_->sendData(*request_encoder_, 1, false);
  codec_client_->sendTrailers(*request_encoder_, request_trailers);
  waitForNextUpstreamRequest();
  upstream_request_->encodeHeaders(default_response_headers_, false);
  upstream_request_->encodeData(1, false);
  upstream_request_->encodeTrailers(response_trailers);
  response->waitForEndStream();

  EXPECT_TRUE(upstream_request_->complete());
  EXPECT_EQ(1, upstream_request_->bodyLength());
  EXPECT_THAT(*upstream_request_->trailers(), HeaderMapEqualRef(&request_trailers));

  EXPECT_TRUE(response->complete());
  EXPECT_EQ("200", response->headers().getStatusValue());
  EXPECT_TRUE(absl::StrContains(response->body(), "response1:trailer1"));
  EXPECT_TRUE(absl::StrContains(response->body(), "response2:trailer2"));

  if (downstream_protocol == Http::CodecClient::Type::HTTP1) {
    // When the downstream protocol is HTTP/1.1 we expect the trailers to be in the response-body.
    EXPECT_EQ(nullptr, response->trailers());
  }

  if (downstream_protocol == Http::CodecClient::Type::HTTP2) {
    if (http2_skip_encoding_empty_trailers) {
      // When the downstream protocol is HTTP/2 and the feature-flag to skip encoding empty trailers
      // is turned on, expect that the trailers are included in the response-body.
      EXPECT_EQ(nullptr, response->trailers());
    } else {
      // Otherwise, we send empty trailers.
      ASSERT_NE(nullptr, response->trailers());
      EXPECT_TRUE(response->trailers()->empty());
    }
  }
}

TEST_P(GrpcWebFilterIntegrationTest, UpstreamDisconnect) {
  const auto downstream_protocol = std::get<1>(GetParam());
  const bool http2_skip_encoding_empty_trailers = std::get<2>(GetParam());

  if (downstream_protocol == Http::CodecClient::Type::HTTP1) {
    config_helper_.addConfigModifier(setEnableDownstreamTrailersHttp1());
  } else {
    skipEncodingEmptyTrailers(http2_skip_encoding_empty_trailers);
  }

  setUpstreamProtocol(FakeHttpConnection::Type::HTTP2);

  Http::TestRequestTrailerMapImpl request_trailers{{"request1", "trailer1"},
                                                   {"request2", "trailer2"}};

  initialize();
  codec_client_ = makeHttpConnection(lookupPort("http"));
  auto encoder_decoder = codec_client_->startRequest(
      Http::TestRequestHeaderMapImpl{{":method", "POST"},
                                     {":path", "/test/long/url"},
                                     {":scheme", "http"},
                                     {"content-type", "application/grpc-web"},
                                     {":authority", "host"}});
  request_encoder_ = &encoder_decoder.first;
  auto response = std::move(encoder_decoder.second);
  codec_client_->sendData(*request_encoder_, 1, false);
  codec_client_->sendTrailers(*request_encoder_, request_trailers);
  waitForNextUpstreamRequest();

  ASSERT_TRUE(fake_upstream_connection_->close());
  response->waitForEndStream();
  EXPECT_EQ("503", response->headers().getStatusValue());

  codec_client_->close();
}

} // namespace
} // namespace Envoy
<|endoftext|>