text:
/*
    This file is part of cpp-ethereum.

    cpp-ethereum is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    cpp-ethereum 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Pretty-printer for the abstract syntax tree (the "pretty" is arguable), used for debugging.
 */

#include <libsolidity/ast/ASTPrinter.h>
#include <boost/algorithm/string/join.hpp>
#include <libsolidity/ast/AST.h>

using namespace std;

namespace dev
{
namespace solidity
{

ASTPrinter::ASTPrinter(
	ASTNode const& _ast,
	string const& _source,
	GasEstimator::ASTGasConsumption const& _gasCosts
): m_indentation(0), m_source(_source), m_ast(&_ast), m_gasCosts(_gasCosts)
{
}

void ASTPrinter::print(ostream& _stream)
{
	m_ostream = &_stream;
	m_ast->accept(*this);
	m_ostream = nullptr;
}

bool ASTPrinter::visit(ImportDirective const& _node)
{
	writeLine("ImportDirective \"" + _node.path() + "\"");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(ContractDefinition const& _node)
{
	writeLine("ContractDefinition \"" + _node.name() + "\"");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(InheritanceSpecifier const& _node)
{
	writeLine("InheritanceSpecifier");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(StructDefinition const& _node)
{
	writeLine("StructDefinition \"" + _node.name() + "\"");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(EnumDefinition const& _node)
{
	writeLine("EnumDefinition \"" + _node.name() + "\"");
	return goDeeper();
}

bool ASTPrinter::visit(EnumValue const& _node)
{
	writeLine("EnumValue \"" + _node.name() + "\"");
	return goDeeper();
}

bool ASTPrinter::visit(ParameterList const& _node)
{
	writeLine("ParameterList");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(FunctionDefinition const& _node)
{
	writeLine("FunctionDefinition \"" + _node.name() + "\"" +
			  (_node.isPublic() ? " - public" : "") +
			  (_node.isDeclaredConst() ? " - const" : ""));
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(VariableDeclaration const& _node)
{
	writeLine("VariableDeclaration \"" + _node.name() + "\"");
	*m_ostream << indentation() << (
		_node.annotation().type ?
		string("   Type: ") + _node.annotation().type->toString() :
		string("   Type unknown.")
	) << "\n";
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(ModifierDefinition const& _node)
{
	writeLine("ModifierDefinition \"" + _node.name() + "\"");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(ModifierInvocation const& _node)
{
	writeLine("ModifierInvocation \"" + _node.name()->name() + "\"");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(EventDefinition const& _node)
{
	writeLine("EventDefinition \"" + _node.name() + "\"");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(TypeName const& _node)
{
	writeLine("TypeName");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(ElementaryTypeName const& _node)
{
	writeLine(string("ElementaryTypeName ") + _node.typeName().toString());
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(UserDefinedTypeName const& _node)
{
	writeLine("UserDefinedTypeName \"" + boost::algorithm::join(_node.namePath(), ".") + "\"");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Mapping const& _node)
{
	writeLine("Mapping");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(ArrayTypeName const& _node)
{
	writeLine("ArrayTypeName");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(InlineAssembly const& _node)
{
	writeLine("InlineAssembly");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Block const& _node)
{
	writeLine("Block");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(PlaceholderStatement const& _node)
{
	writeLine("PlaceholderStatement");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(IfStatement const& _node)
{
	writeLine("IfStatement");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(WhileStatement const& _node)
{
	writeLine("WhileStatement");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(ForStatement const& _node)
{
	writeLine("ForStatement");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Continue const& _node)
{
	writeLine("Continue");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Break const& _node)
{
	writeLine("Break");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Return const& _node)
{
	writeLine("Return");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Throw const& _node)
{
	writeLine("Throw");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(VariableDeclarationStatement const& _node)
{
	writeLine("VariableDeclarationStatement");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(ExpressionStatement const& _node)
{
	writeLine("ExpressionStatement");
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Conditional const& _node)
{
	writeLine("Conditional");
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Assignment const& _node)
{
	writeLine(string("Assignment using operator ") + Token::toString(_node.assignmentOperator()));
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(TupleExpression const& _node)
{
	writeLine(string("TupleExpression"));
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(UnaryOperation const& _node)
{
	writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") +
			  ") " + Token::toString(_node.getOperator()));
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(BinaryOperation const& _node)
{
	writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator()));
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(FunctionCall const& _node)
{
	writeLine("FunctionCall");
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(NewExpression const& _node)
{
	writeLine("NewExpression");
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(MemberAccess const& _node)
{
	writeLine("MemberAccess to member " + _node.memberName());
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(IndexAccess const& _node)
{
	writeLine("IndexAccess");
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Identifier const& _node)
{
	writeLine(string("Identifier ") + _node.name());
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(ElementaryTypeNameExpression const& _node)
{
	writeLine(string("ElementaryTypeNameExpression ") + _node.typeName().toString());
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

bool ASTPrinter::visit(Literal const& _node)
{
	char const* tokenString = Token::toString(_node.token());
	if (!tokenString)
		tokenString = "[no token]";
	writeLine(string("Literal, token: ") + tokenString + " value: " + _node.value());
	printType(_node);
	printSourcePart(_node);
	return goDeeper();
}

void ASTPrinter::endVisit(ImportDirective const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(ContractDefinition const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(InheritanceSpecifier const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(StructDefinition const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(EnumDefinition const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(EnumValue const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(ParameterList const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(FunctionDefinition const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(VariableDeclaration const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(ModifierDefinition const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(ModifierInvocation const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(EventDefinition const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(TypeName const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(ElementaryTypeName const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(UserDefinedTypeName const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Mapping const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(ArrayTypeName const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(InlineAssembly const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Block const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(PlaceholderStatement const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(IfStatement const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(WhileStatement const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(ForStatement const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Continue const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Break const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Return const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Throw const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(VariableDeclarationStatement const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(ExpressionStatement const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Conditional const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Assignment const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(TupleExpression const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(UnaryOperation const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(BinaryOperation const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(FunctionCall const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(NewExpression const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(MemberAccess const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(IndexAccess const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Identifier const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(ElementaryTypeNameExpression const&)
{
	m_indentation--;
}

void ASTPrinter::endVisit(Literal const&)
{
	m_indentation--;
}

void ASTPrinter::printSourcePart(ASTNode const& _node)
{
	if (m_gasCosts.count(&_node))
		*m_ostream << indentation() << "   Gas costs: " << m_gasCosts.at(&_node) << endl;
	if (!m_source.empty())
	{
		SourceLocation const& location(_node.location());
		*m_ostream << indentation() << "   Source: "
				   << escaped(m_source.substr(location.start, location.end - location.start), false) << endl;
	}
}

void ASTPrinter::printType(Expression const& _expression)
{
	if (_expression.annotation().type)
		*m_ostream << indentation() << "   Type: " << _expression.annotation().type->toString() << "\n";
	else
		*m_ostream << indentation() << "   Type unknown.\n";
}

string ASTPrinter::indentation() const
{
	return string(m_indentation * 2, ' ');
}

void ASTPrinter::writeLine(string const& _line)
{
	*m_ostream << indentation() << _line << endl;
}

}
}

ext: cpp

max_stars_repo_name: miohtama/solidity

max_issues_repo_name: miohtama/solidity

max_forks_repo_name: miohtama/solidity


text:
//
// boost-geometry-render
//
// Copyright (c) 2011
// osyo-manga : http://d.hatena.ne.jp/osyo-manga/
//
// License:
// Boost Software License - Version 1.0
// <http://www.boost.org/LICENSE_1_0.txt>
//
#ifndef BOOST_GEOMETRY_RENDER_GL_GEOMETRY_RENDER_H
#define BOOST_GEOMETRY_RENDER_GL_GEOMETRY_RENDER_H

#include <boost/geometry/geometry.hpp>
#include <boost/mpl/size_t.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/at.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/range/algorithm/for_each.hpp>

namespace gl{

template<typename T>
void
render(T const& geometry);

namespace detail{

namespace mpl = boost::mpl;
namespace bg  = boost::geometry;

typedef mpl::map<
	mpl::pair<short,  mpl::size_t<GL_SHORT> >,
	mpl::pair<int,    mpl::size_t<GL_INT> >,
	mpl::pair<float,  mpl::size_t<GL_FLOAT> >,
	mpl::pair<double, mpl::size_t<GL_DOUBLE> >
> glVertexPointer_value_types;

template<typename Geometry>
struct glVertexPointer_value_type :
	mpl::at<
		glVertexPointer_value_types,
		typename boost::geometry::coordinate_type<Geometry>::type
	>::type
{};

template<typename Tag>
struct geometry_render;

template<>
struct geometry_render<boost::geometry::polygon_tag>{
	template<typename T>
	static void apply(T const& geometry){
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(bg::dimension<T>::value,
			glVertexPointer_value_type<T>::value, 0, &geometry.outer()[0]);
		glDrawArrays(GL_POLYGON, 0, geometry.outer().size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
};

template<>
struct geometry_render<boost::geometry::ring_tag>{
	template<typename T>
	static void apply(T const& geometry){
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(bg::dimension<T>::value,
			glVertexPointer_value_type<T>::value, 0, &geometry[0]);
		glDrawArrays(GL_POLYGON, 0, geometry.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
};

template<>
struct geometry_render<boost::geometry::linestring_tag>{
	template<typename T>
	static void apply(T const& geometry){
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(bg::dimension<T>::value,
			glVertexPointer_value_type<T>::value, 0, &geometry[0]);
		glDrawArrays(GL_LINE_STRIP, 0, geometry.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
};

template<>
struct geometry_render<boost::geometry::point_tag>{
	template<typename T>
	static void apply(T const& geometry){
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(bg::dimension<T>::value,
			glVertexPointer_value_type<T>::value, 0, &geometry.template get<0>());
		glDrawArrays(GL_POINTS, 0, 1);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
};

template<>
struct geometry_render<boost::geometry::multi_point_tag>{
	template<typename T>
	static void apply(T const& geometry){
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(bg::dimension<T>::value,
			glVertexPointer_value_type<T>::value, 0, &geometry[0]);
		glDrawArrays(GL_POINTS, 0, geometry.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
};

template<>
struct geometry_render<boost::geometry::multi_linestring_tag>{
	template<typename T>
	static void apply(T const& geometry){
		typedef bg::model::linestring<typename bg::point_type<T>::type> linestring_type;
		boost::for_each(geometry, &render<linestring_type>);
	}
};

template<>
struct geometry_render<boost::geometry::multi_polygon_tag>{
	template<typename T>
	static void apply(T const& geometry){
		typedef bg::model::polygon<typename bg::point_type<T>::type> polygon_type;
		boost::for_each(geometry, &render<polygon_type>);
	}
};

template<>
struct geometry_render<boost::geometry::box_tag>{
	template<typename T>
	static void apply(T const& geometry){
		bg::model::polygon<typename bg::point_type<T>::type> polygon;
		bg::convert(geometry, polygon);
		render(polygon);
	}
};

}  // namespace detail

template<typename T>
void
render(T const& geometry){
	if(boost::geometry::num_points(geometry) > 0){
		detail::geometry_render<
			typename boost::geometry::tag<T>::type
		>::apply(geometry);
	}
}

} // namespace gl

#endif /* BOOST_GEOMETRY_RENDER_GL_GEOMETRY_RENDER_H */

ext: hpp

max_stars_repo_name: osyo-manga/boost-geometry-render

max_issues_repo_name: osyo-manga/boost-geometry-render

max_forks_repo_name: osyo-manga/boost-geometry-render


text:
#include <bsoncxx/builder/basic/document.hpp>
#include <bsoncxx/builder/basic/kvp.hpp>
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>

#include <boost/exception/diagnostic_information.hpp>

#include <yaml-cpp/yaml.h>

#include <testlib/ActorHelper.hpp>
#include <testlib/MongoTestFixture.hpp>
#include <testlib/helpers.hpp>

#include <gennylib/context.hpp>

namespace {
using namespace genny::testing;
namespace BasicBson = bsoncxx::builder::basic;
namespace bson_stream = bsoncxx::builder::stream;

class SessionTest {
public:
    SessionTest() {}

    void clearEvents() {
        events.clear();
    }

    std::function<void(const mongocxx::events::command_started_event&)> callback =
        [&](const mongocxx::events::command_started_event& event) {
            std::string command_name{event.command_name().data()};

            // Ignore auth commands like "saslStart", and handshakes with "isMaster".
            std::string sasl{"sasl"};
            if (event.command_name().substr(0, sasl.size()).compare(sasl) == 0 ||
                command_name.compare("isMaster") == 0) {
                return;
            }

            events.emplace_back(command_name, bsoncxx::document::value(event.command()));
        };

    class ApmEvent {
    public:
        ApmEvent(const std::string& command_name_, const bsoncxx::document::value& document_)
            : command_name(command_name_), value(document_), command(value.view()) {}

        std::string command_name;
        bsoncxx::document::value value;
        bsoncxx::document::view command;
    };

    std::vector<ApmEvent> events;
    mongocxx::options::client clientOpts;
};

TEST_CASE_METHOD(MongoTestFixture,
                 "CrudActor successfully connects to a MongoDB instance.",
                 "[standalone][single_node_replset][three_node_replset][CrudActor]") {

    dropAllDatabases();
    auto db = client.database("mydb");

    YAML::Node config = YAML::Load(R"(
      SchemaVersion: 2018-07-01
      Actors:
      - Name: CrudActor
        Type: CrudActor
        Database: mydb
        ExecutionStrategy:
          ThrowOnFailure: true
        Phases:
        - Repeat: 1
          Collection: test
          Operations:
          - OperationName: bulkWrite
            OperationCommand:
              WriteOperations:
              - WriteCommand: insertOne
                Document: { a: 1 }
      )");

    SECTION("Inserts documents into the database.") {
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto builder = bson_stream::document{};
            builder << "a"
                    << "1" << bson_stream::finalize;
            auto count = db.collection("test").count(builder.view());
            REQUIRE(count == 1);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }
}

TEST_CASE_METHOD(MongoTestFixture,
                 "Test bulkWrite operation.",
                 "[standalone][single_node_replset][three_node_replset][CrudActor]") {

    dropAllDatabases();
    auto db = client.database("mydb");

    SECTION("Inserts and updates document in the database.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: 1 }
                  - WriteCommand: updateOne
                    Filter: { a: 1 }
                    Update: { $set: { a: 5 } }
          )");
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto count =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 5)));
            REQUIRE(count == 1);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Inserts and deletes documents in the database.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: 1 }
                  - WriteCommand: deleteOne
                    Filter: { a: 1 }
                  - WriteCommand: insertOne
                    Document: { a: 2 }
          )");
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto count =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 1)));
            REQUIRE(count == 0);
            count = db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 2)));
            REQUIRE(count == 1);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Inserts and replaces document in the database.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: 1 }
                  - WriteCommand: replaceOne
                    Filter: { a : 1 }
                    Replacement: { name: test }
          )");
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto count = db.collection("test").count(
                BasicBson::make_document(BasicBson::kvp("name", "test")));
            REQUIRE(count == 1);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Inserts and updates with 'BypassDocumentValidation' true and 'Ordered' false.") {
        SessionTest test;

        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: 1 }
                  - WriteCommand: updateOne
                    Filter: { a: 1 }
                    Update: { $set: { a: 5 } }
                  Options:
                    Ordered: false
                    BypassDocumentValidation: true
          )");
        try {
            genny::ActorHelper ah(
                config, 1, MongoTestFixture::connectionUri().to_string(), test.callback);
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto count =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 5)));
            REQUIRE(count == 1);
            REQUIRE(test.events.size() > 0);
            for (auto&& event : test.events) {
                REQUIRE(event.command["ordered"]);
                auto isOrdered = event.command["ordered"].get_bool().value;
                REQUIRE(isOrdered == false);
                REQUIRE(event.command["bypassDocumentValidation"]);
                auto bypassDocValidation =
                    event.command["bypassDocumentValidation"].get_bool().value;
                REQUIRE(bypassDocValidation);
            }
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Inserts and updates many documents in the database.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: {^RandomInt: {min: 5, max: 15} } }
                  - WriteCommand: insertOne
                    Document: { a: {^RandomInt: {min: 5, max: 15} } }
                  - WriteCommand: insertOne
                    Document: { a: {^RandomInt: {min: 5, max: 15} } }
                  - WriteCommand: updateMany
                    Filter: { a: {$gte: 5} }
                    Update: { $set: { a: 1 } }
          )");
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto count =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 1)));
            REQUIRE(count == 3);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Inserts and deletes many documents in the database.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: {^RandomInt: {min: 5, max: 15} } }
                  - WriteCommand: insertOne
                    Document: { a: {^RandomInt: {min: 5, max: 15} } }
                  - WriteCommand: insertOne
                    Document: { a: {^RandomInt: {min: 5, max: 15} } }
                  - WriteCommand: deleteMany
                    Filter: { a: {$gte: 5} }
          )");
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto count = db.collection("test").count(BasicBson::make_document(
                BasicBson::kvp("a", BasicBson::make_document(BasicBson::kvp("$gte", 5)))));
            REQUIRE(count == 0);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Insert randomly generated doc and update with write concern majority.") {
        SessionTest test;
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: {^RandomInt: {min: 2, max: 5} }}
                  - WriteCommand: updateOne
                    Filter: { a: { $gte: 2 } }
                    Update: { $set: { a: 8 } }
                  Options:
                    WriteConcern:
                      Level: majority
                      Timeout: 6000 milliseconds
          )");
        try {
            genny::ActorHelper ah(
                config, 1, MongoTestFixture::connectionUri().to_string(), test.callback);
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto count =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 8)));
            REQUIRE(count == 1);
            REQUIRE(test.events.size() > 0);
            for (auto&& event : test.events) {
                REQUIRE(event.command["writeConcern"]);
                auto writeConcernLevel = event.command["writeConcern"]["w"].get_utf8().value;
                REQUIRE(std::string(writeConcernLevel) == "majority");
                auto timeout = event.command["writeConcern"]["wtimeout"].get_int32().value;
                REQUIRE(timeout == 6000);
            }

        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }
}

TEST_CASE_METHOD(MongoTestFixture,
                 "Test write concern options.",
                 "[standalone][single_node_replset][three_node_replset][CrudActor]") {

    dropAllDatabases();
    SessionTest test;
    auto db = client.database("mydb");
    test.clearEvents();

    SECTION("Write concern majority with timeout.") {
        YAML::Node config = YAML::Load(R"(
            SchemaVersion: 2018-07-01
            Actors:
            - Name: CrudActor
              Type: CrudActor
              Database: mydb
              ExecutionStrategy:
                ThrowOnFailure: true
              Phases:
              - Repeat: 1
                Collection: test
                Operations:
                - OperationName: bulkWrite
                  OperationCommand:
                    WriteOperations:
                    - WriteCommand: insertOne
                      Document: { a: 1 }
                    - WriteCommand: updateOne
                      Filter: { a: 1 }
                      Update: { $set: { a: 5 } }
                    Options:
                      WriteConcern:
                        Level: majority
                        Timeout: 5000 milliseconds
            )");
        try {
            genny::ActorHelper ah(
                config, 1, MongoTestFixture::connectionUri().to_string(), test.callback);
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            REQUIRE(test.events.size() > 0);
            for (auto&& event : test.events) {
                REQUIRE(event.command["writeConcern"]);
                auto writeConcernLevel = event.command["writeConcern"]["w"].get_utf8().value;
                REQUIRE(std::string(writeConcernLevel) == "majority");
                auto timeout = event.command["writeConcern"]["wtimeout"].get_int32().value;
                REQUIRE(timeout == 5000);
            }

        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Write concern 1 with timeout and journalling true.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: 1 }
                  - WriteCommand: updateOne
                    Filter: { a: 1 }
                    Update: { $set: { a: 5 } }
                  Options:
                    WriteConcern:
                      Level: 1
                      Timeout: 2500 milliseconds
                      Journal: true
          )");
        try {
            genny::ActorHelper ah(
                config, 1, MongoTestFixture::connectionUri().to_string(), test.callback);
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            REQUIRE(test.events.size() > 0);
            for (auto&& event : test.events) {
                REQUIRE(event.command["writeConcern"]);
                auto writeConcernLevel = event.command["writeConcern"]["w"].get_int32().value;
                REQUIRE(writeConcernLevel == 1);
                auto timeout = event.command["writeConcern"]["wtimeout"].get_int32().value;
                REQUIRE(timeout == 2500);
                auto journal = event.command["writeConcern"]["j"].get_bool().value;
                REQUIRE(journal);
            }

        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Write concern 0 with timeout and journalling false.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: 1 }
                  - WriteCommand: updateOne
                    Filter: { a: 1 }
                    Update: { $set: { a: 5 } }
                  Options:
                    Ordered: true
                    WriteConcern:
                      Level: 0
                      Timeout: 3000 milliseconds
                      Journal: false
          )");
        try {
            genny::ActorHelper ah(
                config, 1, MongoTestFixture::connectionUri().to_string(), test.callback);
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            REQUIRE(test.events.size() > 0);
            for (auto&& event : test.events) {
                REQUIRE(event.command["writeConcern"]);
                auto writeConcernLevel = event.command["writeConcern"]["w"].get_int32().value;
                REQUIRE(writeConcernLevel == 0);
                auto timeout = event.command["writeConcern"]["wtimeout"].get_int32().value;
                REQUIRE(timeout == 3000);
                auto journal = event.command["writeConcern"]["j"].get_bool().value;
                REQUIRE(journal == false);
            }

        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Write concern without 'Level' field should throw.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: 1 }
                  - WriteCommand: updateOne
                    Filter: { a: 1 }
                    Update: { $set: { a: 5 } }
                  Options:
                    WriteConcern:
                      Timeout: 3000 milliseconds
                      Journal: false
          )");
        try {
            REQUIRE_THROWS_AS(
                genny::ActorHelper(config, 1, MongoTestFixture::connectionUri().to_string()),
                YAML::TypedBadConversion<mongocxx::v_noabi::write_concern>);

        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Invalid write concern level should throw.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: bulkWrite
                OperationCommand:
                  WriteOperations:
                  - WriteCommand: insertOne
                    Document: { a: 1 }
                  - WriteCommand: updateOne
                    Filter: { a: 1 }
                    Update: { $set: { a: 5 } }
                  Options:
                    WriteConcern:
                      Level: infinite
          )");
        try {
            REQUIRE_THROWS_AS(
                genny::ActorHelper(config, 1, MongoTestFixture::connectionUri().to_string()),
                YAML::TypedBadConversion<mongocxx::v_noabi::write_concern>);

        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }
}

TEST_CASE_METHOD(MongoTestFixture,
                 "Test read preference options.",
                 "[standalone][single_node_replset][three_node_replset][CrudActor]") {

    dropAllDatabases();
    SessionTest test;
    test.clearEvents();
    auto db = client.database("mydb");

    SECTION("Read preference is 'secondaryPreferred'.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: count
                OperationCommand:
                  Filter: { a : 1 }
                  Options:
                    ReadPreference:
                      ReadMode: secondaryPreferred
          )");
        try {
            genny::ActorHelper ah(
                config, 1, MongoTestFixture::connectionUri().to_string(), test.callback);
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            REQUIRE(test.events.size() > 0);
            for (auto&& event : test.events) {
                REQUIRE(event.command["$readPreference"]);
                REQUIRE(event.command["$readPreference"]["mode"]);
                auto readMode = event.command["$readPreference"]["mode"].get_utf8().value;
                REQUIRE(std::string(readMode) == "secondaryPreferred");
            }
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Read preference is 'nearest' with MaxStaleness set.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: count
                OperationCommand:
                  Filter: { a : 1 }
                  Options:
                    ReadPreference:
                      ReadMode: nearest
                      MaxStaleness: 100 seconds
          )");
        try {
            genny::ActorHelper ah(
                config, 1, MongoTestFixture::connectionUri().to_string(), test.callback);
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            REQUIRE(test.events.size() > 0);
            for (auto&& event : test.events) {
                REQUIRE(event.command["$readPreference"]);
                REQUIRE(event.command["$readPreference"]["mode"]);
                auto readMode = event.command["$readPreference"]["mode"].get_utf8().value;
                REQUIRE(std::string(readMode) == "nearest");
                REQUIRE(event.command["$readPreference"]["maxStalenessSeconds"]);
                auto maxStaleness =
                    event.command["$readPreference"]["maxStalenessSeconds"].get_int64().value;
                REQUIRE(maxStaleness == 100);
            }
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Read preference without 'ReadMode' should throw.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: count
                OperationCommand:
                  Filter: { a : 1 }
                  Options:
                    ReadPreference:
                      MaxStaleness: 100 seconds
          )");
        try {
            REQUIRE_THROWS_AS(
                genny::ActorHelper(config, 1, MongoTestFixture::connectionUri().to_string()),
                YAML::TypedBadConversion<mongocxx::v_noabi::read_preference>);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Read preference with invalid 'ReadMode' should throw.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: count
                OperationCommand:
                  Filter: { a : 1 }
                  Options:
                    ReadPreference:
                      ReadMode: badReadMode
          )");
        try {
            REQUIRE_THROWS_AS(
                genny::ActorHelper(config, 1, MongoTestFixture::connectionUri().to_string()),
                YAML::TypedBadConversion<mongocxx::v_noabi::read_preference>);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }
}

TEST_CASE_METHOD(MongoTestFixture,
                 "Test the 'insertMany' operation.",
                 "[standalone][single_node_replset][three_node_replset][CrudActor]") {

    dropAllDatabases();
    auto db = client.database("mydb");

    YAML::Node config = YAML::Load(R"(
      SchemaVersion: 2018-07-01
      Actors:
      - Name: CrudActor
        Type: CrudActor
        Database: mydb
        ExecutionStrategy:
          ThrowOnFailure: true
        Phases:
        - Repeat: 1
          Collection: test
          Operations:
          - OperationName: insertMany
            OperationCommand:
              Documents:
              - { a: 1 }
              - { a : 1 }
              - { b : 1 }
      )");

    SECTION("The correct documents are inserted.") {
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto count =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 1)));
            REQUIRE(count == 2);
            count = db.collection("test").count(BasicBson::make_document(BasicBson::kvp("b", 1)));
            REQUIRE(count == 1);
            count = db.collection("test").count(BasicBson::make_document());
            REQUIRE(count == 3);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }
}

TEST_CASE_METHOD(MongoTestFixture,
                 "Test 'drop' operation.",
                 "[standalone][single_node_replset][three_node_replset][CrudActor]") {

    SessionTest test;
    dropAllDatabases();
    test.clearEvents();
    auto db = client.database("mydb");

    SECTION("The 'test' collection is dropped.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operation:
                OperationName: drop
          )");
        try {
            db.create_collection("test");
            REQUIRE(db.has_collection("test"));
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            REQUIRE(db.has_collection("test") == false);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("The 'test' collection is dropped with write concern majority.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operation:
                OperationName: drop
                OperationCommand:
                  Options:
                    WriteConcern:
                     Level: majority
          )");
        try {
            db.create_collection("test");
            REQUIRE(db.has_collection("test"));
            genny::ActorHelper ah(
                config, 1, MongoTestFixture::connectionUri().to_string(), test.callback);
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            REQUIRE(db.has_collection("test") == false);
            for (auto&& event : test.events) {
                auto writeConcernLevel = event.command["writeConcern"]["w"].get_utf8().value;
                REQUIRE(std::string(writeConcernLevel) == "majority");
            }
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }
}

TEST_CASE_METHOD(MongoTestFixture,
                 "Test 'count' operation.",
                 "[standalone][single_node_replset][three_node_replset][CrudActor]") {

    SessionTest test;
    dropAllDatabases();
    test.clearEvents();
    auto db = client.database("mydb");

    SECTION("Perform a count on the collection.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operation:
                OperationName: count
                OperationCommand:
                  Filter: { a: 1 }
          )");
        try {
            genny::ActorHelper ah(
                config, 1, MongoTestFixture::connectionUri().to_string(), test.callback);
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            REQUIRE(test.events.size() > 0);
            auto countEvent = test.events[0].command;
            auto collection = countEvent["count"].get_utf8().value;
            REQUIRE(std::string(collection) == "test");
            REQUIRE(countEvent["query"].get_document().view() ==
                    BasicBson::make_document(BasicBson::kvp("a", 1)));
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }
}

TEST_CASE_METHOD(MongoTestFixture,
                 "Test write operations.",
                 "[standalone][single_node_replset][three_node_replset][CrudActor]") {

    dropAllDatabases();
    auto db = client.database("mydb");

    SECTION("Insert a document into a collection.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operation:
                OperationName: insertOne
                OperationCommand:
                  Document: { a: 1 }
          )");
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto count =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 1)));
            REQUIRE(count == 1);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Insert and replace document in a collection.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: insertOne
                OperationCommand:
                  Document: { a: 1 }
              - OperationName: replaceOne
                OperationCommand:
                  Filter: { a : 1 }
                  Replacement: { newfile: test }
          )");
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto countOldDoc =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 1)));
            auto countNew = db.collection("test").count(
                BasicBson::make_document(BasicBson::kvp("newfile", "test")));
            REQUIRE(countOldDoc == 0);
            REQUIRE(countNew == 1);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Insert and update document in a collection.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: insertOne
                OperationCommand:
                  Document: { a: 1 }
              - OperationName: updateOne
                OperationCommand:
                  Filter: { a: 1 }
                  Update: { $set: { a: 10 } }
          )");
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto countOldDoc =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 1)));
            auto countUpdated =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 10)));
            REQUIRE(countOldDoc == 0);
            REQUIRE(countUpdated == 1);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Insert and update multiple documents in a collection.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: insertOne
                OperationCommand:
                  Document: { a: {^RandomInt: {min: 5, max: 15} } }
              - OperationName: insertOne
                OperationCommand:
                  Document: { a: {^RandomInt: {min: 5, max: 15} } }
              - OperationName: updateMany
                OperationCommand:
                  Filter: { a: { $gte: 5 } }
                  Update: { $set: { a: 2 } }
          )");
        try {
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            auto countOldDocs = db.collection("test").count(BasicBson::make_document(
                BasicBson::kvp("a", BasicBson::make_document(BasicBson::kvp("$gte", 5)))));
            auto countUpdated =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 2)));
            REQUIRE(countOldDocs == 0);
            REQUIRE(countUpdated == 2);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Delete a document in a collection.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: deleteOne
                OperationCommand:
                  Filter: { a: 1 }
          )");
        try {
            db.collection("test").insert_one(BasicBson::make_document(BasicBson::kvp("a", 1)));
            auto count =
                db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 1)));
            REQUIRE(count == 1);
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            count = db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 1)));
            REQUIRE(count == 0);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }

    SECTION("Delete multiple documents in a collection.") {
        YAML::Node config = YAML::Load(R"(
          SchemaVersion: 2018-07-01
          Actors:
          - Name: CrudActor
            Type: CrudActor
            Database: mydb
            ExecutionStrategy:
              ThrowOnFailure: true
            Phases:
            - Repeat: 1
              Collection: test
              Operations:
              - OperationName: deleteMany
                OperationCommand:
                  Filter: { a: 1 }
          )");
        try {
            db.collection("test").insert_one(BasicBson::make_document(BasicBson::kvp("a", 1)));
            db.collection("test").insert_one(BasicBson::make_document(BasicBson::kvp("a", 1)));
            auto count = db.collection("test").count(BasicBson::make_document());
            REQUIRE(count == 2);
            genny::ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });
            count = db.collection("test").count(BasicBson::make_document(BasicBson::kvp("a", 1)));
            REQUIRE(count == 0);
        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }
}

// TODO: add test for ReadConcern
// TODO: add test for Find
// TODO: add test for start and commit transaction.

}  // namespace

max_stars_repo_name: henrikingo/genny

max_issues_repo_name: henrikingo/genny

max_forks_repo_name: henrikingo/genny


text:
#ifndef SUPERGENIUS_SRC_INJECTOR_APPLICATION_INJECTOR_HPP
#define SUPERGENIUS_SRC_INJECTOR_APPLICATION_INJECTOR_HPP
#include <boost/di.hpp>
#include <boost/di/extension/scopes/shared.hpp>

// added to fix "fatal error C1189: #error:  WinSock.h has already been included " in windows build
// this error is generated in libp2p/injector/host_injector.hpp
#include <boost/asio.hpp>
//#include <libp2p/host/host.hpp>
#include <libp2p/injector/host_injector.hpp>
#include <libp2p/peer/peer_info.hpp>
//end

#include <crypto/bip39/impl/bip39_provider_impl.hpp>
#include <crypto/crypto_store/crypto_store_impl.hpp>
#include <crypto/pbkdf2/impl/pbkdf2_provider_impl.hpp>
#include <crypto/secp256k1/secp256k1_provider_impl.hpp>

#include <outcome/outcome.hpp>
#include "api/service/api_service.hpp"
#include "api/service/author/author_jrpc_processor.hpp"
#include "api/service/author/impl/author_api_impl.hpp"
#include "api/service/chain/chain_jrpc_processor.hpp"
#include "api/service/chain/impl/chain_api_impl.hpp"
#include "api/service/state/impl/state_api_impl.hpp"
#include "api/service/state/state_jrpc_processor.hpp"
#include "api/service/system/impl/system_api_impl.hpp"
#include "api/service/system/system_jrpc_processor.hpp"
#include "api/transport/impl/http/http_listener_impl.hpp"
#include "api/transport/impl/http/http_session.hpp"
#include "api/transport/impl/ws/ws_listener_impl.hpp"
#include "api/transport/impl/ws/ws_session.hpp"
#include "api/transport/rpc_thread_pool.hpp"

#include "application/impl/app_state_manager_impl.hpp"
#include "application/impl/configuration_storage_impl.hpp"
#include "authorship/impl/block_builder_factory_impl.hpp"
#include "authorship/impl/block_builder_impl.hpp"
#include "authorship/impl/proposer_impl.hpp"
#include "blockchain/impl/block_tree_impl.hpp"
#include "blockchain/impl/key_value_block_header_repository.hpp"
#include "blockchain/impl/key_value_block_storage.hpp"
#include "blockchain/impl/storage_util.hpp"
#include "boost/di/extension/injections/extensible_injector.hpp"
#include "clock/impl/basic_waitable_timer.hpp"
#include "clock/impl/clock_impl.hpp"
#include "base/outcome_throw.hpp"
#include "verification/authority/authority_manager.hpp"
#include "verification/authority/authority_update_observer.hpp"
#include "verification/authority/impl/authority_manager_impl.hpp"
#include "verification/production/production_lottery.hpp"
#include "verification/production/common.hpp"
#include "verification/production/impl/production_lottery_impl.hpp"
#include "verification/production/impl/production_synchronizer_impl.hpp"
#include "verification/production/impl/epoch_storage_impl.hpp"
#include "verification/finality/finalization_observer.hpp"
#include "verification/finality/impl/environment_impl.hpp"
#include "verification/finality/impl/finalization_composite.hpp"
#include "verification/finality/impl/vote_crypto_provider_impl.hpp"
#include "verification/finality/structs.hpp"
#include "verification/finality/vote_graph.hpp"
#include "verification/finality/vote_tracker.hpp"
#include "verification/validation/production_block_validator.hpp"
#include "primitives/production_configuration.hpp"
#include "crypto/ed25519/ed25519_provider_impl.hpp"
#include "crypto/hasher/hasher_impl.hpp"
#include "crypto/random_generator/boost_generator.hpp"
#include "crypto/sr25519/sr25519_provider_impl.hpp"
#include "crypto/vrf/vrf_provider_impl.hpp"
#include "extensions/impl/extension_factory_impl.hpp"
#include "network/impl/dummy_sync_protocol_client.hpp"
#include "network/impl/extrinsic_observer_impl.hpp"
#include "network/impl/gossiper_broadcast.hpp"
#include "network/impl/remote_sync_protocol_client.hpp"
#include "network/impl/router_libp2p.hpp"
#include "network/impl/sync_protocol_observer_impl.hpp"
#include "network/sync_protocol_client.hpp"
#include "network/sync_protocol_observer.hpp"
#include "network/types/sync_clients_set.hpp"
#include "runtime/binaryen/module/wasm_module_impl.hpp"
#include "runtime/binaryen/module/wasm_module_factory_impl.hpp"

#include "runtime/binaryen/runtime_api/production_api_impl.hpp"
#include "runtime/binaryen/runtime_api/block_builder_impl.hpp"
#include "runtime/binaryen/runtime_api/core_factory_impl.hpp"
#include "runtime/binaryen/runtime_api/core_impl.hpp"
#include "runtime/binaryen/runtime_api/finality_api_impl.hpp"
#include "runtime/binaryen/runtime_api/metadata_impl.hpp"
#include "runtime/binaryen/runtime_api/offchain_worker_impl.hpp"
#include "runtime/binaryen/runtime_api/parachain_host_impl.hpp"
#include "runtime/binaryen/runtime_api/tagged_transaction_queue_impl.hpp"
#include "runtime/common/storage_wasm_provider.hpp"
#include "runtime/common/trie_storage_provider_impl.hpp"

#include "storage/changes_trie/impl/storage_changes_tracker_impl.hpp"
#include "storage/rocksdb/rocksdb.hpp"
#include "storage/predefined_keys.hpp"
#include "storage/trie/impl/trie_storage_backend_impl.hpp"
#include "storage/trie/impl/trie_storage_impl.hpp"
#include "storage/trie/supergenius_trie/supergenius_node.hpp"
#include "storage/trie/supergenius_trie/supergenius_trie_factory_impl.hpp"
#include "storage/trie/serialization/supergenius_codec.hpp"
#include "storage/trie/serialization/trie_serializer_impl.hpp"
#include "transaction_pool/impl/pool_moderator_impl.hpp"
#include "transaction_pool/impl/transaction_pool_impl.hpp"

namespace sgns::injector {
  enum class InjectorError {
    INDEX_OUT_OF_BOUND = 1,  // index out of bound
  };
}

OUTCOME_HPP_DECLARE_ERROR_2(sgns::injector, InjectorError);

namespace sgns::injector {
  namespace di = boost::di;

  template <typename C>
  auto useConfig(C c) {
    return boost::di::bind<std::decay_t<C>>()./*template */to(
        std::move(c))[boost::di::override];
  }

  template <class T>
  using sptr = std::shared_ptr<T>;

  template <class T>
  using uptr = std::unique_ptr<T>;

  template <typename Injector>
  sptr<network::PeerList> get_boot_nodes(const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<network::PeerList>>(boost::none);
    if (initialized) {
      return initialized.value();
    }
    auto &cfg = injector.template create<application::ConfigurationStorage &>();

    initialized = std::make_shared<network::PeerList>(cfg.getBootNodes());
    return initialized.value();
  }

  template <typename Injector>
  sptr<api::ApiService> get_jrpc_api_service(const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<api::ApiService>>(boost::none);
    if (initialized) {
      return initialized.value();
    }
    using SubscriptionEnginePtr = std::shared_ptr<
        subscription::SubscriptionEngine<base::Buffer,
                                         std::shared_ptr<api::Session>,
                                         base::Buffer,
                                         primitives::BlockHash>>;
    auto subscription_engine =
        injector.template create<SubscriptionEnginePtr>();
    auto app_state_manager =
        injector
            .template create<std::shared_ptr<application::AppStateManager>>();
    auto rpc_thread_pool =
        injector.template create<std::shared_ptr<api::RpcThreadPool>>();
    std::vector<std::shared_ptr<api::Listener>> listeners{
        injector.template create<std::shared_ptr<api::HttpListenerImpl>>(),
        injector.template create<std::shared_ptr<api::WsListenerImpl>>(),
    };
    auto server = injector.template create<std::shared_ptr<api::JRpcServer>>();
    std::vector<std::shared_ptr<api::JRpcProcessor>> processors{
        injector
            .template create<std::shared_ptr<api::state::StateJrpcProcessor>>(),
        injector.template create<
            std::shared_ptr<api::author::AuthorJRpcProcessor>>(),
        injector
            .template create<std::shared_ptr<api::chain::ChainJrpcProcessor>>(),
        injector.template create<
            std::shared_ptr<api::system::SystemJrpcProcessor>>()};

    initialized =
        std::make_shared<api::ApiService>(std::move(app_state_manager),
                                          std::move(rpc_thread_pool),
                                          std::move(listeners),
                                          std::move(server),
                                          processors,
                                          std::move(subscription_engine));

    auto state_api = injector.template create<std::shared_ptr<api::StateApi>>();
    state_api->setApiService(initialized.value());
    return initialized.value();
  }

    // jrpc api listener (over HTTP) getter
  template <typename Injector>
  sptr<api::HttpListenerImpl> get_jrpc_api_http_listener(
      const Injector &injector,
      const boost::asio::ip::tcp::endpoint &endpoint) {
    static auto initialized =
        boost::optional<sptr<api::HttpListenerImpl>>(boost::none);
    if (initialized) {
      return initialized.value();
    }

    auto app_state_manager =
        injector.template create<sptr<application::AppStateManager>>();

    auto context = injector.template create<sptr<api::RpcContext>>();

    api::HttpListenerImpl::Configuration listener_config;
    listener_config.endpoint = endpoint;

    auto &&http_session_config =
        injector.template create<api::HttpSession::Configuration>();

    initialized = std::make_shared<api::HttpListenerImpl>(
        app_state_manager, context, listener_config, http_session_config);
    return initialized.value();
  }

  // jrpc api listener (over WebSockets) getter
  template <typename Injector>
  sptr<api::WsListenerImpl> get_jrpc_api_ws_listener(
      const Injector &injector,
      const boost::asio::ip::tcp::endpoint &endpoint) {
    static auto initialized =
        boost::optional<sptr<api::WsListenerImpl>>(boost::none);
    if (initialized) {
      return initialized.value();
    }

    auto app_state_manager =
        injector.template create<sptr<application::AppStateManager>>();

    auto context = injector.template create<sptr<api::RpcContext>>();

    api::WsListenerImpl::Configuration listener_config;
    listener_config.endpoint = endpoint;

    auto &&ws_session_config =
        injector.template create<api::WsSession::Configuration>();

    initialized = std::make_shared<api::WsListenerImpl>(
        app_state_manager, context, listener_config, ws_session_config);
    return initialized.value();
  }

  // block storage getter
  template <typename Injector>
  sptr<blockchain::BlockStorage> get_block_storage(const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<blockchain::BlockStorage>>(boost::none);

    if (initialized) {
      return initialized.value();
    }
    auto &&hasher = injector.template create<sptr<crypto::Hasher>>();

    const auto &db = injector.template create<sptr<storage::BufferStorage>>();

    const auto &trie_storage =
        injector.template create<sptr<storage::trie::TrieStorage>>();

    auto storage = blockchain::KeyValueBlockStorage::create(
        trie_storage->getRootHash(),
        db,
        hasher,
        [&db, &injector](const primitives::Block &genesis_block) {
          // handle genesis initialization, which happens when there is not
          // authorities and last completed round in the storage
          if (! db->get(storage::kAuthoritySetKey)) {
            // insert authorities
            auto finality_api =
                injector.template create<sptr<runtime::FinalityApi>>();
            const auto &weighted_authorities_res = finality_api->authorities(
                primitives::BlockId(primitives::BlockNumber{0}));
            BOOST_ASSERT_MSG(weighted_authorities_res,
                             "finality_api_->authorities failed");
            const auto &weighted_authorities = weighted_authorities_res.value();

            for (const auto authority : weighted_authorities) {
              spdlog::info("Finality authority: {}", authority.id.id.toHex());
            }

            verification::finality::VoterSet voters{0};
            for (const auto &weighted_authority : weighted_authorities) {
              voters.insert(weighted_authority.id.id,
                            weighted_authority.weight);
              spdlog::debug("Added to finality authorities: {}, weight: {}",
                            weighted_authority.id.id.toHex(),
                            weighted_authority.weight);
            }
            BOOST_ASSERT_MSG(voters.size() != 0, "Finality voters are empty");
            auto authorities_put_res =
                db->put(storage::kAuthoritySetKey,
                        base::Buffer(scale::encode(voters).value()));
            if (! authorities_put_res) {
              BOOST_ASSERT_MSG(false, "Could not insert authorities");
              std::exit(1);
            }
          }
        });
    if (storage.has_error()) {
      base::raise(storage.error());
    }
    initialized = storage.value();
    return initialized.value();
  }

  // block tree getter
  template <typename Injector>
  sptr<blockchain::BlockTree> get_block_tree(const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<blockchain::BlockTree>>(boost::none);

    if (initialized) {
      return initialized.value();
    }
    auto header_repo =
        injector.template create<sptr<blockchain::BlockHeaderRepository>>();

    auto &&storage = injector.template create<sptr<blockchain::BlockStorage>>();

    auto last_finalized_block_res = storage->getLastFinalizedBlockHash();

    /*const*/ auto block_id =
        last_finalized_block_res.has_value()
            ? primitives::BlockId{last_finalized_block_res.value()}
            : primitives::BlockId{0};

    auto &&extrinsic_observer =
        injector.template create<sptr<network::ExtrinsicObserver>>();

    auto &&hasher = injector.template create<sptr<crypto::Hasher>>();

    auto &&tree =
        blockchain::BlockTreeImpl::create(std::move(header_repo),
                                          storage,
                                          block_id,
                                          std::move(extrinsic_observer),
                                          std::move(hasher));
    if (!tree) {
      base::raise(tree.error());
    }
    initialized = tree.value();
    return initialized.value();
  }

  template <typename Injector>
  sptr<extensions::ExtensionFactoryImpl> get_extension_factory(
      const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<extensions::ExtensionFactoryImpl>>(boost::none);
    if (initialized) {
      return initialized.value();
    }
    auto tracker =
        injector.template create<sptr<storage::changes_trie::ChangesTracker>>();
    auto sr25519_provider =
        injector.template create<sptr<crypto::SR25519Provider>>();
    auto ed25519_provider =
        injector.template create<sptr<crypto::ED25519Provider>>();
    auto secp256k1_provider =
        injector.template create<sptr<crypto::Secp256k1Provider>>();
    auto hasher = injector.template create<sptr<crypto::Hasher>>();
    auto crypto_store = injector.template create<sptr<crypto::CryptoStore>>();
    auto bip39_provider =
        injector.template create<sptr<crypto::Bip39Provider>>();
    auto core_factory_method =
        [&injector](sptr<runtime::WasmProvider> wasm_provider) {
          auto core_factory =
              injector.template create<sptr<runtime::CoreFactory>>();
          return core_factory->createWithCode(wasm_provider);
        };

    initialized =
        std::make_shared<extensions::ExtensionFactoryImpl>(tracker,
                                                           sr25519_provider,
                                                           ed25519_provider,
                                                           secp256k1_provider,
                                                           hasher,
                                                           crypto_store,
                                                           bip39_provider,
                                                           core_factory_method);
    return initialized.value();
  }

  template <typename Injector>
  sptr<storage::trie::TrieStorageBackendImpl> get_trie_storage_backend(
      const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<storage::trie::TrieStorageBackendImpl>>(
            boost::none);

    if (initialized) {
      return initialized.value();
    }
    auto storage = injector.template create<sptr<storage::BufferStorage>>();
    using blockchain::prefix::TRIE_NODE;
    auto backend = std::make_shared<storage::trie::TrieStorageBackendImpl>(
        storage, base::Buffer{TRIE_NODE});
    initialized = backend;
    return backend;
  }

  template <typename Injector>
  sptr<storage::trie::TrieStorageImpl> get_trie_storage_impl(
      const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<storage::trie::TrieStorageImpl>>(boost::none);

    if (initialized) {
      return initialized.value();
    }
    auto factory =
        injector.template create<sptr<storage::trie::SuperGeniusTrieFactory>>();
    auto codec = injector.template create<sptr<storage::trie::Codec>>();
    auto serializer =
        injector.template create<sptr<storage::trie::TrieSerializer>>();
    auto tracker =
        injector.template create<sptr<storage::changes_trie::ChangesTracker>>();
    auto trie_storage_res = storage::trie::TrieStorageImpl::createEmpty(
        factory, codec, serializer, tracker);
    if (!trie_storage_res) {
      base::raise(trie_storage_res.error());
    }

    sptr<storage::trie::TrieStorageImpl> trie_storage =
        std::move(trie_storage_res.value());
    initialized = trie_storage;
    return trie_storage;
  }

  template <typename Injector>
  sptr<storage::trie::TrieStorage> get_trie_storage(const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<storage::trie::TrieStorage>>(boost::none);
    if (initialized) {
      return initialized.value();
    }
    auto configuration_storage =
        injector.template create<sptr<application::ConfigurationStorage>>();
    const auto &genesis_raw_configs = configuration_storage->getGenesis();

    auto trie_storage =
        injector.template create<sptr<storage::trie::TrieStorageImpl>>();
    auto batch = trie_storage->getPersistentBatch();
    if (! batch) {
      base::raise(batch.error());
    }
    for (const auto &[key, val] : genesis_raw_configs) {
      spdlog::info(
          "Key: {}, Val: {}", key.toHex(), val.toHex().substr(0, 200));
      if (auto res = batch.value()->put(key, val); ! res) {
        base::raise(res.error());
      }
    }
    if (auto res = batch.value()->commit(); ! res) {
      base::raise(res.error());
    }

    initialized = trie_storage;
    return trie_storage;
  }

  // rocks db getter
  template <typename Injector>
  sptr<storage::BufferStorage> get_rocks_db(std::string_view rocksdb_path,
                                            const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<storage::BufferStorage>>(boost::none);
    if (initialized) {
      return initialized.value();
    }
    auto options = rocksdb::Options{};
    options.create_if_missing = true;
    auto db = storage::rocksdb::create(rocksdb_path, options);
    if (!db) {
      base::raise(db.error());
    }
    initialized = db.value();
    return initialized.value();
  };

  // configuration storage getter
  template <typename Injector>
  std::shared_ptr<application::ConfigurationStorage> get_configuration_storage(
      std::string_view genesis_path, const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<application::ConfigurationStorage>>(boost::none);
    if (initialized) {
      return initialized.value();
    }
    auto config_storage_res = application::ConfigurationStorageImpl::create(
        std::string(genesis_path));
    if (config_storage_res.has_error()) {
      base::raise(config_storage_res.error());
    }
    initialized = config_storage_res.value();
    return config_storage_res.value();
  };

  template <typename Injector>
  sptr<network::SyncClientsSet> get_sync_clients_set(const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<network::SyncClientsSet>>(boost::none);
    if (initialized) {
      return initialized.value();
    }
    auto configuration_storage =
        injector.template create<sptr<application::ConfigurationStorage>>();
    auto peer_infos = configuration_storage->getBootNodes().peers;

    auto host = injector.template create<sptr<libp2p::Host>>();
    auto block_tree = injector.template create<sptr<blockchain::BlockTree>>();
    auto block_header_repository =
        injector.template create<sptr<blockchain::BlockHeaderRepository>>();

    auto res = std::make_shared<network::SyncClientsSet>();

    auto &current_peer_info =
        injector.template create<network::OwnPeerInfo &>();
    for (auto &peer_info : peer_infos) {
      spdlog::debug("Added peer with id: {}", peer_info.id.toBase58());
      if (peer_info.id != current_peer_info.id) {
        res->clients.emplace_back(
            std::make_shared<network::RemoteSyncProtocolClient>(
                *host, std::move(peer_info)));
      } else {
        res->clients.emplace_back(
            std::make_shared<network::DummySyncProtocolClient>());
      }
    }
    std::reverse(res->clients.begin(), res->clients.end());
    initialized = res;
    return res;
  }

  template <typename Injector>
  sptr<primitives::ProductionConfiguration> get_production_configuration(
      const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<primitives::ProductionConfiguration>>(boost::none);
    if (initialized) {
      return *initialized;
    }

    auto production_api = injector.template create<sptr<runtime::ProductionApi>>();
    auto configuration_res = production_api->configuration();
    if (! configuration_res) {
      base::raise(configuration_res.error());
    }
    auto config = configuration_res.value();
	//added code for debug mode
	primitives::ProductionDuration duration{ 60000000 };  // changed from 30000000 to 40000000
	config.slot_duration = duration;
	//end
    for (const auto &authority : config.genesis_authorities) {
      spdlog::debug("Production authority: {}", authority.id.id.toHex());
    }
    config.leadership_rate.first *= 3;
    initialized = std::make_shared<primitives::ProductionConfiguration>(config);
    return *initialized;
  };

  template <class Injector>
  sptr<crypto::CryptoStore> get_crypto_store(std::string_view keystore_path,
                                             const Injector &injector) {
    static auto initialized =
        boost::optional<sptr<crypto::CryptoStore>>(boost::none);
    if (initialized) {
      return *initialized;
    }

    auto ed25519_provider =
        injector.template create<sptr<crypto::ED25519Provider>>();
    auto sr25519_provider =
        injector.template create<sptr<crypto::SR25519Provider>>();
    auto secp256k1_provider =
        injector.template create<sptr<crypto::Secp256k1Provider>>();
    auto bip39_provider =
        injector.template create<sptr<crypto::Bip39Provider>>();
    auto random_generator = injector.template create<sptr<crypto::CSPRNG>>();

    auto crypto_store =
        std::make_shared<crypto::CryptoStoreImpl>(std::move(ed25519_provider),
                                                  std::move(sr25519_provider),
                                                  std::move(secp256k1_provider),
                                                  std::move(bip39_provider),
                                                  std::move(random_generator));

    boost::filesystem::path path = std::string(keystore_path);
    if (auto &&res = crypto_store->initialize(path); res) {
      base::raise(res.error());
    }
    initialized = crypto_store;

    return *initialized;
  }

  template <class Injector>
  sptr<verification::finality::FinalizationObserver> get_finalization_observer(
      const Injector &injector) {
    static auto instance = boost::optional<
        std::shared_ptr<verification::finality::FinalizationObserver>>(boost::none);
    if (instance) {
      return *instance;
    }

    instance = std::make_shared<verification::finality::FinalizationComposite>(
        injector.template create<
            std::shared_ptr<authority::AuthorityManagerImpl>>());

    return *instance;
  }

  template <typename... Ts>
  auto makeApplicationInjector(
      const std::string &genesis_path,
      const std::string &rocksdb_path,
      const boost::asio::ip::tcp::endpoint &rpc_http_endpoint,
      const boost::asio::ip::tcp::endpoint &rpc_ws_endpoint,
      Ts &&... args) {
    using namespace boost;  // NOLINT;

    // default values for configurations
    api::RpcThreadPool::Configuration rpc_thread_pool_config{};
    api::HttpSession::Configuration http_config{};
    api::WsSession::Configuration ws_config{};
    transaction_pool::PoolModeratorImpl::Params pool_moderator_config{};
    transaction_pool::TransactionPool::Limits tp_pool_limits{};
    return di::make_injector(
        // bind configs
        injector::useConfig<api::RpcThreadPool::Configuration>(rpc_thread_pool_config),
        injector::useConfig<api::HttpSession::Configuration>(http_config),
        injector::useConfig(ws_config),
        injector::useConfig(pool_moderator_config),
        injector::useConfig(tp_pool_limits),

        // inherit host injector
        libp2p::injector::makeHostInjector<BOOST_DI_CFG>(
            libp2p::injector::useSecurityAdaptors<
                libp2p::security::Secio>()[di::override]),

        // bind boot nodes
        di::bind<network::PeerList>.to(
            [](auto const &inj) { return get_boot_nodes(inj); }),
        di::bind<application::AppStateManager>.template to<application::AppStateManagerImpl>(),

        // bind io_context: 1 per injector
        di::bind<::boost::asio::io_context>.in(
            di::extension::shared)[boost::di::override],

        // bind interfaces
        di::bind<api::HttpListenerImpl>.to(
            [rpc_http_endpoint](const auto &injector) {
              return get_jrpc_api_http_listener(injector, rpc_http_endpoint);
            }),
        di::bind<api::WsListenerImpl>.to(
            [rpc_ws_endpoint](const auto &injector) {
              return get_jrpc_api_ws_listener(injector, rpc_ws_endpoint);
            }),
        di::bind<api::AuthorApi>.template to<api::AuthorApiImpl>(),
        di::bind<api::ChainApi>.template to<api::ChainApiImpl>(),
        di::bind<api::StateApi>.template to<api::StateApiImpl>(),
        di::bind<api::SystemApi>.template to<api::SystemApiImpl>(),
        di::bind<api::ApiService>.to([](const auto &injector) {
          return get_jrpc_api_service(injector);
        }),
        di::bind<api::JRpcServer>.template to<api::JRpcServerImpl>(),
        di::bind<authorship::Proposer>.template to<authorship::ProposerImpl>(),
        di::bind<authorship::BlockBuilder>.template to<authorship::BlockBuilderImpl>(),
        di::bind<authorship::BlockBuilderFactory>.template to<authorship::BlockBuilderFactoryImpl>(),
        di::bind<storage::BufferStorage>.to(
            [rocksdb_path](const auto &injector) {
              return get_rocks_db(rocksdb_path, injector);
            }),
        di::bind<blockchain::BlockStorage>.to(
            [](const auto &injector) { return get_block_storage(injector); }),
        di::bind<blockchain::BlockTree>.to(
            [](auto const &inj) { return get_block_tree(inj); }),
        di::bind<blockchain::BlockHeaderRepository>.template to<blockchain::KeyValueBlockHeaderRepository>(),
        di::bind<clock::SystemClock>.template to<clock::SystemClockImpl>(),
        di::bind<clock::SteadyClock>.template to<clock::SteadyClockImpl>(),
        di::bind<clock::Timer>.template to<clock::BasicWaitableTimer>(),
        di::bind<primitives::ProductionConfiguration>.to([](auto const &injector) {
          return get_production_configuration(injector);
        }),
        di::bind<verification::ProductionSynchronizer>.template to<verification::ProductionSynchronizerImpl>(),
        di::bind<verification::finality::Environment>.template to<verification::finality::EnvironmentImpl>(),
        di::bind<verification::finality::VoteCryptoProvider>.template to<verification::finality::VoteCryptoProviderImpl>(),
        di::bind<verification::EpochStorage>.template to<verification::EpochStorageImpl>(),
        di::bind<verification::BlockValidator>.template to<verification::ProductionBlockValidator>(),
        di::bind<crypto::ED25519Provider>.template to<crypto::ED25519ProviderImpl>(),
        di::bind<crypto::Hasher>.template to<crypto::HasherImpl>(),
        di::bind<crypto::SR25519Provider>.template to<crypto::SR25519ProviderImpl>(),
        di::bind<crypto::VRFProvider>.template to<crypto::VRFProviderImpl>(),
        di::bind<crypto::Bip39Provider>.template to<crypto::Bip39ProviderImpl>(),
        di::bind<crypto::Pbkdf2Provider>.template to<crypto::Pbkdf2ProviderImpl>(),
        di::bind<crypto::Secp256k1Provider>.template to<crypto::Secp256k1ProviderImpl>(),

        di::bind<crypto::CryptoStore>.template to<crypto::CryptoStoreImpl>(),
        di::bind<extensions::ExtensionFactory>./*template */to(
            [](auto const &injector) {
              return get_extension_factory(injector);
            }),
        di::bind<network::Router>.template to<network::RouterLibp2p>(),
        di::bind<verification::ProductionGossiper>.template to<network::GossiperBroadcast>(),
        di::bind<verification::finality::Gossiper>.template to<network::GossiperBroadcast>(),
        di::bind<network::Gossiper>.template to<network::GossiperBroadcast>(),
        di::bind<network::SyncClientsSet>.to([](auto const &injector) {
          return get_sync_clients_set(injector);
        }),
        di::bind<network::SyncProtocolObserver>.template to<network::SyncProtocolObserverImpl>(),
        di::bind<runtime::binaryen::WasmModule>.template to<runtime::binaryen::WasmModuleImpl>(),
        di::bind<runtime::binaryen::WasmModuleFactory>.template to<runtime::binaryen::WasmModuleFactoryImpl>(),
        di::bind<runtime::CoreFactory>.template to<runtime::binaryen::CoreFactoryImpl>(),
        di::bind<runtime::TaggedTransactionQueue>.template to<runtime::binaryen::TaggedTransactionQueueImpl>(),
        di::bind<runtime::ParachainHost>.template to<runtime::binaryen::ParachainHostImpl>(),
        di::bind<runtime::OffchainWorker>.template to<runtime::binaryen::OffchainWorkerImpl>(),

        di::bind<runtime::Metadata>.template to<runtime::binaryen::MetadataImpl>(),
        di::bind<runtime::FinalityApi>.template to<runtime::binaryen::FinalityApiImpl>(),
        di::bind<runtime::Core>.template to<runtime::binaryen::CoreImpl>(),
        di::bind<runtime::ProductionApi>.template to<runtime::binaryen::ProductionApiImpl>(),
        di::bind<runtime::BlockBuilder>.template to<runtime::binaryen::BlockBuilderImpl>(),
        di::bind<runtime::TrieStorageProvider>.template to<runtime::TrieStorageProviderImpl>(),
        di::bind<transaction_pool::TransactionPool>.template to<transaction_pool::TransactionPoolImpl>(),
        di::bind<transaction_pool::PoolModerator>.template to<transaction_pool::PoolModeratorImpl>(),
        di::bind<storage::changes_trie::ChangesTracker>.template to<storage::changes_trie::StorageChangesTrackerImpl>(),
        di::bind<storage::trie::TrieStorageBackend>.to(
            [](auto const &inj) { return get_trie_storage_backend(inj); }),
        di::bind<storage::trie::TrieStorageImpl>.to(
            [](auto const &inj) { return get_trie_storage_impl(inj); }),
        di::bind<storage::trie::TrieStorage>.to(
            [](auto const &inj) { return get_trie_storage(inj); }),
        di::bind<storage::trie::SuperGeniusTrieFactory>.template to<storage::trie::SuperGeniusTrieFactoryImpl>(),
        di::bind<storage::trie::Codec>.template to<storage::trie::SuperGeniusCodec>(),
        di::bind<storage::trie::TrieSerializer>.template to<storage::trie::TrieSerializerImpl>(),
        di::bind<runtime::WasmProvider>.template to<runtime::StorageWasmProvider>(),
        di::bind<application::ConfigurationStorage>.to(
            [genesis_path](const auto &injector) {
              return get_configuration_storage(genesis_path, injector);
            }),
        di::bind<network::ExtrinsicObserver>.template to<network::ExtrinsicObserverImpl>(),
        di::bind<network::ExtrinsicGossiper>.template to<network::GossiperBroadcast>(),
        di::bind<authority::AuthorityUpdateObserver>.template to<authority::AuthorityManagerImpl>(),
        di::bind<authority::AuthorityManager>.template to<authority::AuthorityManagerImpl>(),
        di::bind<verification::finality::FinalizationObserver>.to(
            [](auto const &inj) { return get_finalization_observer(inj); }),

        // user-defined overrides...
        std::forward<decltype(args)>(args)...);
  }

}  // namespace sgns::injector

#endif  // SUPERGENIUS_SRC_INJECTOR_APPLICATION_INJECTOR_HPP

max_stars_repo_name: GeniusVentures/SuperGenius

max_issues_repo_name: GeniusVentures/SuperGenius

max_forks_repo_name: GeniusVentures/SuperGenius