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

#include "logger.h"

#include <gtest/gtest.h>
#include <memcached/engine.h>
#include <memcached/extension.h>
#include <platform/cbassert.h>
#include <platform/dirutils.h>
#include <platform/memorymap.h>
#include <valgrind/valgrind.h>

static EXTENSION_LOGGER_DESCRIPTOR* logger;

class SpdloggerTest : public ::testing::Test {
protected:
/*
 * Unset a few environment variables which affect how the logger works.
 * unsetenv() is not supported on Windows.
 */
#ifndef WIN32
    static void SetUpTestCase() {
        unsetenv("CB_MINIMIZE_LOGGER_SLEEPTIME");
        unsetenv("CB_MAXIMIZE_LOGGER_CYCLE_SIZE");
        unsetenv("CB_MAXIMIZE_LOGGER_BUFFER_SIZE");
    }
#endif

    void SetUp() override {
        RemoveFiles();

        cb::logger::Config config;
        config.filename = filename;
        config.cyclesize = 2048;
        config.buffersize = 8192;
        config.sleeptime = 1;
        config.unit_test = true;
        config.console = false;

        const auto ret = cb::logger::initialize(config);
        EXPECT_FALSE(ret) << ret.get();
        logger = &cb::logger::getLoggerDescriptor();
        cb::logger::get()->set_level(spdlog::level::level_enum::debug);
    }

    void RemoveFiles() {
        files = cb::io::findFilesWithPrefix(filename);
        for (const auto file : files) {
            cb::io::rmrf(file);
        }
    }

    void TearDown() override {
        cb::logger::shutdown();
        RemoveFiles();
    }

    std::vector<std::string> files;
    const std::string filename{"spdlogger_test"};
    const std::string openingHook = "---------- Opening logfile: ";
    const std::string closingHook = "---------- Closing logfile";
};

/**
 * Helper function - counts how many times a string appears in a file.
 *
 * @param file the name of the file
 * @param msg the message to searc hfor
 * @return the number of times we found the message in the file
 */
int countInFile(const std::string& file, const std::string& msg) {
    cb::MemoryMappedFile map(file.c_str(), cb::MemoryMappedFile::Mode::RDONLY);
    map.open();

    const auto* begin = reinterpret_cast<const char*>(map.getRoot());
    const auto* end = begin + map.getSize();

    int count = 0;
    while ((begin = std::search(begin, end, msg.begin(), msg.end())) != end) {
        ++count;
        begin += msg.size();
    }
    return count;
}

/**
 * Test that the printf-style of the logger still works
 */
TEST_F(SpdloggerTest, OldStylePrintf) {
    auto& old = cb::logger::getLoggerDescriptor();
    const uint32_t value = 0xdeadbeef;
    old.log(EXTENSION_LOG_INFO, nullptr, "OldStylePrintf %x", value);
    cb::logger::shutdown();
    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size()) << "We should only have a single logfile";
    EXPECT_EQ(1, countInFile(files.front(), "INFO OldStylePrintf deadbeef"));
}

/**
 * Test that the new fmt-style formatting works
 */
TEST_F(SpdloggerTest, FmtStyleFormatting) {
    const uint32_t value = 0xdeadbeef;
    LOG_INFO("FmtStyleFormatting {:x}", value);
    cb::logger::shutdown();
    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size()) << "We should only have a single logfile";
    EXPECT_EQ(1,
              countInFile(files.front(), "INFO FmtStyleFormatting deadbeef"));
}

/**
 * Tests writing the maximum allowed message to file. Messages are held in
 * a buffer of size 2048, which allows for a message of size 2047 characters
 * (excluding logger formatting and null terminator).
 */
TEST_F(SpdloggerTest, LargeMessageTest) {
    std::string message(2047, 'x'); // max message size is 2047 + 1 for '\0'
    logger->log(EXTENSION_LOG_DEBUG, nullptr, message.c_str());
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);

    auto found = false;
    for (auto& file : files) {
        auto messageCount = countInFile(file, message);
        if (messageCount == 1) {
            found = true;
            break;
        }
    }
    EXPECT_TRUE(found);
}

/**
 * Tests the message cropping feature.
 * Crops a message which wouldn't fit in the message buffer.
 */
TEST_F(SpdloggerTest, LargeMessageWithCroppingTest) {
    std::string message(2048, 'x'); // just 1 over max message size
    std::string cropped(2047 - strlen(" [cut]"), 'x');
    cropped.append(" [cut]");

    logger->log(EXTENSION_LOG_DEBUG, nullptr, message.c_str());
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix("spdlogger_test");

    auto found = false;
    for (auto& file : files) {
        auto messageCount = countInFile(file, cropped);
        if (messageCount == 1) {
            found = true;
            break;
        }
    }

    EXPECT_TRUE(found);
}

/**
 * Most basic test. Open a logfile, write a log message, close the logfile and
 * check if the hooks appear in the file.
 */
TEST_F(SpdloggerTest, BasicHooksTest) {
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size());

    auto openingHookCount = countInFile(files.front(), openingHook);
    auto closingHookCount = countInFile(files.front(), closingHook);

    EXPECT_EQ(1, openingHookCount);
    EXPECT_EQ(1, closingHookCount);
}

/**
 * Log multiple messages, which will causes the files to rotate a few times.
 * Test if the hooks appear in each file.
 */
TEST_F(SpdloggerTest, MultipleFilesTest) {
    const std::string message{
            "This is a textual log message that we want to repeat a number of "
            "times: %u"};
    for (auto ii = 0; ii < 100; ii++) {
        logger->log(EXTENSION_LOG_DEBUG, nullptr, message.c_str(), ii);
    }
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_LT(1, files.size());
    for (auto file : files) {
        auto openingHookCount = countInFile(file, openingHook);
        auto closingHookCount = countInFile(file, closingHook);
        EXPECT_EQ(1, openingHookCount) << "Missing open hook in file: " << file;
        EXPECT_EQ(1, closingHookCount) << "Missing closing hook in file: "
                                       << file;
    }
}

#ifndef WIN32
/**
 * Test that it works as expected when running out of file
 * descriptors. This test won't run on Windows as they don't
 * have the same ulimit setting
 */
TEST_F(SpdloggerTest, HandleOpenFileErrors) {
    if (RUNNING_ON_VALGRIND) {
        return;
    }

    logger->log(EXTENSION_LOG_DEBUG, nullptr, "Hey, this is a test");
    cb::logger::flush();
    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size());

    // Bring down out open file limit to a more conservative level (to
    // save using up a huge number of user / system FDs (and speed up the test).
    rlimit rlim;
    ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim))
            << "Failed to get RLIMIT_NOFILE: " << strerror(errno);

    const auto current = rlim.rlim_cur;
    rlim.rlim_cur = 100;
    ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlim))
            << "Failed to set RLIMIT_NOFILE: " << strerror(errno);

    // Eat up file descriptors
    std::vector<FILE*> fds;
    FILE* fp;
    while ((fp = fopen(files.front().c_str(), "r")) != nullptr) {
        fds.push_back(fp);
    }
    EXPECT_EQ(EMFILE, errno);

    // Keep on logging. This should cause the files to wrap
    const std::string message{
            "This is a textual log message that we want to repeat a number of "
            "times %u"};
    for (auto ii = 0; ii < 100; ii++) {
        logger->log(EXTENSION_LOG_DEBUG, nullptr, message.c_str(), ii);
    }

    logger->log(EXTENSION_LOG_DEBUG, nullptr, "HandleOpenFileErrors");
    cb::logger::flush();

    // We've just flushed the data to the file, so it should be possible
    // to find it in the file.
    char buffer[1024];
    bool found = false;
    while (fgets(buffer, sizeof(buffer), fds.front()) != nullptr) {
        if (strstr(buffer, "HandleOpenFileErrors") != nullptr) {
            found = true;
        }
    }

    EXPECT_TRUE(found) << files.front()
                       << " does not contain HandleOpenFileErrors";

    // close all of the file descriptors
    for (const auto& fp : fds) {
        fclose(fp);
    }
    fds.clear();

    // Verify that we didn't get a new file while we didn't have any
    // free file descriptors
    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size());

    // Add a log entry, and we should get a new file
    logger->log(EXTENSION_LOG_DEBUG, nullptr, "Logging to the next file");
    cb::logger::flush();

    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(2, files.size());

    // Restore the filedescriptors
    rlim.rlim_cur = current;
    ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlim))
            << "Failed to restore RLIMIT_NOFILE: " << strerror(errno);
}
#endif

class DedupeSinkTest : public SpdloggerTest {};

/*
 * Tests the functionality of the dedupe_sink by sending it the same message
 * 100 times. Once this is done, the log file should contain the string
 * "Message repeated 100 times".
 */
TEST_F(DedupeSinkTest, BasicTest) {
    std::string message("This message will be repeated 100 times!");
    std::string dedupeMessage("Message repeated 100 times");

    for (auto i = 0; i < 100; i++) {
        logger->log(EXTENSION_LOG_WARNING, nullptr, message.c_str());
    }
    cb::logger::flush();

    files = cb::io::findFilesWithPrefix(filename);
    auto found = false;
    for (auto& file : files) {
        auto logMessageCount = countInFile(file, message);
        auto dedupeMessageCount = countInFile(file, dedupeMessage);
        if (logMessageCount == 1 && dedupeMessageCount == 1) {
            found = true;
            break;
        }
    }
    EXPECT_EQ(true, found);
}

/* No dedupe message should be printed if the message appeared only once */
TEST_F(DedupeSinkTest, MessageLoggedOnceTest) {
    std::string message("This message will be logged just once!");
    std::string dedupeMessage("Message repeated");

    logger->log(EXTENSION_LOG_WARNING, nullptr, message.c_str());
    cb::logger::flush();

    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size());
    auto logMessageCount = countInFile(files.front(), message);
    auto dedupeMessageCount = countInFile(files.front(), dedupeMessage);

    EXPECT_EQ(1, logMessageCount);
    EXPECT_EQ(0, dedupeMessageCount);
}

/* The dedupe message should trigger if the message appeared twice */
TEST_F(DedupeSinkTest, MessageLoggedTwiceTest) {
    std::string message("This message will be repeated twice!");
    std::string dedupeMessage("Message repeated 2 times");

    logger->log(EXTENSION_LOG_WARNING, nullptr, message.c_str());
    logger->log(EXTENSION_LOG_WARNING, nullptr, message.c_str());
    cb::logger::flush();

    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size());
    auto logMessageCount = countInFile(files.front(), message);
    auto dedupeMessageCount = countInFile(files.front(), dedupeMessage);

    EXPECT_EQ(1, logMessageCount);
    EXPECT_EQ(1, dedupeMessageCount);
}

/* The dedupe message should not trigger if flushed in between */
TEST_F(DedupeSinkTest, MessageLoggedTwiceWithFlushTest) {
    std::string message("This message will be written and flushed!");
    std::string dedupeMessage("Message repeated");

    for (auto i = 0; i < 10; i++) {
        logger->log(EXTENSION_LOG_WARNING, nullptr, message.c_str());
        cb::logger::flush();
    }

    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size());
    auto logMessageCount = countInFile(files.front(), message);
    auto dedupeMessageCount = countInFile(files.front(), dedupeMessage);

    EXPECT_EQ(10, logMessageCount);
    EXPECT_EQ(0, dedupeMessageCount);
}
<commit_msg>MB-27882: Tighten up logger tests<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "logger.h"

#include <gtest/gtest.h>
#include <memcached/engine.h>
#include <memcached/extension.h>
#include <platform/cbassert.h>
#include <platform/dirutils.h>
#include <platform/memorymap.h>
#include <valgrind/valgrind.h>

class SpdloggerTest : public ::testing::Test {
protected:
/*
 * Unset a few environment variables which affect how the logger works.
 * unsetenv() is not supported on Windows.
 */
#ifndef WIN32
    static void SetUpTestCase() {
        unsetenv("CB_MINIMIZE_LOGGER_SLEEPTIME");
        unsetenv("CB_MAXIMIZE_LOGGER_CYCLE_SIZE");
        unsetenv("CB_MAXIMIZE_LOGGER_BUFFER_SIZE");
    }
#endif

    void SetUp() override {
        RemoveFiles();

        cb::logger::Config config;
        config.filename = filename;
        config.cyclesize = 2048;
        config.buffersize = 8192;
        // sleeptime can't be set too low as then the deduplication
        // logic may not work as it flush too early...
        config.sleeptime = 10000;
        config.unit_test = true;
        config.console = false;

        const auto ret = cb::logger::initialize(config);
        EXPECT_FALSE(ret) << ret.get();
        cb::logger::get()->set_level(spdlog::level::level_enum::debug);
    }

    void RemoveFiles() {
        files = cb::io::findFilesWithPrefix(filename);
        for (const auto& file : files) {
            cb::io::rmrf(file);
        }
    }

    void TearDown() override {
        cb::logger::shutdown();
        RemoveFiles();
    }

    std::vector<std::string> files;
    const std::string filename{"spdlogger_test"};
    const std::string openingHook = "---------- Opening logfile: ";
    const std::string closingHook = "---------- Closing logfile";
};

/**
 * Helper function - counts how many times a string appears in a file.
 *
 * @param file the name of the file
 * @param msg the message to searc hfor
 * @return the number of times we found the message in the file
 */
int countInFile(const std::string& file, const std::string& msg) {
    cb::MemoryMappedFile map(file.c_str(), cb::MemoryMappedFile::Mode::RDONLY);
    map.open();

    const auto* begin = reinterpret_cast<const char*>(map.getRoot());
    const auto* end = begin + map.getSize();

    int count = 0;
    while ((begin = std::search(begin, end, msg.begin(), msg.end())) != end) {
        ++count;
        begin += msg.size();
    }
    return count;
}

/**
 * Test that the printf-style of the logger still works
 */
TEST_F(SpdloggerTest, OldStylePrintf) {
    auto& logger = cb::logger::getLoggerDescriptor();
    const uint32_t value = 0xdeadbeef;
    logger.log(EXTENSION_LOG_INFO, nullptr, "OldStylePrintf %x", value);
    cb::logger::shutdown();
    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size()) << "We should only have a single logfile";
    EXPECT_EQ(1, countInFile(files.front(), "INFO OldStylePrintf deadbeef"));
}

/**
 * Test that the new fmt-style formatting works
 */
TEST_F(SpdloggerTest, FmtStyleFormatting) {
    const uint32_t value = 0xdeadbeef;
    LOG_INFO("FmtStyleFormatting {:x}", value);
    cb::logger::shutdown();
    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size()) << "We should only have a single logfile";
    EXPECT_EQ(1,
              countInFile(files.front(), "INFO FmtStyleFormatting deadbeef"));
}

/**
 * Tests writing the maximum allowed message to file. Messages are held in
 * a buffer of size 2048, which allows for a message of size 2047 characters
 * (excluding logger formatting and null terminator).
 *
 * (old printf style)
 */
TEST_F(SpdloggerTest, LargeMessageTest) {
    const std::string message(2047,
                              'x'); // max message size is 2047 + 1 for '\0'
    auto& logger = cb::logger::getLoggerDescriptor();
    logger.log(EXTENSION_LOG_DEBUG, nullptr, message.c_str());
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);

    auto found = false;
    for (auto& file : files) {
        auto messageCount = countInFile(file, message);
        if (messageCount == 1) {
            found = true;
            break;
        }
    }
    EXPECT_TRUE(found) << "Failed to locate the long message in any of the "
                       << files.size() << " logfiles";
}

/**
 * Tests the message cropping feature.
 * Crops a message which wouldn't fit in the message buffer.
 *
 * (old printf style)
 */
TEST_F(SpdloggerTest, LargeMessageWithCroppingTest) {
    const std::string message(2048, 'x'); // just 1 over max message size
    std::string cropped(2047 - strlen(" [cut]"), 'x');
    cropped.append(" [cut]");

    auto& logger = cb::logger::getLoggerDescriptor();
    logger.log(EXTENSION_LOG_DEBUG, nullptr, message.c_str());
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);

    auto found = false;
    for (auto& file : files) {
        auto messageCount = countInFile(file, cropped);
        if (messageCount == 1) {
            found = true;
            break;
        }
    }

    EXPECT_TRUE(found) << "Failed to locate the cropped text in any of the "
                       << files.size() << " logfiles";
}

/**
 * Most basic test. Open a logfile, write a log message, close the logfile and
 * check if the hooks appear in the file.
 */
TEST_F(SpdloggerTest, BasicHooksTest) {
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);
    ASSERT_EQ(1, files.size());
    EXPECT_EQ(1, countInFile(files.front(), openingHook));
    EXPECT_EQ(1, countInFile(files.front(), closingHook));
}

/**
 * Log multiple messages, which will causes the files to rotate a few times.
 * Test if the hooks appear in each file.
 */
TEST_F(SpdloggerTest, MultipleFilesTest) {
    const char* message =
            "This is a textual log message that we want to repeat a number of "
            "times: {}";
    for (auto ii = 0; ii < 100; ii++) {
        LOG_DEBUG(message, ii);
    }
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_LT(1, files.size());
    for (auto& file : files) {
        EXPECT_EQ(1, countInFile(file, openingHook))
                << "Missing open hook in file: " << file;
        EXPECT_EQ(1, countInFile(file, closingHook))
                << "Missing closing hook in file: " << file;
    }
}

#ifndef WIN32
/**
 * Test that it works as expected when running out of file
 * descriptors. This test won't run on Windows as they don't
 * have the same ulimit setting
 */
TEST_F(SpdloggerTest, HandleOpenFileErrors) {
    if (RUNNING_ON_VALGRIND) {
        std::cerr << "Skipping test when running on valgrind" << std::endl;
        return;
    }

    LOG_DEBUG("Hey, this is a test");
    cb::logger::flush();
    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size());

    // Bring down out open file limit to a more conservative level (to
    // save using up a huge number of user / system FDs (and speed up the test).
    rlimit rlim;
    ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim))
            << "Failed to get RLIMIT_NOFILE: " << strerror(errno);

    const auto current = rlim.rlim_cur;
    rlim.rlim_cur = 100;
    ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlim))
            << "Failed to set RLIMIT_NOFILE: " << strerror(errno);

    // Eat up file descriptors
    std::vector<FILE*> fds;
    FILE* fp;
    while ((fp = fopen(files.front().c_str(), "r")) != nullptr) {
        fds.push_back(fp);
    }
    EXPECT_EQ(EMFILE, errno);

    // Keep on logging. This should cause the files to wrap
    const char* message =
            "This is a textual log message that we want to repeat a number of "
            "times {}";
    for (auto ii = 0; ii < 100; ii++) {
        LOG_DEBUG(message, ii);
    }

    LOG_DEBUG("HandleOpenFileErrors");
    cb::logger::flush();

    // We've just flushed the data to the file, so it should be possible
    // to find it in the file.
    char buffer[1024];
    bool found = false;
    while (fgets(buffer, sizeof(buffer), fds.front()) != nullptr) {
        if (strstr(buffer, "HandleOpenFileErrors") != nullptr) {
            found = true;
        }
    }

    EXPECT_TRUE(found) << files.front()
                       << " does not contain HandleOpenFileErrors";

    // close all of the file descriptors
    for (const auto& fp : fds) {
        fclose(fp);
    }
    fds.clear();

    // Verify that we didn't get a new file while we didn't have any
    // free file descriptors
    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(1, files.size());

    // Add a log entry, and we should get a new file
    LOG_DEBUG("Logging to the next file");
    cb::logger::flush();

    files = cb::io::findFilesWithPrefix(filename);
    EXPECT_EQ(2, files.size());

    // Restore the filedescriptors
    rlim.rlim_cur = current;
    ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlim))
            << "Failed to restore RLIMIT_NOFILE: " << strerror(errno);
}
#endif

class DedupeSinkTest : public SpdloggerTest {};

/**
 * Tests the functionality of the dedupe_sink by sending it the same message
 * 100 times. Once this is done, the log file should contain the string
 * "Message repeated 100 times".
 */
TEST_F(DedupeSinkTest, BasicTest) {
    const std::string message{"This message will be repeated 100 times!"};
    const std::string dedupeMessage{"Message repeated 100 times"};

    for (auto ii = 0; ii < 100; ii++) {
        LOG_WARNING(message);
    }
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);
    ASSERT_EQ(1, files.size()) << "Did not expect log rotation to happen";
    EXPECT_EQ(1, countInFile(files.front(), message));
    EXPECT_EQ(1, countInFile(files.front(), dedupeMessage));
}

/**
 * No dedupe message should be printed if the message appeared only once
 */
TEST_F(DedupeSinkTest, MessageLoggedOnceTest) {
    const std::string message{"This message will be logged just once!"};
    const std::string dedupeMessage{"Message repeated"};

    LOG_WARNING(message);
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);
    ASSERT_EQ(1, files.size()) << "Did not expect log rotation to happen";
    EXPECT_EQ(1, countInFile(files.front(), message));
    EXPECT_EQ(0, countInFile(files.front(), dedupeMessage));
}

/**
 * The dedupe message should trigger if the message appeared twice
 */
TEST_F(DedupeSinkTest, MessageLoggedTwiceTest) {
    const std::string message{"This message will be repeated twice!"};
    const std::string dedupeMessage{"Message repeated 2 times"};

    LOG_WARNING(message);
    LOG_WARNING(message);
    cb::logger::shutdown();

    files = cb::io::findFilesWithPrefix(filename);
    ASSERT_EQ(1, files.size()) << "Did not expect log rotation to happen";
    EXPECT_EQ(1, countInFile(files.front(), message));
    EXPECT_EQ(1, countInFile(files.front(), dedupeMessage));
}

/**
 * Flushing the buffer should "reset" the deduplication logic as we don't
 * want the log to look like:
 *
 *     message x repeated 10 times
 *     message x repeated 11 times
 *     message x repeated 15 times
 *
 * It makes it harder to read the logs.. Does it mean that it happened
 * 1 time or 11 times between the first two lines etc.
 */
TEST_F(DedupeSinkTest, MessageLoggedTwiceWithFlushTest) {
    const std::string message{"This message will be written and flushed!"};
    const std::string dedupeMessage{"Message repeated"};

    for (auto i = 0; i < 10; i++) {
        LOG_WARNING(message);
        cb::logger::flush();
    }

    files = cb::io::findFilesWithPrefix(filename);
    ASSERT_EQ(1, files.size()) << "Did not expect log rotation to happen";
    EXPECT_EQ(10, countInFile(files.front(), message));
    EXPECT_EQ(0, countInFile(files.front(), dedupeMessage));
}
<|endoftext|>


<commit_before>#include <stdexcept>
#include <fstream>
#include <xorg/gtest/xorg-gtest.h>

#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>

/**
 * A test fixture for testing some input drivers
 *
 */
class InputDriverTest : public xorg::testing::Test,
                        public ::testing::EmptyTestEventListener,
                        public ::testing::WithParamInterface<const char*> {
protected:
    void WriteConfig(const char *param) {
        std::stringstream s;
        s << "/tmp/" << param << ".conf";
        config_file = s.str();

        std::ofstream conffile(config_file.c_str());
        conffile.exceptions(std::ofstream::failbit | std::ofstream::badbit);

        std::string driver(param);

        conffile << ""
"            Section \"ServerFlags\"\n"
"                Option \"Log\" \"flush\"\n"
"            EndSection\n"
"\n"
"            Section \"ServerLayout\"\n"
"                Identifier \"Dummy layout\"\n"
"                Screen 0 \"Dummy screen\" 0 0\n"
"                Option \"AutoAddDevices\" \"off\"\n"
"                InputDevice \"--device--\"\n"
"            EndSection\n"
"\n"
"            Section \"Screen\"\n"
"                Identifier \"Dummy screen\"\n"
"                Device \"Dummy video device\"\n"
"            EndSection\n"
"\n"
"            Section \"Device\"\n"
"                Identifier \"Dummy video device\"\n"
"                Driver \"dummy\"\n"
"            EndSection\n";
        server.SetOption("-config", config_file);
    }

    void AddInputSection(const char *param, const char *options = "") {
        std::ofstream conffile(config_file.c_str(), std::ios_base::app);
        conffile.exceptions(std::ofstream::failbit | std::ofstream::badbit);

        std::string driver(param);

        conffile << ""
"            Section \"InputDevice\"\n"
"                Identifier \"--device--\"\n"
"                Driver \"" << driver << "\"\n"
                 << options <<
"            EndSection\n";
        server.SetOption("-config", config_file);
    }

    void StartServer() {
        server.SetOption("-logfile",log_file);
        server.Start();
        server.WaitForConnections();
        xorg::testing::Test::SetDisplayString(server.GetDisplayString());

        ASSERT_NO_FATAL_FAILURE(xorg::testing::Test::SetUp());
    }

    virtual void SetUp()
    {
        failed = false;

        testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
        listeners.Append(this);

        std::stringstream s;
        s << "/tmp/Xorg-" << GetParam() << ".log";
        log_file = s.str();

        WriteConfig(GetParam());
        AddInputSection(GetParam());
        StartServer();
    }

    virtual void TearDown()
    {
        if (server.Pid() != -1)
            if (!server.Terminate())
                server.Kill();

        if (!failed) {
            if (config_file.size())
                unlink(config_file.c_str());

            if (log_file.size())
                unlink(log_file.c_str());
        }

        testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
        listeners.Release(this);
    }

    virtual void OnTestPartResult(const ::testing::TestPartResult &test_part_result) {
        failed = test_part_result.failed();
    }

    std::string config_file;
    std::string log_file;
    xorg::testing::XServer server;
    bool failed;
};

TEST_P(InputDriverTest, DriverDevice)
{
    std::ifstream in_file(log_file.c_str());
    std::string line;
    std::string error_msg("Failed to load module");
    std::string param(GetParam());

    // grep for error message in the log file...
    error_msg +=  " \"" + param + "\"";
    if(in_file.is_open())
    {
        while (getline (in_file, line))
        {
            size_t found = line.find(error_msg);
            Bool error = (found != std::string::npos);
            ASSERT_FALSE (error) << "Module " << param << " failed to load" << std::endl << line <<  std::endl;
        }
    }
}

INSTANTIATE_TEST_CASE_P(, InputDriverTest,
        ::testing::Values("acecad", "aiptek", "elographics",
                          "fpit", "hyperpen",  "mutouch",
                          "penmount", "wacom", "synaptics",
                          "keyboard", "mouse", "vmmouse",
                          "evdev"));

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>AddInputSection can take default arguments (and std::string() at that)<commit_after>#include <stdexcept>
#include <fstream>
#include <xorg/gtest/xorg-gtest.h>

#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>

/**
 * A test fixture for testing some input drivers
 *
 */
class InputDriverTest : public xorg::testing::Test,
                        public ::testing::EmptyTestEventListener,
                        public ::testing::WithParamInterface<const char*> {
protected:
    void WriteConfig(const char *param) {
        std::stringstream s;
        s << "/tmp/" << param << ".conf";
        config_file = s.str();

        std::ofstream conffile(config_file.c_str());
        conffile.exceptions(std::ofstream::failbit | std::ofstream::badbit);

        std::string driver(param);

        conffile << ""
"            Section \"ServerFlags\"\n"
"                Option \"Log\" \"flush\"\n"
"            EndSection\n"
"\n"
"            Section \"ServerLayout\"\n"
"                Identifier \"Dummy layout\"\n"
"                Screen 0 \"Dummy screen\" 0 0\n"
"                Option \"AutoAddDevices\" \"off\"\n"
"                InputDevice \"--device--\"\n"
"            EndSection\n"
"\n"
"            Section \"Screen\"\n"
"                Identifier \"Dummy screen\"\n"
"                Device \"Dummy video device\"\n"
"            EndSection\n"
"\n"
"            Section \"Device\"\n"
"                Identifier \"Dummy video device\"\n"
"                Driver \"dummy\"\n"
"            EndSection\n";
        server.SetOption("-config", config_file);
    }

    void AddInputSection(std::string driver, std::string identifier = "--device--", std::string options = "") {
        std::ofstream conffile(config_file.c_str(), std::ios_base::app);
        conffile.exceptions(std::ofstream::failbit | std::ofstream::badbit);

        conffile << ""
"            Section \"InputDevice\"\n"
"                Identifier \"" << identifier << "\"\n"
"                Driver \"" << driver << "\"\n"
                 << options <<
"            EndSection\n";
        server.SetOption("-config", config_file);
    }

    void StartServer() {
        server.SetOption("-logfile",log_file);
        server.Start();
        server.WaitForConnections();
        xorg::testing::Test::SetDisplayString(server.GetDisplayString());

        ASSERT_NO_FATAL_FAILURE(xorg::testing::Test::SetUp());
    }

    virtual void SetUp()
    {
        failed = false;

        testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
        listeners.Append(this);

        std::stringstream s;
        s << "/tmp/Xorg-" << GetParam() << ".log";
        log_file = s.str();

        WriteConfig(GetParam());
        AddInputSection(GetParam());
        StartServer();
    }

    virtual void TearDown()
    {
        if (server.Pid() != -1)
            if (!server.Terminate())
                server.Kill();

        if (!failed) {
            if (config_file.size())
                unlink(config_file.c_str());

            if (log_file.size())
                unlink(log_file.c_str());
        }

        testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
        listeners.Release(this);
    }

    virtual void OnTestPartResult(const ::testing::TestPartResult &test_part_result) {
        failed = test_part_result.failed();
    }

    std::string config_file;
    std::string log_file;
    xorg::testing::XServer server;
    bool failed;
};

TEST_P(InputDriverTest, DriverDevice)
{
    std::ifstream in_file(log_file.c_str());
    std::string line;
    std::string error_msg("Failed to load module");
    std::string param(GetParam());

    // grep for error message in the log file...
    error_msg +=  " \"" + param + "\"";
    if(in_file.is_open())
    {
        while (getline (in_file, line))
        {
            size_t found = line.find(error_msg);
            Bool error = (found != std::string::npos);
            ASSERT_FALSE (error) << "Module " << param << " failed to load" << std::endl << line <<  std::endl;
        }
    }
}

INSTANTIATE_TEST_CASE_P(, InputDriverTest,
        ::testing::Values("acecad", "aiptek", "elographics",
                          "fpit", "hyperpen",  "mutouch",
                          "penmount", "wacom", "synaptics",
                          "keyboard", "mouse", "vmmouse",
                          "evdev"));

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>// Open the two solution files named on standard input, find all
// variables they have in common, and output the Hilbert norms of the
// differences between them.

#include "libmesh.h"

#include "mesh.h"
#include "equation_systems.h"
#include "exact_solution.h"

unsigned int dim = 2; // This gets overridden by most mesh formats

int main(int argc, char** argv)
{
  LibMeshInit init(argc, argv);

  Mesh mesh1(dim), mesh2(dim);
  EquationSystems es1(mesh1), es2(mesh2);

  std::cout << "Usage: " << argv[0]
            << " coarsemesh coarsesolution finemesh finesolution" << std::endl;

  mesh1.read(argv[1]);
  std::cout << "Loaded coarse mesh " << argv[1] << std::endl;
  es1.read(argv[2], libMeshEnums::READ);
  std::cout << "Loaded coarse solution " << argv[2] << std::endl;
  mesh2.read(argv[3]);
  std::cout << "Loaded fine mesh " << argv[3] << std::endl;
  es2.read(argv[4], libMeshEnums::READ);
  std::cout << "Loaded fine solution " << argv[4] << std::endl;

  ExactSolution exact_sol(es1);
  exact_sol.attach_reference_solution(&es2);

  std::vector<std::string> sysnames;
  sysnames.reserve(es1.n_systems());

  for (unsigned int i = 0; i != es1.n_systems(); ++i)
    if (es2.has_system(es1.get_system(i).name()))
      sysnames.push_back(es1.get_system(i).name());

  for (unsigned int i = 0; i != sysnames.size(); ++i)
    {
      std::string sysname = sysnames[i];
      System &sys1 = es1.get_system(sysname);
      System &sys2 = es2.get_system(sysname);

      for (unsigned int j = 0; j != sys1.n_vars(); ++j)
        {
          std::string varname = sys1.variable_name(j);

          if (!sys2.has_variable(varname))
            continue;

          exact_sol.compute_error(sysname, varname);

          std::cout << "Errors in system " << sysname << ", variable " << varname << ":" << std::endl;
          std::cout << "L2 error: " << exact_sol.l2_error(sysname, varname) << std::endl;
          std::cout << "H1 error: " << exact_sol.h1_error(sysname, varname) << std::endl;
          std::cout << "H2 error: " << exact_sol.h2_error(sysname, varname) << std::endl;
        }
    }

  return 0;
}
<commit_msg>Work with separate libMesh namespace<commit_after>// Open the two solution files named on standard input, find all
// variables they have in common, and output the Hilbert norms of the
// differences between them.

#include "libmesh.h"

#include "mesh.h"
#include "equation_systems.h"
#include "exact_solution.h"

using namespace libMesh;

unsigned int dim = 2; // This gets overridden by most mesh formats

int main(int argc, char** argv)
{
  LibMeshInit init(argc, argv);

  Mesh mesh1(dim), mesh2(dim);
  EquationSystems es1(mesh1), es2(mesh2);

  std::cout << "Usage: " << argv[0]
            << " coarsemesh coarsesolution finemesh finesolution" << std::endl;

  mesh1.read(argv[1]);
  std::cout << "Loaded coarse mesh " << argv[1] << std::endl;
  es1.read(argv[2], libMeshEnums::READ);
  std::cout << "Loaded coarse solution " << argv[2] << std::endl;
  mesh2.read(argv[3]);
  std::cout << "Loaded fine mesh " << argv[3] << std::endl;
  es2.read(argv[4], libMeshEnums::READ);
  std::cout << "Loaded fine solution " << argv[4] << std::endl;

  ExactSolution exact_sol(es1);
  exact_sol.attach_reference_solution(&es2);

  std::vector<std::string> sysnames;
  sysnames.reserve(es1.n_systems());

  for (unsigned int i = 0; i != es1.n_systems(); ++i)
    if (es2.has_system(es1.get_system(i).name()))
      sysnames.push_back(es1.get_system(i).name());

  for (unsigned int i = 0; i != sysnames.size(); ++i)
    {
      std::string sysname = sysnames[i];
      System &sys1 = es1.get_system(sysname);
      System &sys2 = es2.get_system(sysname);

      for (unsigned int j = 0; j != sys1.n_vars(); ++j)
        {
          std::string varname = sys1.variable_name(j);

          if (!sys2.has_variable(varname))
            continue;

          exact_sol.compute_error(sysname, varname);

          std::cout << "Errors in system " << sysname << ", variable " << varname << ":" << std::endl;
          std::cout << "L2 error: " << exact_sol.l2_error(sysname, varname) << std::endl;
          std::cout << "H1 error: " << exact_sol.h1_error(sysname, varname) << std::endl;
          std::cout << "H2 error: " << exact_sol.h2_error(sysname, varname) << std::endl;
        }
    }

  return 0;
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gtest/gtest.h>

#include <process/future.hpp>
#include <process/http.hpp>
#include <process/owned.hpp>
#include <process/pid.hpp>

#include <stout/gtest.hpp>
#include <stout/try.hpp>

#include "master/master.hpp"

#include "tests/mesos.hpp"

using mesos::internal::master::Master;
using mesos::internal::slave::Slave;

using mesos::master::detector::MasterDetector;

using process::Owned;

namespace mesos {
namespace internal {
namespace tests {

class MetricsTest : public mesos::internal::tests::MesosTest {};

TEST_F(MetricsTest, Master)
{
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  // Get the snapshot.
  process::UPID upid("metrics", process::address());

  process::Future<process::http::Response> response =
      process::http::get(upid, "snapshot");

  AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response);
  AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);

  Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
  ASSERT_SOME(parse);

  JSON::Object stats = parse.get();

  EXPECT_EQ(1u, stats.values.count("master/uptime_secs"));

  EXPECT_EQ(1u, stats.values.count("master/elected"));

  EXPECT_EQ(1u, stats.values.count("master/slaves_connected"));
  EXPECT_EQ(1u, stats.values.count("master/slaves_disconnected"));
  EXPECT_EQ(1u, stats.values.count("master/slaves_active"));
  EXPECT_EQ(1u, stats.values.count("master/slaves_inactive"));

  EXPECT_EQ(1u, stats.values.count("master/frameworks_connected"));
  EXPECT_EQ(1u, stats.values.count("master/frameworks_disconnected"));
  EXPECT_EQ(1u, stats.values.count("master/frameworks_active"));
  EXPECT_EQ(1u, stats.values.count("master/frameworks_inactive"));

  EXPECT_EQ(1u, stats.values.count("master/outstanding_offers"));

  EXPECT_EQ(1u, stats.values.count("master/tasks_staging"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_starting"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_running"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_killing"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_finished"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_failed"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_killed"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_lost"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_error"));

  EXPECT_EQ(1u, stats.values.count("master/dropped_messages"));

  // Messages from schedulers.
  EXPECT_EQ(1u, stats.values.count("master/messages_register_framework"));
  EXPECT_EQ(1u, stats.values.count("master/messages_reregister_framework"));
  EXPECT_EQ(1u, stats.values.count("master/messages_unregister_framework"));
  EXPECT_EQ(1u, stats.values.count("master/messages_deactivate_framework"));
  EXPECT_EQ(1u, stats.values.count("master/messages_kill_task"));
  EXPECT_EQ(1u, stats.values.count(
      "master/messages_status_update_acknowledgement"));
  EXPECT_EQ(1u, stats.values.count("master/messages_resource_request"));
  EXPECT_EQ(1u, stats.values.count("master/messages_launch_tasks"));
  EXPECT_EQ(1u, stats.values.count("master/messages_decline_offers"));
  EXPECT_EQ(1u, stats.values.count("master/messages_revive_offers"));
  EXPECT_EQ(1u, stats.values.count("master/messages_suppress_offers"));
  EXPECT_EQ(1u, stats.values.count("master/messages_reconcile_tasks"));
  EXPECT_EQ(1u, stats.values.count("master/messages_framework_to_executor"));

  // Messages from slaves.
  EXPECT_EQ(1u, stats.values.count("master/messages_register_slave"));
  EXPECT_EQ(1u, stats.values.count("master/messages_reregister_slave"));
  EXPECT_EQ(1u, stats.values.count("master/messages_unregister_slave"));
  EXPECT_EQ(1u, stats.values.count("master/messages_status_update"));
  EXPECT_EQ(1u, stats.values.count("master/messages_exited_executor"));

  // Messages from both schedulers and slaves.
  EXPECT_EQ(1u, stats.values.count("master/messages_authenticate"));

  EXPECT_EQ(1u, stats.values.count(
      "master/valid_framework_to_executor_messages"));
  EXPECT_EQ(1u, stats.values.count(
      "master/invalid_framework_to_executor_messages"));

  EXPECT_EQ(1u, stats.values.count("master/valid_status_updates"));
  EXPECT_EQ(1u, stats.values.count("master/invalid_status_updates"));

  EXPECT_EQ(1u, stats.values.count(
      "master/valid_status_update_acknowledgements"));
  EXPECT_EQ(1u, stats.values.count(
      "master/invalid_status_update_acknowledgements"));

  EXPECT_EQ(1u, stats.values.count("master/recovery_slave_removals"));

  EXPECT_EQ(1u, stats.values.count("master/event_queue_messages"));
  EXPECT_EQ(1u, stats.values.count("master/event_queue_dispatches"));
  EXPECT_EQ(1u, stats.values.count("master/event_queue_http_requests"));

  EXPECT_EQ(1u, stats.values.count("master/cpus_total"));
  EXPECT_EQ(1u, stats.values.count("master/cpus_used"));
  EXPECT_EQ(1u, stats.values.count("master/cpus_percent"));

  EXPECT_EQ(1u, stats.values.count("master/mem_total"));
  EXPECT_EQ(1u, stats.values.count("master/mem_used"));
  EXPECT_EQ(1u, stats.values.count("master/mem_percent"));

  EXPECT_EQ(1u, stats.values.count("master/disk_total"));
  EXPECT_EQ(1u, stats.values.count("master/disk_used"));
  EXPECT_EQ(1u, stats.values.count("master/disk_percent"));

  EXPECT_EQ(1u, stats.values.count("registrar/queued_operations"));
  EXPECT_EQ(1u, stats.values.count("registrar/registry_size_bytes"));

  EXPECT_EQ(1u, stats.values.count("registrar/state_fetch_ms"));
  EXPECT_EQ(1u, stats.values.count("registrar/state_store_ms"));
}

TEST_F(MetricsTest, Slave)
{
  // TODO(dhamon): https://issues.apache.org/jira/browse/MESOS-2134 to allow
  // only a Slave to be started.
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  Owned<MasterDetector> detector = master.get()->createDetector();
  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get());
  ASSERT_SOME(slave);

  // Get the snapshot.
  process::UPID upid("metrics", process::address());

  process::Future<process::http::Response> response =
      process::http::get(upid, "snapshot");

  AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response);
  AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);

  Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
  ASSERT_SOME(parse);

  JSON::Object stats = parse.get();

  EXPECT_EQ(1u, stats.values.count("slave/uptime_secs"));
  EXPECT_EQ(1u, stats.values.count("slave/registered"));

  EXPECT_EQ(1u, stats.values.count("slave/recovery_errors"));

  EXPECT_EQ(1u, stats.values.count("slave/frameworks_active"));

  EXPECT_EQ(1u, stats.values.count("slave/tasks_staging"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_starting"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_running"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_killing"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_finished"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_failed"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_killed"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_lost"));

  EXPECT_EQ(1u, stats.values.count("slave/executors_registering"));
  EXPECT_EQ(1u, stats.values.count("slave/executors_running"));
  EXPECT_EQ(1u, stats.values.count("slave/executors_terminating"));
  EXPECT_EQ(1u, stats.values.count("slave/executors_terminated"));

  EXPECT_EQ(1u, stats.values.count("slave/valid_status_updates"));
  EXPECT_EQ(1u, stats.values.count("slave/invalid_status_updates"));

  EXPECT_EQ(1u, stats.values.count("slave/valid_framework_messages"));
  EXPECT_EQ(1u, stats.values.count("slave/invalid_framework_messages"));

  EXPECT_EQ(1u, stats.values.count("slave/container_launch_errors"));

  EXPECT_EQ(1u, stats.values.count("slave/cpus_total"));
  EXPECT_EQ(1u, stats.values.count("slave/cpus_used"));
  EXPECT_EQ(1u, stats.values.count("slave/cpus_percent"));

  EXPECT_EQ(1u, stats.values.count("slave/mem_total"));
  EXPECT_EQ(1u, stats.values.count("slave/mem_used"));
  EXPECT_EQ(1u, stats.values.count("slave/mem_percent"));

  EXPECT_EQ(1u, stats.values.count("slave/disk_total"));
  EXPECT_EQ(1u, stats.values.count("slave/disk_used"));
  EXPECT_EQ(1u, stats.values.count("slave/disk_percent"));
}

} // namespace tests {
} // namespace internal {
} // namespace mesos {
<commit_msg>Added new MetricsTests with authentication to Mesos tests.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gtest/gtest.h>

#include <mesos/authentication/http/basic_authenticator_factory.hpp>

#include <process/future.hpp>
#include <process/http.hpp>
#include <process/owned.hpp>
#include <process/pid.hpp>

#include <stout/gtest.hpp>
#include <stout/try.hpp>

#include "master/master.hpp"

#include "tests/mesos.hpp"

namespace authentication = process::http::authentication;

using mesos::http::authentication::BasicAuthenticatorFactory;

using mesos::internal::master::Master;
using mesos::internal::slave::Slave;

using mesos::master::detector::MasterDetector;

using process::Owned;

namespace mesos {
namespace internal {
namespace tests {

class MetricsTest : public mesos::internal::tests::MesosTest
{
protected:
  void setBasicHttpAuthenticator(
      const std::string& realm,
      const Credentials& credentials)
  {
    Try<authentication::Authenticator*> authenticator =
      BasicAuthenticatorFactory::create(realm, credentials);

    ASSERT_SOME(authenticator);

    // Add this realm to the set of realms which will be unset during teardown.
    realms.insert(realm);

    // Pass ownership of the authenticator to libprocess.
    AWAIT_READY(authentication::setAuthenticator(
        realm,
        Owned<authentication::Authenticator>(authenticator.get())));
  }

  virtual void TearDown()
  {
    foreach (const std::string& realm, realms) {
      // We need to wait in order to ensure that the operation completes before
      // we leave `TearDown`. Otherwise, we may leak a mock object.
      AWAIT_READY(authentication::unsetAuthenticator(realm));
    }

    realms.clear();

    MesosTest::TearDown();
  }

private:
  hashset<std::string> realms;
};

TEST_F(MetricsTest, Master)
{
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  // Get the snapshot.
  process::UPID upid("metrics", process::address());

  process::Future<process::http::Response> response =
      process::http::get(upid, "snapshot");

  AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response);
  AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);

  Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
  ASSERT_SOME(parse);

  JSON::Object stats = parse.get();

  EXPECT_EQ(1u, stats.values.count("master/uptime_secs"));

  EXPECT_EQ(1u, stats.values.count("master/elected"));

  EXPECT_EQ(1u, stats.values.count("master/slaves_connected"));
  EXPECT_EQ(1u, stats.values.count("master/slaves_disconnected"));
  EXPECT_EQ(1u, stats.values.count("master/slaves_active"));
  EXPECT_EQ(1u, stats.values.count("master/slaves_inactive"));

  EXPECT_EQ(1u, stats.values.count("master/frameworks_connected"));
  EXPECT_EQ(1u, stats.values.count("master/frameworks_disconnected"));
  EXPECT_EQ(1u, stats.values.count("master/frameworks_active"));
  EXPECT_EQ(1u, stats.values.count("master/frameworks_inactive"));

  EXPECT_EQ(1u, stats.values.count("master/outstanding_offers"));

  EXPECT_EQ(1u, stats.values.count("master/tasks_staging"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_starting"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_running"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_killing"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_finished"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_failed"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_killed"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_lost"));
  EXPECT_EQ(1u, stats.values.count("master/tasks_error"));

  EXPECT_EQ(1u, stats.values.count("master/dropped_messages"));

  // Messages from schedulers.
  EXPECT_EQ(1u, stats.values.count("master/messages_register_framework"));
  EXPECT_EQ(1u, stats.values.count("master/messages_reregister_framework"));
  EXPECT_EQ(1u, stats.values.count("master/messages_unregister_framework"));
  EXPECT_EQ(1u, stats.values.count("master/messages_deactivate_framework"));
  EXPECT_EQ(1u, stats.values.count("master/messages_kill_task"));
  EXPECT_EQ(1u, stats.values.count(
      "master/messages_status_update_acknowledgement"));
  EXPECT_EQ(1u, stats.values.count("master/messages_resource_request"));
  EXPECT_EQ(1u, stats.values.count("master/messages_launch_tasks"));
  EXPECT_EQ(1u, stats.values.count("master/messages_decline_offers"));
  EXPECT_EQ(1u, stats.values.count("master/messages_revive_offers"));
  EXPECT_EQ(1u, stats.values.count("master/messages_suppress_offers"));
  EXPECT_EQ(1u, stats.values.count("master/messages_reconcile_tasks"));
  EXPECT_EQ(1u, stats.values.count("master/messages_framework_to_executor"));

  // Messages from slaves.
  EXPECT_EQ(1u, stats.values.count("master/messages_register_slave"));
  EXPECT_EQ(1u, stats.values.count("master/messages_reregister_slave"));
  EXPECT_EQ(1u, stats.values.count("master/messages_unregister_slave"));
  EXPECT_EQ(1u, stats.values.count("master/messages_status_update"));
  EXPECT_EQ(1u, stats.values.count("master/messages_exited_executor"));

  // Messages from both schedulers and slaves.
  EXPECT_EQ(1u, stats.values.count("master/messages_authenticate"));

  EXPECT_EQ(1u, stats.values.count(
      "master/valid_framework_to_executor_messages"));
  EXPECT_EQ(1u, stats.values.count(
      "master/invalid_framework_to_executor_messages"));

  EXPECT_EQ(1u, stats.values.count("master/valid_status_updates"));
  EXPECT_EQ(1u, stats.values.count("master/invalid_status_updates"));

  EXPECT_EQ(1u, stats.values.count(
      "master/valid_status_update_acknowledgements"));
  EXPECT_EQ(1u, stats.values.count(
      "master/invalid_status_update_acknowledgements"));

  EXPECT_EQ(1u, stats.values.count("master/recovery_slave_removals"));

  EXPECT_EQ(1u, stats.values.count("master/event_queue_messages"));
  EXPECT_EQ(1u, stats.values.count("master/event_queue_dispatches"));
  EXPECT_EQ(1u, stats.values.count("master/event_queue_http_requests"));

  EXPECT_EQ(1u, stats.values.count("master/cpus_total"));
  EXPECT_EQ(1u, stats.values.count("master/cpus_used"));
  EXPECT_EQ(1u, stats.values.count("master/cpus_percent"));

  EXPECT_EQ(1u, stats.values.count("master/mem_total"));
  EXPECT_EQ(1u, stats.values.count("master/mem_used"));
  EXPECT_EQ(1u, stats.values.count("master/mem_percent"));

  EXPECT_EQ(1u, stats.values.count("master/disk_total"));
  EXPECT_EQ(1u, stats.values.count("master/disk_used"));
  EXPECT_EQ(1u, stats.values.count("master/disk_percent"));

  EXPECT_EQ(1u, stats.values.count("registrar/queued_operations"));
  EXPECT_EQ(1u, stats.values.count("registrar/registry_size_bytes"));

  EXPECT_EQ(1u, stats.values.count("registrar/state_fetch_ms"));
  EXPECT_EQ(1u, stats.values.count("registrar/state_store_ms"));
}

TEST_F(MetricsTest, Slave)
{
  // TODO(dhamon): https://issues.apache.org/jira/browse/MESOS-2134 to allow
  // only a Slave to be started.
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  Owned<MasterDetector> detector = master.get()->createDetector();
  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get());
  ASSERT_SOME(slave);

  // Get the snapshot.
  process::UPID upid("metrics", process::address());

  process::Future<process::http::Response> response =
      process::http::get(upid, "snapshot");

  AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response);
  AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);

  Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
  ASSERT_SOME(parse);

  JSON::Object stats = parse.get();

  EXPECT_EQ(1u, stats.values.count("slave/uptime_secs"));
  EXPECT_EQ(1u, stats.values.count("slave/registered"));

  EXPECT_EQ(1u, stats.values.count("slave/recovery_errors"));

  EXPECT_EQ(1u, stats.values.count("slave/frameworks_active"));

  EXPECT_EQ(1u, stats.values.count("slave/tasks_staging"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_starting"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_running"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_killing"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_finished"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_failed"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_killed"));
  EXPECT_EQ(1u, stats.values.count("slave/tasks_lost"));

  EXPECT_EQ(1u, stats.values.count("slave/executors_registering"));
  EXPECT_EQ(1u, stats.values.count("slave/executors_running"));
  EXPECT_EQ(1u, stats.values.count("slave/executors_terminating"));
  EXPECT_EQ(1u, stats.values.count("slave/executors_terminated"));

  EXPECT_EQ(1u, stats.values.count("slave/valid_status_updates"));
  EXPECT_EQ(1u, stats.values.count("slave/invalid_status_updates"));

  EXPECT_EQ(1u, stats.values.count("slave/valid_framework_messages"));
  EXPECT_EQ(1u, stats.values.count("slave/invalid_framework_messages"));

  EXPECT_EQ(1u, stats.values.count("slave/container_launch_errors"));

  EXPECT_EQ(1u, stats.values.count("slave/cpus_total"));
  EXPECT_EQ(1u, stats.values.count("slave/cpus_used"));
  EXPECT_EQ(1u, stats.values.count("slave/cpus_percent"));

  EXPECT_EQ(1u, stats.values.count("slave/mem_total"));
  EXPECT_EQ(1u, stats.values.count("slave/mem_used"));
  EXPECT_EQ(1u, stats.values.count("slave/mem_percent"));

  EXPECT_EQ(1u, stats.values.count("slave/disk_total"));
  EXPECT_EQ(1u, stats.values.count("slave/disk_used"));
  EXPECT_EQ(1u, stats.values.count("slave/disk_percent"));
}

// Tests that the `/metrics/snapshot` endpoint will reject unauthenticated
// requests when HTTP authentication is enabled on the master.
TEST_F(MetricsTest, MasterAuthenticationEnabled)
{
  Credentials credentials;
  credentials.add_credentials()->CopyFrom(DEFAULT_CREDENTIAL);

  // Create a basic HTTP authenticator with the specified credentials and set it
  // as the authenticator for `DEFAULT_HTTP_AUTHENTICATION_REALM`.
  setBasicHttpAuthenticator(DEFAULT_HTTP_AUTHENTICATION_REALM, credentials);

  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  // Get the snapshot.
  process::UPID upid("metrics", process::address());

  process::Future<process::http::Response> response =
      process::http::get(upid, "snapshot");

  AWAIT_EXPECT_RESPONSE_STATUS_EQ(
      process::http::Unauthorized({}).status, response);
}

// Tests that the `/metrics/snapshot` endpoint will reject unauthenticated
// requests when HTTP authentication is enabled on the agent.
TEST_F(MetricsTest, AgentAuthenticationEnabled)
{
  Credentials credentials;
  credentials.add_credentials()->CopyFrom(DEFAULT_CREDENTIAL);

  // Create a basic HTTP authenticator with the specified credentials and set it
  // as the authenticator for `DEFAULT_HTTP_AUTHENTICATION_REALM`.
  setBasicHttpAuthenticator(DEFAULT_HTTP_AUTHENTICATION_REALM, credentials);

  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  Owned<MasterDetector> detector = master.get()->createDetector();
  Try<Owned<cluster::Slave>> agent = StartSlave(detector.get());
  ASSERT_SOME(agent);

  // Get the snapshot.
  process::UPID upid("metrics", process::address());

  process::Future<process::http::Response> response =
      process::http::get(upid, "snapshot");

  AWAIT_EXPECT_RESPONSE_STATUS_EQ(
      process::http::Unauthorized({}).status, response);
}

} // namespace tests {
} // namespace internal {
} // namespace mesos {
<|endoftext|>


<commit_before>/*
* (C) 2014 cryptosource GmbH
* (C) 2014 Falko Strenzke fstrenzke@cryptosource.de
* (C) 2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"

#if defined(BOTAN_HAS_MCELIECE)

#include <botan/mceliece.h>
#include <botan/pubkey.h>
#include <botan/oids.h>
#include <botan/hmac_drbg.h>
#include <botan/loadstor.h>
#include <botan/hash.h>
#include <botan/hex.h>

#if defined(BOTAN_HAS_MCEIES)
#include <botan/mceies.h>
#endif

#endif

namespace Botan_Tests {

namespace {

#if defined(BOTAN_HAS_MCELIECE)

std::vector<byte> hash_bytes(const byte b[], size_t len, const std::string& hash_fn = "SHA-256")
   {
   std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(hash_fn));
   hash->update(b, len);
   std::vector<byte> r(hash->output_length());
   hash->final(r.data());
   return r;
   }

template<typename A>
std::vector<byte> hash_bytes(const std::vector<byte, A>& v)
   {
   return hash_bytes(v.data(), v.size());
   }

class McEliece_Keygen_Encrypt_Test : public Text_Based_Test
   {
   public:
      McEliece_Keygen_Encrypt_Test() :
         Text_Based_Test("McEliece",
                         "pubkey/mce.vec",
                         {"McElieceSeed", "KeyN","KeyT","PublicKeyFingerprint",
                          "PrivateKeyFingerprint", "EncryptPRNGSeed",
                            "SharedKey", "Ciphertext" })
         {}

      Test::Result run_one_test(const std::string&, const VarMap& vars) override
         {
         const std::vector<byte> keygen_seed  = get_req_bin(vars, "McElieceSeed");
         const std::vector<byte> fprint_pub   = get_req_bin(vars, "PublicKeyFingerprint");
         const std::vector<byte> fprint_priv  = get_req_bin(vars, "PrivateKeyFingerprint");
         const std::vector<byte> encrypt_seed = get_req_bin(vars, "EncryptPRNGSeed");
         const std::vector<byte> ciphertext   = get_req_bin(vars, "Ciphertext");
         const std::vector<byte> shared_key   = get_req_bin(vars, "SharedKey");
         const size_t keygen_n = get_req_sz(vars, "KeyN");
         const size_t keygen_t = get_req_sz(vars, "KeyT");

         Botan::HMAC_DRBG rng("HMAC(SHA-384)");

         rng.add_entropy(keygen_seed.data(), keygen_seed.size());
         Botan::McEliece_PrivateKey mce_priv(rng, keygen_n, keygen_t);

         Test::Result result("McEliece keygen");

         result.test_eq("public key fingerprint", hash_bytes(mce_priv.x509_subject_public_key()), fprint_pub);
         result.test_eq("private key fingerprint", hash_bytes(mce_priv.pkcs8_private_key()), fprint_priv);

         rng.clear();
         rng.add_entropy(encrypt_seed.data(), encrypt_seed.size());

         try
            {
            Botan::PK_KEM_Encryptor kem_enc(mce_priv, "KDF1(SHA-512)");
            Botan::PK_KEM_Decryptor kem_dec(mce_priv, "KDF1(SHA-512)");

            Botan::secure_vector<byte> encap_key, prod_shared_key;
            kem_enc.encrypt(encap_key, prod_shared_key, 64, rng);

            Botan::secure_vector<byte> dec_shared_key = kem_dec.decrypt(encap_key.data(), encap_key.size(), 64);

            result.test_eq("ciphertext", encap_key, ciphertext);
            result.test_eq("encrypt shared", prod_shared_key, shared_key);
            result.test_eq("decrypt shared", dec_shared_key, shared_key);
            }
         catch(Botan::Lookup_Error&)
            {
            }

         return result;
         }

   };

BOTAN_REGISTER_TEST("mce_keygen", McEliece_Keygen_Encrypt_Test);

class McEliece_Tests : public Test
   {
   public:

      std::string fingerprint(const Botan::Private_Key& key, const std::string& hash_algo = "SHA-256")
         {
         std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(hash_algo));
         if(!hash)
            throw Test_Error("Hash " + hash_algo + " not available");

         hash->update(key.pkcs8_private_key());
         return Botan::hex_encode(hash->final());
         }

      std::string fingerprint(const Botan::Public_Key& key, const std::string& hash_algo = "SHA-256")
         {
         std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(hash_algo));
         if(!hash)
            throw Test_Error("Hash " + hash_algo + " not available");

         hash->update(key.x509_subject_public_key());
         return Botan::hex_encode(hash->final());
         }

      std::vector<Test::Result> run() override
         {
         size_t params__n__t_min_max[] = {
            256, 5, 15,
            512, 5, 33,
            1024, 15, 35,
            2048, 33, 50,
            2960, 50, 56,
            6624, 110, 115
         };

         std::vector<Test::Result> results;

         for(size_t i = 0; i < sizeof(params__n__t_min_max)/sizeof(params__n__t_min_max[0]); i+=3)
            {
            const size_t code_length = params__n__t_min_max[i];
            const size_t min_t = params__n__t_min_max[i+1];
            const size_t max_t = params__n__t_min_max[i+2];

            for(size_t t = min_t; t <= max_t; ++t)
               {
               Botan::McEliece_PrivateKey sk1(Test::rng(), code_length, t);
               const Botan::McEliece_PublicKey& pk1 = sk1;

               const std::vector<byte> pk_enc = pk1.x509_subject_public_key();
               const Botan::secure_vector<byte> sk_enc = sk1.pkcs8_private_key();

               Botan::McEliece_PublicKey pk(pk_enc);
               Botan::McEliece_PrivateKey sk(sk_enc);

               Test::Result result("McEliece keygen");

               result.test_eq("decoded public key equals original", fingerprint(pk1), fingerprint(pk));

               result.test_eq("decoded private key equals original", fingerprint(sk1), fingerprint(sk));

               result.test_eq("key validation passes", sk.check_key(Test::rng(), false), true);

               results.push_back(result);

               results.push_back(test_kem(sk, pk));

#if defined(BOTAN_HAS_MCEIES)
               results.push_back(test_mceies(sk, pk));
#endif
               }
            }

         return results;
         }

   private:
      Test::Result test_kem(const Botan::McEliece_PrivateKey& sk,
                            const Botan::McEliece_PublicKey& pk)
         {
         Test::Result result("McEliece KEM");

         Botan::PK_KEM_Encryptor enc_op(pk, "KDF2(SHA-256)");
         Botan::PK_KEM_Decryptor dec_op(sk, "KDF2(SHA-256)");

         for(size_t i = 0; i <= Test::soak_level(); i++)
            {
            Botan::secure_vector<byte> salt = Test::rng().random_vec(i);

            Botan::secure_vector<byte> encap_key, shared_key;
            enc_op.encrypt(encap_key, shared_key, 64, Test::rng(), salt);

            Botan::secure_vector<byte> shared_key2 = dec_op.decrypt(encap_key, 64, salt);

            result.test_eq("same key", shared_key, shared_key2);
            }
         return result;
         }

#if defined(BOTAN_HAS_MCEIES)
      Test::Result test_mceies(const Botan::McEliece_PrivateKey& sk,
                               const Botan::McEliece_PublicKey& pk)
         {
         Test::Result result("McEliece IES");

         for(size_t i = 0; i <= Test::soak_level(); ++i)
            {
            uint8_t ad[8];
            Botan::store_be(static_cast<Botan::u64bit>(i), ad);
            const size_t ad_len = sizeof(ad);

            const Botan::secure_vector<byte> pt = Test::rng().random_vec(Test::rng().next_byte());

            const Botan::secure_vector<byte> ct = mceies_encrypt(pk, pt.data(), pt.size(), ad, ad_len, Test::rng());
            const Botan::secure_vector<byte> dec = mceies_decrypt(sk, ct.data(), ct.size(), ad, ad_len);

            result.test_eq("decrypted ok", dec, pt);

            Botan::secure_vector<byte> bad_ct = ct;
            for(size_t j = 0; j != 3; ++j)
               {
               bad_ct = mutate_vec(ct, true);

               try
                  {
                  mceies_decrypt(sk, bad_ct.data(), bad_ct.size(), ad, ad_len);
                  result.test_failure("AEAD decrypted manipulated ciphertext");
                  result.test_note("Manipulated text was " + Botan::hex_encode(bad_ct));
                  }
               catch(Botan::Integrity_Failure&)
                  {
                  result.test_note("AEAD rejected manipulated ciphertext");
                  }
               catch(std::exception& e)
                  {
                  result.test_failure("AEAD rejected manipulated ciphertext with unexpected error", e.what());
                  }
               }
            }

         return result;
         }
#endif

   };

BOTAN_REGISTER_TEST("mceliece", McEliece_Tests);

#endif

}

}
<commit_msg>Tweak for readability in McEliece tests<commit_after>/*
* (C) 2014 cryptosource GmbH
* (C) 2014 Falko Strenzke fstrenzke@cryptosource.de
* (C) 2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"

#if defined(BOTAN_HAS_MCELIECE)

#include <botan/mceliece.h>
#include <botan/pubkey.h>
#include <botan/oids.h>
#include <botan/hmac_drbg.h>
#include <botan/loadstor.h>
#include <botan/hash.h>
#include <botan/hex.h>

#if defined(BOTAN_HAS_MCEIES)
#include <botan/mceies.h>
#endif

#endif

namespace Botan_Tests {

namespace {

#if defined(BOTAN_HAS_MCELIECE)

std::vector<byte> hash_bytes(const byte b[], size_t len, const std::string& hash_fn = "SHA-256")
   {
   std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(hash_fn));
   hash->update(b, len);
   std::vector<byte> r(hash->output_length());
   hash->final(r.data());
   return r;
   }

template<typename A>
std::vector<byte> hash_bytes(const std::vector<byte, A>& v)
   {
   return hash_bytes(v.data(), v.size());
   }

class McEliece_Keygen_Encrypt_Test : public Text_Based_Test
   {
   public:
      McEliece_Keygen_Encrypt_Test() :
         Text_Based_Test("McEliece",
                         "pubkey/mce.vec",
                         {"McElieceSeed", "KeyN","KeyT","PublicKeyFingerprint",
                          "PrivateKeyFingerprint", "EncryptPRNGSeed",
                            "SharedKey", "Ciphertext" })
         {}

      Test::Result run_one_test(const std::string&, const VarMap& vars) override
         {
         const std::vector<byte> keygen_seed  = get_req_bin(vars, "McElieceSeed");
         const std::vector<byte> fprint_pub   = get_req_bin(vars, "PublicKeyFingerprint");
         const std::vector<byte> fprint_priv  = get_req_bin(vars, "PrivateKeyFingerprint");
         const std::vector<byte> encrypt_seed = get_req_bin(vars, "EncryptPRNGSeed");
         const std::vector<byte> ciphertext   = get_req_bin(vars, "Ciphertext");
         const std::vector<byte> shared_key   = get_req_bin(vars, "SharedKey");
         const size_t keygen_n = get_req_sz(vars, "KeyN");
         const size_t keygen_t = get_req_sz(vars, "KeyT");

         Botan::HMAC_DRBG rng("HMAC(SHA-384)");

         rng.add_entropy(keygen_seed.data(), keygen_seed.size());
         Botan::McEliece_PrivateKey mce_priv(rng, keygen_n, keygen_t);

         Test::Result result("McEliece keygen");

         result.test_eq("public key fingerprint", hash_bytes(mce_priv.x509_subject_public_key()), fprint_pub);
         result.test_eq("private key fingerprint", hash_bytes(mce_priv.pkcs8_private_key()), fprint_priv);

         rng.clear();
         rng.add_entropy(encrypt_seed.data(), encrypt_seed.size());

         try
            {
            Botan::PK_KEM_Encryptor kem_enc(mce_priv, "KDF1(SHA-512)");
            Botan::PK_KEM_Decryptor kem_dec(mce_priv, "KDF1(SHA-512)");

            Botan::secure_vector<byte> encap_key, prod_shared_key;
            kem_enc.encrypt(encap_key, prod_shared_key, 64, rng);

            Botan::secure_vector<byte> dec_shared_key = kem_dec.decrypt(encap_key.data(), encap_key.size(), 64);

            result.test_eq("ciphertext", encap_key, ciphertext);
            result.test_eq("encrypt shared", prod_shared_key, shared_key);
            result.test_eq("decrypt shared", dec_shared_key, shared_key);
            }
         catch(Botan::Lookup_Error&)
            {
            }

         return result;
         }

   };

BOTAN_REGISTER_TEST("mce_keygen", McEliece_Keygen_Encrypt_Test);

class McEliece_Tests : public Test
   {
   public:

      std::string fingerprint(const Botan::Private_Key& key, const std::string& hash_algo = "SHA-256")
         {
         std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(hash_algo));
         if(!hash)
            throw Test_Error("Hash " + hash_algo + " not available");

         hash->update(key.pkcs8_private_key());
         return Botan::hex_encode(hash->final());
         }

      std::string fingerprint(const Botan::Public_Key& key, const std::string& hash_algo = "SHA-256")
         {
         std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(hash_algo));
         if(!hash)
            throw Test_Error("Hash " + hash_algo + " not available");

         hash->update(key.x509_subject_public_key());
         return Botan::hex_encode(hash->final());
         }

      std::vector<Test::Result> run() override
         {
         struct keygen_params { size_t code_length, t_min, t_max; };

         const keygen_params param_sets[] = { { 256, 5, 15 },
                                              { 512, 5, 33 },
                                              { 1024, 15, 35 },
                                              { 2048, 33, 50 },
                                              { 6624, 110, 115 } };

         std::vector<Test::Result> results;

         for(size_t i = 0; i < sizeof(param_sets)/sizeof(param_sets[0]); ++i)
            {
            for(size_t t = param_sets[i].t_min; t <= param_sets[i].t_max; ++t)
               {
               Botan::McEliece_PrivateKey sk1(Test::rng(), param_sets[i].code_length, t);
               const Botan::McEliece_PublicKey& pk1 = sk1;

               const std::vector<byte> pk_enc = pk1.x509_subject_public_key();
               const Botan::secure_vector<byte> sk_enc = sk1.pkcs8_private_key();

               Botan::McEliece_PublicKey pk(pk_enc);
               Botan::McEliece_PrivateKey sk(sk_enc);

               Test::Result result("McEliece keygen");

               result.test_eq("decoded public key equals original", fingerprint(pk1), fingerprint(pk));

               result.test_eq("decoded private key equals original", fingerprint(sk1), fingerprint(sk));

               result.test_eq("key validation passes", sk.check_key(Test::rng(), false), true);

               results.push_back(result);

               results.push_back(test_kem(sk, pk));

#if defined(BOTAN_HAS_MCEIES)
               results.push_back(test_mceies(sk, pk));
#endif
               }
            }

         return results;
         }

   private:
      Test::Result test_kem(const Botan::McEliece_PrivateKey& sk,
                            const Botan::McEliece_PublicKey& pk)
         {
         Test::Result result("McEliece KEM");

         Botan::PK_KEM_Encryptor enc_op(pk, "KDF2(SHA-256)");
         Botan::PK_KEM_Decryptor dec_op(sk, "KDF2(SHA-256)");

         for(size_t i = 0; i <= Test::soak_level(); i++)
            {
            Botan::secure_vector<byte> salt = Test::rng().random_vec(i);

            Botan::secure_vector<byte> encap_key, shared_key;
            enc_op.encrypt(encap_key, shared_key, 64, Test::rng(), salt);

            Botan::secure_vector<byte> shared_key2 = dec_op.decrypt(encap_key, 64, salt);

            result.test_eq("same key", shared_key, shared_key2);
            }
         return result;
         }

#if defined(BOTAN_HAS_MCEIES)
      Test::Result test_mceies(const Botan::McEliece_PrivateKey& sk,
                               const Botan::McEliece_PublicKey& pk)
         {
         Test::Result result("McEliece IES");

         for(size_t i = 0; i <= Test::soak_level(); ++i)
            {
            uint8_t ad[8];
            Botan::store_be(static_cast<Botan::u64bit>(i), ad);
            const size_t ad_len = sizeof(ad);

            const Botan::secure_vector<byte> pt = Test::rng().random_vec(Test::rng().next_byte());

            const Botan::secure_vector<byte> ct = mceies_encrypt(pk, pt.data(), pt.size(), ad, ad_len, Test::rng());
            const Botan::secure_vector<byte> dec = mceies_decrypt(sk, ct.data(), ct.size(), ad, ad_len);

            result.test_eq("decrypted ok", dec, pt);

            Botan::secure_vector<byte> bad_ct = ct;
            for(size_t j = 0; j != 3; ++j)
               {
               bad_ct = mutate_vec(ct, true);

               try
                  {
                  mceies_decrypt(sk, bad_ct.data(), bad_ct.size(), ad, ad_len);
                  result.test_failure("AEAD decrypted manipulated ciphertext");
                  result.test_note("Manipulated text was " + Botan::hex_encode(bad_ct));
                  }
               catch(Botan::Integrity_Failure&)
                  {
                  result.test_note("AEAD rejected manipulated ciphertext");
                  }
               catch(std::exception& e)
                  {
                  result.test_failure("AEAD rejected manipulated ciphertext with unexpected error", e.what());
                  }
               }
            }

         return result;
         }
#endif

   };

BOTAN_REGISTER_TEST("mceliece", McEliece_Tests);

#endif

}

}
<|endoftext|>


<commit_before>#include <GLFW/glfw3.h>
#include <cstring>
#include <stdlib.h>		  // srand, rand
#include <thread>         // std::this_thread::sleep_for
#include <chrono>         // std::chrono::seconds
#include <windows.h>
#include <iostream>
#include "iconvector.h"

using namespace std;

// scratched from https://courses.engr.illinois.edu/ece390/archive/archive-f2000/mp/mp4/anti.html
// see 'Rasterization' part.
void drawOnPixelBuffer()
{
	//std::memset(pixels, 1.0f, sizeof(float)*width*height * 3); // doesn't work
	std::fill_n(pixels, width*height * 3, 1.0f);	// white background

													//for (int i = 0; i<width*height; i++) {
													//	pixels[i * 3 + 0] = 1.0f; // red
													//	pixels[i * 3 + 1] = 1.0f; // green
													//	pixels[i * 3 + 2] = 1.0f; // blue
													//}

	const int i = rand() % width, j = rand() % height;
	drawPixel(i, j, 0.0f, 0.0f, 0.0f);

	// drawing a line
	//TODO: anti-aliasing
	/*const int i0 = 100, i1 = 200;
	const int j0 = 50, j1 = 80;
	drawLine(i0, j0, i1, j1, 1.0f, 0.0f, 0.0f);*/

	//TODO: try moving object
}

int main(void)
{
	GLFWwindow* window;

	/* Initialize the library */
	if (!glfwInit())
		return -1;

	/* Create a windowed mode window and its OpenGL context */
	window = glfwCreateWindow(width, height, "Hello World", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		return -1;
	}

	vector<geo*> object_list;

	/* Make the window's context current */
	glfwMakeContextCurrent(window);

	/* Loop until the user closes the window */
	while (!glfwWindowShouldClose(window))
	{
		/* Render here */
		glClear(GL_COLOR_BUFFER_BIT);

		std::fill_n(pixels, width*height * 3, 1.0f);

		//for (auto itr : object_list)
		//{
		//	itr->drawfor(int i:int object_list)
		//}

		geticon(object_list);
		for (geo*g : object_list)
		{
			g->draw();
			glfwGetCursorPos(window, &xx, &yy);
			yy = height - yy;
		}
		glDrawPixels(width, height, GL_RGB, GL_FLOAT, pixels);

		/* Swap front and back buffers */
		glfwSwapBuffers(window);

		/* Poll for and process events */
		glfwPollEvents();
	}

	delete[] pixels;

	glfwTerminate();
	return 0;
}<commit_msg>Delete P1,2,3.cpp<commit_after><|endoftext|>


<commit_before>/*
 * Element.cpp
 *
 *  Created on: Dec 3, 2012
 *      Author: rmcmahon
 */

#include <stdlib.h>
#include <stdio.h>
#include "Element.h"
#include <math.h>

struct Element* createElement(enum LayoutType layoutType) {
    struct Element* element = (struct Element*)malloc(sizeof(struct Element));

    if (NULL == element) {
        printf("\n Element creation failed \n");
        return NULL;
    }

    (*element)._layoutCoefficients.width = {NAN, NAN, NAN};
    (*element)._layoutCoefficients.minWidth = {NAN, NAN, NAN};
    (*element)._layoutCoefficients.sandboxWidth = {NAN, NAN, NAN};
    (*element)._layoutCoefficients.height = {NAN, NAN, NAN};
    (*element)._layoutCoefficients.minHeight = {NAN, NAN, NAN};
    (*element)._layoutCoefficients.sandboxHeight = {NAN, NAN, NAN};
    (*element)._layoutCoefficients.left = {NAN, NAN, NAN};
    (*element)._layoutCoefficients.top =  {NAN, NAN, NAN, NAN};
    (*element)._layoutType = layoutType;
    (*element)._defaultRowAlignment = start;
    (*element)._defaultHorizontalAlignment = center;
    (*element)._defaultVerticalAlignment = center;

    return element;
}

void addChildElement(Element* parent, Element* child) {

	if (NULL == parent || NULL == child) {
	   printf("\n Element add child failed \n");
	}

	(*parent)._children.push_back(child);
}
<commit_msg>Remove element inits {} and using ansi style<commit_after>/*
 * Element.cpp
 *
 *  Created on: Dec 3, 2012
 *      Author: rmcmahon
 */

#include <stdlib.h>
#include <stdio.h>
#include "Element.h"
#include <math.h>

struct Element* createElement(enum LayoutType layoutType) {
    struct Element* element = (struct Element*)malloc(sizeof(struct Element));

    if (NULL == element) {
        printf("\n Element creation failed \n");
        return NULL;
    }

    (*element)._layoutCoefficients.width.x1 = NAN;
    (*element)._layoutCoefficients.width.x2 =  NAN;
    (*element)._layoutCoefficients.width.x3 = NAN;
    (*element)._layoutCoefficients.minWidth.x1 = NAN;
    (*element)._layoutCoefficients.minWidth.x2 = NAN;
    (*element)._layoutCoefficients.minWidth.x3 = NAN;
    (*element)._layoutCoefficients.sandboxWidth.x1 = NAN;
    (*element)._layoutCoefficients.sandboxWidth.x2 = NAN;
    (*element)._layoutCoefficients.sandboxWidth.x3 = NAN;
    (*element)._layoutCoefficients.height.x1 = NAN;
    (*element)._layoutCoefficients.height.x2 =  NAN;
    (*element)._layoutCoefficients.height.x3 =  NAN;
    (*element)._layoutCoefficients.minHeight.x1 = NAN;
    (*element)._layoutCoefficients.minHeight.x2 =  NAN;
    (*element)._layoutCoefficients.minHeight.x3 =  NAN;
    (*element)._layoutCoefficients.sandboxHeight.x1 = NAN;
    (*element)._layoutCoefficients.sandboxHeight.x2 = NAN;
    (*element)._layoutCoefficients.sandboxHeight.x3 = NAN;
    (*element)._layoutCoefficients.left.x1 = NAN;
    (*element)._layoutCoefficients.left.x2 = NAN;
    (*element)._layoutCoefficients.left.x3 = NAN;
    (*element)._layoutCoefficients.top.x1 =  NAN;
    (*element)._layoutCoefficients.top.x2 = NAN;
	(*element)._layoutCoefficients.top.x3 = NAN;
    (*element)._layoutType = layoutType;
    (*element)._defaultRowAlignment = start;
    (*element)._defaultHorizontalAlignment = center;
    (*element)._defaultVerticalAlignment = center;

    return element;
}

void addChildElement(Element* parent, Element* child) {

	if (NULL == parent || NULL == child) {
	   printf("\n Element add child failed \n");
	}

	(*parent)._children.push_back(child);
}
<|endoftext|>


<commit_before>/*
 * TiProxy.cpp
 *
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2013 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */

#include "Ti_Proxy.h"
#include "Ti_Helper.h"
#include "Ti_Constants.h"
#include <QObject>
#include <v8.h>

Ti::TiProxy::TiProxy(const char* name) :
__data__(NULL),
_proxyName(QString(name))
{
	HandleScope scope;
	_jsObjectTemplate = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
	_jsObjectTemplate->SetNamedPropertyHandler(Ti::TiProxy::_Getter, Ti::TiProxy::_Setter);
	_jsObject = Persistent<Object>::New(_jsObjectTemplate->NewInstance());

	createPropertyFunction("addEventListener", _addEventListener);
	createPropertyFunction("removeEventListener", _removeEventListener);
	createPropertyFunction("fireEvent", _fireEvent);
	createPropertyFunction("toString", _getToString);
}

Ti::TiProxy::~TiProxy()
{
	qDeleteAll(properties);
	properties.clear();

	_jsObject.Clear();
	_jsObject.Dispose();
	_jsObjectTemplate.Clear();
	_jsObjectTemplate.Dispose();
}

void Ti::TiProxy::initStart()
{

}

void Ti::TiProxy::initWithObject(Handle<Object> obj)
{
	HandleScope scope;
	Local<Array> props = obj->GetPropertyNames();
	for(int i = 0, len = props->Length(); i < len; i++) {
		Local<String> key = props->Get(i)->ToString();
		Local<Value> val = obj->Get(key);
		_jsObject->Set(key, val);
	}
}

Ti::TiValue Ti::TiProxy::applyProperties(Ti::TiValue value)
{
	if(value.isMap())
	{
		initWithObject(value.toJSValue()->ToObject());
	}
	Ti::TiValue val;
	val.setUndefined();
	return val;
}

void Ti::TiProxy::initEnd()
{

}

const char* Ti::TiProxy::getProxyName()
{
	return _proxyName.toLocal8Bit().constData();
}

Handle<ObjectTemplate> Ti::TiProxy::getJSObjectTemplate() {
	return _jsObjectTemplate;
}

void Ti::TiProxy::addFunction(const char* name, InvocationCallback callback)
{
	_jsObject->ForceSet(String::New(name), FunctionTemplate::New(callback)->GetFunction(), DontDelete);

}
void Ti::TiProxy::createPropertyFunction(QString name, PROPERTY_FUNCTION callback)
{
	Ti::TiProperty::createFunction(this, name, callback);
}
void Ti::TiProxy::createPropertySetter(QString name, PROPERTY_SETTER callback)
{
	Ti::TiProperty::createSetter(this, name, callback);
}
void Ti::TiProxy::createPropertyGetter(QString name, PROPERTY_GETTER callback)
{
	Ti::TiProperty::createGetter(this, name, callback);
}
void Ti::TiProxy::createPropertySetterGetter(QString name, PROPERTY_SETTER setter, PROPERTY_GETTER getter)
{
	Ti::TiProperty::createProperty(this, name, setter, getter);
}

void Ti::TiProxy::onEventAdded(QString str)
{
	events.append(str);
	// for subclass
}
void Ti::TiProxy::onEventRemoved(QString str)
{
	if(events.contains(str)) {
		events.removeOne(str);
	}
	// for subclass
}

Ti::TiValue Ti::TiProxy::addEventListener(Ti::TiValue value)
{
	QString eventName;

	Ti::TiValue nameValue = value.toList().at(0);
	Ti::TiValue functionValue = value.toList().at(1);

	eventName = nameValue.toString();

	onEventAdded(eventName);

	Ti::TiEvent::AddEventToObject(_jsObject, eventName, Handle<Function>::Cast(functionValue.toJSValue()));

	Ti::TiValue res;
	res.setUndefined();
	return res;
}

Ti::TiValue Ti::TiProxy::removeEventListener(Ti::TiValue value)
{
	Ti::TiValue nameValue = value.toList().at(0);
	QString eventName = nameValue.toString();

	Ti::TiValue functionValue = value.toList().at(1);
	Handle<Function> func = Handle<Function>::Cast(functionValue.toJSValue());

	Ti::TiEvent::RemoveEventFromObject(_jsObject, eventName, func);
	Ti::TiValue res;
	res.setUndefined();
	return res;
}

// TODO: Finish this
Ti::TiValue Ti::TiProxy::fireEvent(Ti::TiValue value)
{
	QString eventName;
	Ti::TiEventParameters eventParams;
	if(value.isList()) {

		Ti::TiValue eName = value.toList().at(0);
		Ti::TiValue eParams = value.toList().at(1);
		eventName = eName.toString();

		if(eParams.isMap())
		{
			QMap<QString, Ti::TiValue> map = eParams.toMap();
			QList<QString> keys = map.keys();
			int len = keys.size();
			while(len--)
			{
				QString 	name 	= keys.at(len);
				Ti::TiValue val 	= map[name];

				if(val.isNumber())
				{
					eventParams.addParam(name, val.toNumber());
				}
				else if (val.isProxy())
				{
					eventParams.addParam(name, val.toProxy());
				}
				else // if(val.isString())
				{
					eventParams.addParam(name, val.toString());
				}
			}
		}
	}
	else
	{
		eventName = value.toString();
	}

	fireEvent(eventName, eventParams);

	return Ti::TiValue(Undefined());
}

void Ti::TiProxy::fireCallback(QString eventName, Ti::TiEventParameters params)
{
	Ti::TiEvent::FireCallbackIfNeeded(eventName, _jsObject, &params);
}
void Ti::TiProxy::fireEvent(QString eventName, Ti::TiEventParameters params)
{
	HandleScope scope;
	if(events.contains(eventName)) {
		if(!params.contains("source"))
		{
			params.addParam("source", this);
		}
		Ti::TiEvent::FireEventOnObject(_jsObject, eventName, &params);
	}
	if(eventName == Ti::TiConstants::EventClose)
	{
		Ti::TiHelper::LogInternal("Forcing GC");
		V8::LowMemoryNotification();
	}
}

Ti::TiValue Ti::TiProxy::getToString(Ti::TiValue)
{
	Ti::TiValue val;
	val.setString(QString("[object ").append(_proxyName).append("]"));
	return val;
}

Ti::TiValue Ti::TiProxy::getTiValueForKey(QString key)
{
	Handle<Value> val = _jsObject->Get(Ti::TiHelper::ValueFromQString(key));
	if(val.IsEmpty())
	{
		val = Undefined();
	}
	return Ti::TiValue(val);
}
void Ti::TiProxy::setTiValueForKey(Ti::TiValue value, QString key)
{
	_jsObject->Set(TiHelper::ValueFromQString(key), value.toJSValue());
}

void Ti::TiProxy::makeWeak()
{
	// if(_jsObject.IsEmpty()) return;
	// Ti::TiHelper::LogInternal(QString("Make weak ").append(QString(_proxyName)));
	_jsObject.MakeWeak(this, _WeakCallback);
}
void Ti::TiProxy::clearWeak()
{
	// if(_jsObject.IsEmpty()) return;
	// Ti::TiHelper::LogInternal(QString("Clear weak ").append(QString(_proxyName)));
	_jsObject.ClearWeak();
	_jsObjectTemplate.ClearWeak();
	_jsObject.MarkIndependent();
}

Handle<Value> Ti::TiProxy::_Getter (Local<String> property, const AccessorInfo& info)
{
	HandleScope handleScope;
	Handle<Object> obj = Handle<Object>::Cast(info.Holder());
	Handle<External> proxyObject = Handle<External>::Cast(obj->GetHiddenValue(String::New("module")));

	if(proxyObject.IsEmpty())
		proxyObject = Handle<External>::Cast(obj->GetHiddenValue(String::New("proxy")));

	if(proxyObject.IsEmpty())
		return handleScope.Close(Handle<Value>());

	Ti::TiProxy* tiProxy = static_cast<Ti::TiProxy*>(proxyObject->Value());

	if(tiProxy->properties.contains(Ti::TiHelper::QStringFromValue(property)))
	{
		Ti::TiProperty *prop = tiProxy->properties[Ti::TiHelper::QStringFromValue(property)];
		Handle<Value> r = prop->getValue();
		if(r.IsEmpty() || r->IsUndefined())
			return handleScope.Close(Handle<Value>());
		return handleScope.Close(r);
	}
	return handleScope.Close(Handle<Value>());
}

Handle<Value> Ti::TiProxy::_Setter (Local<String> property, Local<Value> value, const AccessorInfo& info)
{
	HandleScope handleScope;
	// Ti::TiHelper::LogInternal(QString("Property Setter: ").append(Ti::TiHelper::QStringFromValue(property)));

	// Todo: Come back to this later
	// if(value == info.Holder()->Get(property)) {
	//	 Ti::TiHelper::LogInternal(QString("Already set: ").append(Ti::TiHelper::QStringFromValue(property)));
	//	 return value;
	// }

	Handle<Object> obj = Handle<Object>::Cast(info.Holder());
	// Todo: come back to this - might not be allowing GC to collect proxies
	obj->ForceSet(property, value);
	// for example. scrollView.views = [a,b,c]
	// scrollView.remove(a) <--- removed from view, but still in array
	Handle<External> proxyObject = Handle<External>::Cast(obj->GetHiddenValue(String::New("module")));
	if(proxyObject.IsEmpty())
		proxyObject = Handle<External>::Cast(obj->GetHiddenValue(String::New("proxy")));

	if(proxyObject.IsEmpty())
		return value;

	Ti::TiProxy* tiProxy = static_cast<Ti::TiProxy*>(proxyObject->Value());
	if(tiProxy->properties.contains(Ti::TiHelper::QStringFromValue(property)))
	{

		Ti::TiProperty *prop = tiProxy->properties[Ti::TiHelper::QStringFromValue(property)];
		return handleScope.Close(prop->setValue(value));
	}

	return value;
}

void Ti::TiProxy::_WeakCallback(Persistent<Value>, void* parameter)
{
	Ti::TiProxy* obj = static_cast<Ti::TiProxy*>(parameter);
	delete obj;
	obj = NULL;
}
<commit_msg>[TIMOB-15257] Added "type" to global event<commit_after>/*
 * TiProxy.cpp
 *
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2013 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */

#include "Ti_Proxy.h"
#include "Ti_Helper.h"
#include "Ti_Constants.h"
#include <QObject>
#include <v8.h>

Ti::TiProxy::TiProxy(const char* name) :
__data__(NULL),
_proxyName(QString(name))
{
	HandleScope scope;
	_jsObjectTemplate = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
	_jsObjectTemplate->SetNamedPropertyHandler(Ti::TiProxy::_Getter, Ti::TiProxy::_Setter);
	_jsObject = Persistent<Object>::New(_jsObjectTemplate->NewInstance());

	createPropertyFunction("addEventListener", _addEventListener);
	createPropertyFunction("removeEventListener", _removeEventListener);
	createPropertyFunction("fireEvent", _fireEvent);
	createPropertyFunction("toString", _getToString);
}

Ti::TiProxy::~TiProxy()
{
	qDeleteAll(properties);
	properties.clear();

	_jsObject.Clear();
	_jsObject.Dispose();
	_jsObjectTemplate.Clear();
	_jsObjectTemplate.Dispose();
}

void Ti::TiProxy::initStart()
{

}

void Ti::TiProxy::initWithObject(Handle<Object> obj)
{
	HandleScope scope;
	Local<Array> props = obj->GetPropertyNames();
	for(int i = 0, len = props->Length(); i < len; i++) {
		Local<String> key = props->Get(i)->ToString();
		Local<Value> val = obj->Get(key);
		_jsObject->Set(key, val);
	}
}

Ti::TiValue Ti::TiProxy::applyProperties(Ti::TiValue value)
{
	if(value.isMap())
	{
		initWithObject(value.toJSValue()->ToObject());
	}
	Ti::TiValue val;
	val.setUndefined();
	return val;
}

void Ti::TiProxy::initEnd()
{

}

const char* Ti::TiProxy::getProxyName()
{
	return _proxyName.toLocal8Bit().constData();
}

Handle<ObjectTemplate> Ti::TiProxy::getJSObjectTemplate() {
	return _jsObjectTemplate;
}

void Ti::TiProxy::addFunction(const char* name, InvocationCallback callback)
{
	_jsObject->ForceSet(String::New(name), FunctionTemplate::New(callback)->GetFunction(), DontDelete);

}
void Ti::TiProxy::createPropertyFunction(QString name, PROPERTY_FUNCTION callback)
{
	Ti::TiProperty::createFunction(this, name, callback);
}
void Ti::TiProxy::createPropertySetter(QString name, PROPERTY_SETTER callback)
{
	Ti::TiProperty::createSetter(this, name, callback);
}
void Ti::TiProxy::createPropertyGetter(QString name, PROPERTY_GETTER callback)
{
	Ti::TiProperty::createGetter(this, name, callback);
}
void Ti::TiProxy::createPropertySetterGetter(QString name, PROPERTY_SETTER setter, PROPERTY_GETTER getter)
{
	Ti::TiProperty::createProperty(this, name, setter, getter);
}

void Ti::TiProxy::onEventAdded(QString str)
{
	events.append(str);
	// for subclass
}
void Ti::TiProxy::onEventRemoved(QString str)
{
	if(events.contains(str)) {
		events.removeOne(str);
	}
	// for subclass
}

Ti::TiValue Ti::TiProxy::addEventListener(Ti::TiValue value)
{
	QString eventName;

	Ti::TiValue nameValue = value.toList().at(0);
	Ti::TiValue functionValue = value.toList().at(1);

	eventName = nameValue.toString();

	onEventAdded(eventName);

	Ti::TiEvent::AddEventToObject(_jsObject, eventName, Handle<Function>::Cast(functionValue.toJSValue()));

	Ti::TiValue res;
	res.setUndefined();
	return res;
}

Ti::TiValue Ti::TiProxy::removeEventListener(Ti::TiValue value)
{
	Ti::TiValue nameValue = value.toList().at(0);
	QString eventName = nameValue.toString();

	Ti::TiValue functionValue = value.toList().at(1);
	Handle<Function> func = Handle<Function>::Cast(functionValue.toJSValue());

	Ti::TiEvent::RemoveEventFromObject(_jsObject, eventName, func);
	Ti::TiValue res;
	res.setUndefined();
	return res;
}

// TODO: Finish this
Ti::TiValue Ti::TiProxy::fireEvent(Ti::TiValue value)
{
	QString eventName;
	Ti::TiEventParameters eventParams;
	if(value.isList()) {

		Ti::TiValue eName = value.toList().at(0);
		Ti::TiValue eParams = value.toList().at(1);
		eventName = eName.toString();

		if(eParams.isMap())
		{
			QMap<QString, Ti::TiValue> map = eParams.toMap();
			foreach(QString name, map.keys())
			{
				Ti::TiValue val 	= map[name];

				if(val.isNumber())
				{
					eventParams.addParam(name, val.toNumber());
				}
				else if (val.isProxy())
				{
					eventParams.addParam(name, val.toProxy());
				}
				else // if(val.isString())
				{
					eventParams.addParam(name, val.toString());
				}
			}
		}
	}
	else
	{
		eventName = value.toString();
	}

	fireEvent(eventName, eventParams);

	return Ti::TiValue(Undefined());
}

void Ti::TiProxy::fireCallback(QString eventName, Ti::TiEventParameters params)
{
	Ti::TiEvent::FireCallbackIfNeeded(eventName, _jsObject, &params);
}
void Ti::TiProxy::fireEvent(QString eventName, Ti::TiEventParameters params)
{
	HandleScope scope;
	if(events.contains(eventName)) {
		if(!params.contains("source"))
		{
			params.addParam("source", this);
		}
		if(!params.contains("type"))
		{
			params.addParam("type", eventName);
		}
		Ti::TiEvent::FireEventOnObject(_jsObject, eventName, &params);
	}
	if(eventName == Ti::TiConstants::EventClose)
	{
		Ti::TiHelper::LogInternal("Forcing GC");
		V8::LowMemoryNotification();
	}
}

Ti::TiValue Ti::TiProxy::getToString(Ti::TiValue)
{
	Ti::TiValue val;
	val.setString(QString("[object ").append(_proxyName).append("]"));
	return val;
}

Ti::TiValue Ti::TiProxy::getTiValueForKey(QString key)
{
	Handle<Value> val = _jsObject->Get(Ti::TiHelper::ValueFromQString(key));
	if(val.IsEmpty())
	{
		val = Undefined();
	}
	return Ti::TiValue(val);
}
void Ti::TiProxy::setTiValueForKey(Ti::TiValue value, QString key)
{
	_jsObject->Set(TiHelper::ValueFromQString(key), value.toJSValue());
}

void Ti::TiProxy::makeWeak()
{
	// if(_jsObject.IsEmpty()) return;
	// Ti::TiHelper::LogInternal(QString("Make weak ").append(QString(_proxyName)));
	_jsObject.MakeWeak(this, _WeakCallback);
}
void Ti::TiProxy::clearWeak()
{
	// if(_jsObject.IsEmpty()) return;
	// Ti::TiHelper::LogInternal(QString("Clear weak ").append(QString(_proxyName)));
	_jsObject.ClearWeak();
	_jsObjectTemplate.ClearWeak();
	_jsObject.MarkIndependent();
}

Handle<Value> Ti::TiProxy::_Getter (Local<String> property, const AccessorInfo& info)
{
	HandleScope handleScope;
	Handle<Object> obj = Handle<Object>::Cast(info.Holder());
	Handle<External> proxyObject = Handle<External>::Cast(obj->GetHiddenValue(String::New("module")));

	if(proxyObject.IsEmpty())
		proxyObject = Handle<External>::Cast(obj->GetHiddenValue(String::New("proxy")));

	if(proxyObject.IsEmpty())
		return handleScope.Close(Handle<Value>());

	Ti::TiProxy* tiProxy = static_cast<Ti::TiProxy*>(proxyObject->Value());

	if(tiProxy->properties.contains(Ti::TiHelper::QStringFromValue(property)))
	{
		Ti::TiProperty *prop = tiProxy->properties[Ti::TiHelper::QStringFromValue(property)];
		Handle<Value> r = prop->getValue();
		if(r.IsEmpty() || r->IsUndefined())
			return handleScope.Close(Handle<Value>());
		return handleScope.Close(r);
	}
	return handleScope.Close(Handle<Value>());
}

Handle<Value> Ti::TiProxy::_Setter (Local<String> property, Local<Value> value, const AccessorInfo& info)
{
	HandleScope handleScope;
	// Ti::TiHelper::LogInternal(QString("Property Setter: ").append(Ti::TiHelper::QStringFromValue(property)));

	// Todo: Come back to this later
	// if(value == info.Holder()->Get(property)) {
	//	 Ti::TiHelper::LogInternal(QString("Already set: ").append(Ti::TiHelper::QStringFromValue(property)));
	//	 return value;
	// }

	Handle<Object> obj = Handle<Object>::Cast(info.Holder());
	// Todo: come back to this - might not be allowing GC to collect proxies
	obj->ForceSet(property, value);
	// for example. scrollView.views = [a,b,c]
	// scrollView.remove(a) <--- removed from view, but still in array
	Handle<External> proxyObject = Handle<External>::Cast(obj->GetHiddenValue(String::New("module")));
	if(proxyObject.IsEmpty())
		proxyObject = Handle<External>::Cast(obj->GetHiddenValue(String::New("proxy")));

	if(proxyObject.IsEmpty())
		return value;

	Ti::TiProxy* tiProxy = static_cast<Ti::TiProxy*>(proxyObject->Value());
	if(tiProxy->properties.contains(Ti::TiHelper::QStringFromValue(property)))
	{

		Ti::TiProperty *prop = tiProxy->properties[Ti::TiHelper::QStringFromValue(property)];
		return handleScope.Close(prop->setValue(value));
	}

	return value;
}

void Ti::TiProxy::_WeakCallback(Persistent<Value>, void* parameter)
{
	Ti::TiProxy* obj = static_cast<Ti::TiProxy*>(parameter);
	delete obj;
	obj = NULL;
}
<|endoftext|>