<commit_before>#include "udpping.h"

#include <time.h>
#include <windows.h>
#include <mswsock.h>
#include <Mstcpip.h>
#include <pcap.h>

bool getAddress(const QString &address, sockaddr_any *addr);
PingProbe receiveLoop(pcap_t *capture, PingProbe probe, sockaddr_any destination);

UdpPing::UdpPing(QObject *parent)
    : Measurement(parent),
      currentStatus(Unknown)
{
    WSADATA wsaData;

    // Initialize Winsock
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        // TODO: emit error
    }
}

UdpPing::~UdpPing()
{
    WSACleanup();
}

Measurement::Status UdpPing::status() const
{
    return currentStatus;
}

void UdpPing::setStatus(Status status)
{
    if (currentStatus != status)
    {
        currentStatus = status;
        emit statusChanged(status);
    }
}

bool UdpPing::prepare(NetworkManager* networkManager, const MeasurementDefinitionPtr& measurementDefinition)
{
    Q_UNUSED(networkManager);

    pcap_if_t *alldevs;
    char errbuf[PCAP_ERRBUF_SIZE] = "";
    char source[PCAP_BUF_SIZE] = "";
    char address[16] = "";
    sockaddr_any dst_addr;
    unsigned long netmask;
    struct bpf_program fcode;

    definition = measurementDefinition.dynamicCast<UdpPingDefinition>();

    memset(&dst_addr, 0, sizeof(dst_addr));

    // translate domain name to IP address
    getAddress(definition->url, &dst_addr);
    dst_addr.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    strncpy(address, inet_ntoa(dst_addr.sin.sin_addr), sizeof(address));

    if (pcap_createsrcstr(source, PCAP_SRC_IFLOCAL, address, NULL, NULL, errbuf) != 0)
    {
        emit error("pcap_createsrcstr: " + QString(errbuf));
        return false;
    }

    if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) != 0)
    {
        emit error("pcap_findalldevs_ex: " + QString(errbuf));
        return false;
    }

    // take the first device
    m_device = alldevs;
    if (m_device == NULL)
    {
        emit error("pcap: no device found");
        return false;
    }

    // Open the device
    m_capture = pcap_open(m_device->name, 100, PCAP_OPENFLAG_NOCAPTURE_LOCAL, 2000, NULL, errbuf);
    if (m_capture == NULL)
    {
        emit error("pcap_open: " + QString(errbuf));
        return false;
    }

    // set filter
    if (m_device->addresses != NULL)
    {
        // Retrieve the mask of the first address of the interface
        netmask = ((struct sockaddr_in *) (m_device->addresses->netmask))->sin_addr.S_un.S_addr;
    } else
    {
        // If the interface is without an address we suppose to be in a C class network
        netmask = 0xffffff;
    }

    // capture only our UDP request and some ICMP responses
    QString filter = "(icmp and icmptype != icmp-echo) or (udp and dst host " + QString::fromLocal8Bit(address) + ")";
    if (pcap_compile(m_capture, &fcode, filter.toStdString().c_str(), 1, netmask) < 0)
    {
        pcap_freealldevs(alldevs);
        return false;
    }

    if (pcap_setfilter(m_capture, &fcode) < 0)
    {
        pcap_freealldevs(alldevs);
        return false;
    }

    // At this point, we don't need any more the device list. Free it
    pcap_freealldevs(alldevs);

    return true;
}

bool UdpPing::start()
{
    PingProbe probe;

    setStatus(UdpPing::Running);

    for (quint32 i = 0; i < definition->count; i++)
    {
        memset(&probe, 0, sizeof(probe));
        probe.sock = initSocket();
        if (probe.sock < 0)
        {
            emit error("initSocket");
            continue;
        }

        ping(&probe);
        closesocket(probe.sock);
        m_pingProbes.append(probe);
    }

    setStatus(UdpPing::Finished);
    emit finished();

    return true;
}

bool UdpPing::stop()
{
    return true;
}

ResultPtr UdpPing::result() const
{
    QVariantList res;

    foreach (const PingProbe &probe, m_pingProbes)
    {
        if (probe.sendTime > 0 && probe.recvTime > 0)
        {
            res << probe.recvTime - probe.sendTime;
        }
    }

    return ResultPtr(new Result(QDateTime::currentDateTime(), res, QVariant()));
}

int UdpPing::initSocket()
{
    int ttl = definition->ttl ? definition->ttl : 64;
    sockaddr_any src_addr;
    sockaddr_any dst_addr;
    SOCKET sock = INVALID_SOCKET;

    memset(&src_addr, 0, sizeof(src_addr));
    memset(&dst_addr, 0, sizeof(dst_addr));

    getAddress(definition->url, &dst_addr);
    dst_addr.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == INVALID_SOCKET)
    {
        // TODO: emit error
        return -1;
    }

    src_addr.sa.sa_family = AF_INET;
    src_addr.sin.sin_port = htons(definition->sourcePort);
    if (bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr)) != 0)
    {
        emit error("bind: " + QString(strerror(errno)));
        goto cleanup;
    }

    // set TTL
    if (setsockopt(sock, IPPROTO_IP, IP_TTL, (char *) &ttl, sizeof(ttl)) != 0)
    {
        emit error("setsockopt IP_TTL: " + QString(strerror(errno)));
        goto cleanup;
    }

    if (::connect(sock, (struct sockaddr *) &dst_addr, sizeof(dst_addr)) < 0)
    {
        emit error("connect: " + QString(strerror(errno)));
        goto cleanup;
    }

    return sock;

cleanup:
    closesocket(sock);
    return -1;
}

bool UdpPing::sendData(PingProbe *probe)
{
    if (send(probe->sock, definition->payload, sizeof(definition->payload), 0) < 0)
    {
        emit error("send: " + QString(strerror(errno)));
        return false;
    }
    return true;
}

void UdpPing::receiveData(PingProbe *probe)
{
    Q_UNUSED(probe);
}

void UdpPing::ping(PingProbe *probe)
{
    PingProbe result;
    QFuture<PingProbe> future;
    sockaddr_any dst_addr;

    // translate domain name to IP address
    getAddress(definition->url, &dst_addr);
    dst_addr.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);

    future = QtConcurrent::run(&receiveLoop, m_capture, *probe, dst_addr);

    if (sendData(probe))
    {
        future.waitForFinished();
        result = future.result();

        if (result.sendTime > 0 && result.recvTime > 0)
        {
            probe->sendTime = result.sendTime;
            probe->recvTime = result.recvTime;

            switch (result.response)
            {
            case DESTINATION_UNREACHABLE:
                emit destinationUnreachable(*probe);
                break;
            case TTL_EXCEEDED:
                emit ttlExceeded(*probe);
                break;
            case UNHANDLED_ICMP:
                emit error("Unhandled ICMP packet (type/code): " + QString::number(result.icmpType)
                           + "/" + QString::number(result.icmpCode));
                break;
            }

        } else if (result.sendTime == 0 && result.recvTime == 0)
        {
            emit error("timeout");
        } else
        {
            emit error("error receiving packets");
        }
    } else
    {
        emit error("error while sending");
    }
}

bool getAddress(const QString &address, sockaddr_any *addr)
{
    struct addrinfo hints;
    struct addrinfo *rp = NULL, *result = NULL;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_flags = AI_FQDN;

    if (getaddrinfo(address.toStdString().c_str(), NULL, &hints, &result))
    {
        return false;
    }

    for (rp = result; rp && rp->ai_family != AF_INET; rp = rp->ai_next)
    {
    }

    if (!rp)
    {
        rp = result;
    }

    memcpy(addr, rp->ai_addr, rp->ai_addrlen);

    freeaddrinfo(result);

    return true;
}

static PingProbe receiveLoop(pcap_t *capture, PingProbe probe, sockaddr_any destination)
{
    struct ipAddress
    {
        u_char byte1;
        u_char byte2;
        u_char byte3;
        u_char byte4;
    };

    int res;
    char sourceAddress[16] = "";
    char destinationAddress[16] = "";
    const u_char *data;
    pcap_pkthdr *header;
    ipAddress *source;
    quint8 *icmpType;
    quint8 *icmpCode;
    quint8 *ipProto;
    PingProbe newProbe;

    memcpy(&newProbe, &probe, sizeof(newProbe));

    for (;;)
    {
        res = pcap_next_ex(capture, &header, &data);

        ipProto = (quint8 *) (data + 23);
        source = (ipAddress *) (data + 26);
        icmpType = (quint8 *) (data + 34);
        icmpCode = (quint8 *) (data + 35);

        switch (res)
        {
        case 0:
            // timed out
            newProbe.sendTime = 0;
            newProbe.recvTime = 0;
            goto exit;
        case -1:
            // error indication
            goto error;
        default:
            // packets received
            // TODO: ensure the packets are really ours by checking them

            // source address of the response packet
            sprintf(sourceAddress, "%d.%d.%d.%d", source->byte1, source->byte2, source->byte3, source->byte4);
            // destination of request packet
            strncpy(destinationAddress, inet_ntoa(destination.sin.sin_addr), sizeof(destinationAddress));

            if (*ipProto == 17)
            {
                // UDP request
                newProbe.sendTime = header->ts.tv_sec * 1e6 + header->ts.tv_usec;
            } else if (*ipProto == 1)
            {
                // ICMP response
                if (*icmpCode == 3 && *icmpType == 3)
                {
                    // destination and port unreachable: this was a successful ping
                    if (strncmp(sourceAddress, destinationAddress, 16) == 0)
                    {
                        newProbe.recvTime = header->ts.tv_sec * 1e6 + header->ts.tv_usec;
                        newProbe.response = DESTINATION_UNREACHABLE;
                        goto exit;
                    }
                } else if (*icmpCode == 0 && *icmpType == 11)
                {
                    /*
                     * TTL exceeded
                     *
                     * Let's missuse source and sourceAddress for the destination of the original IP header.
                     */
                    source = (ipAddress *) (data + 76);
                    sprintf(sourceAddress, "%d.%d.%d.%d", source->byte1, source->byte2, source->byte3, source->byte4);

                    if (strncmp(sourceAddress, destinationAddress, 16) == 0)
                    {
                        newProbe.recvTime = header->ts.tv_sec * 1e6 + header->ts.tv_usec;
                        newProbe.response = TTL_EXCEEDED;
                        goto exit;
                    }
                } else
                {
                    /*
                     * An unhandled ICMP packet has been captured. We need to check this and
                     * handle it if needed.
                     */
                    newProbe.icmpType = *icmpType;
                    newProbe.icmpCode = *icmpCode;
                    newProbe.response = UNHANDLED_ICMP;
                    goto exit;
                }
            } else
            {
                /*
                 * This else-branch exists because of paranoia only.
                 * The WinPCAP filter is set to capture certain ICMP and UDP packets only
                 * and therefore should never end up here.
                 */
                goto error;
            }
        }
    }

error:
    // error indication
    newProbe.sendTime = -1;
    newProbe.recvTime = -1;

exit:
    return newProbe;
}

// vim: set sts=4 sw=4 et:
<commit_msg>satisfy code checker v2<commit_after>#include "udpping.h"

#include <time.h>
#include <windows.h>
#include <mswsock.h>
#include <Mstcpip.h>
#include <pcap.h>

bool getAddress(const QString &address, sockaddr_any *addr);
PingProbe receiveLoop(pcap_t *capture, PingProbe probe, sockaddr_any destination);

UdpPing::UdpPing(QObject *parent)
    : Measurement(parent),
      currentStatus(Unknown),
      m_device(NULL),
      m_capture(NULL)
{
    WSADATA wsaData;

    // Initialize Winsock
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        // TODO: emit error
    }
}

UdpPing::~UdpPing()
{
    WSACleanup();
}

Measurement::Status UdpPing::status() const
{
    return currentStatus;
}

void UdpPing::setStatus(Status status)
{
    if (currentStatus != status)
    {
        currentStatus = status;
        emit statusChanged(status);
    }
}

bool UdpPing::prepare(NetworkManager* networkManager, const MeasurementDefinitionPtr& measurementDefinition)
{
    Q_UNUSED(networkManager);

    pcap_if_t *alldevs;
    char errbuf[PCAP_ERRBUF_SIZE] = "";
    char source[PCAP_BUF_SIZE] = "";
    char address[16] = "";
    sockaddr_any dst_addr;
    unsigned long netmask;
    struct bpf_program fcode;

    definition = measurementDefinition.dynamicCast<UdpPingDefinition>();

    memset(&dst_addr, 0, sizeof(dst_addr));

    // translate domain name to IP address
    getAddress(definition->url, &dst_addr);
    dst_addr.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    strncpy(address, inet_ntoa(dst_addr.sin.sin_addr), sizeof(address));

    if (pcap_createsrcstr(source, PCAP_SRC_IFLOCAL, address, NULL, NULL, errbuf) != 0)
    {
        emit error("pcap_createsrcstr: " + QString(errbuf));
        return false;
    }

    if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) != 0)
    {
        emit error("pcap_findalldevs_ex: " + QString(errbuf));
        return false;
    }

    // take the first device
    m_device = alldevs;
    if (m_device == NULL)
    {
        emit error("pcap: no device found");
        return false;
    }

    // Open the device
    m_capture = pcap_open(m_device->name, 100, PCAP_OPENFLAG_NOCAPTURE_LOCAL, 2000, NULL, errbuf);
    if (m_capture == NULL)
    {
        emit error("pcap_open: " + QString(errbuf));
        return false;
    }

    // set filter
    if (m_device->addresses != NULL)
    {
        // Retrieve the mask of the first address of the interface
        netmask = ((struct sockaddr_in *) (m_device->addresses->netmask))->sin_addr.S_un.S_addr;
    } else
    {
        // If the interface is without an address we suppose to be in a C class network
        netmask = 0xffffff;
    }

    // capture only our UDP request and some ICMP responses
    QString filter = "(icmp and icmptype != icmp-echo) or (udp and dst host " + QString::fromLocal8Bit(address) + ")";
    if (pcap_compile(m_capture, &fcode, filter.toStdString().c_str(), 1, netmask) < 0)
    {
        pcap_freealldevs(alldevs);
        return false;
    }

    if (pcap_setfilter(m_capture, &fcode) < 0)
    {
        pcap_freealldevs(alldevs);
        return false;
    }

    // At this point, we don't need any more the device list. Free it
    pcap_freealldevs(alldevs);

    return true;
}

bool UdpPing::start()
{
    PingProbe probe;

    setStatus(UdpPing::Running);

    for (quint32 i = 0; i < definition->count; i++)
    {
        memset(&probe, 0, sizeof(probe));
        probe.sock = initSocket();
        if (probe.sock < 0)
        {
            emit error("initSocket");
            continue;
        }

        ping(&probe);
        closesocket(probe.sock);
        m_pingProbes.append(probe);
    }

    setStatus(UdpPing::Finished);
    emit finished();

    return true;
}

bool UdpPing::stop()
{
    return true;
}

ResultPtr UdpPing::result() const
{
    QVariantList res;

    foreach (const PingProbe &probe, m_pingProbes)
    {
        if (probe.sendTime > 0 && probe.recvTime > 0)
        {
            res << probe.recvTime - probe.sendTime;
        }
    }

    return ResultPtr(new Result(QDateTime::currentDateTime(), res, QVariant()));
}

int UdpPing::initSocket()
{
    int ttl = definition->ttl ? definition->ttl : 64;
    sockaddr_any src_addr;
    sockaddr_any dst_addr;
    SOCKET sock = INVALID_SOCKET;

    memset(&src_addr, 0, sizeof(src_addr));
    memset(&dst_addr, 0, sizeof(dst_addr));

    getAddress(definition->url, &dst_addr);
    dst_addr.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == INVALID_SOCKET)
    {
        // TODO: emit error
        return -1;
    }

    src_addr.sa.sa_family = AF_INET;
    src_addr.sin.sin_port = htons(definition->sourcePort);
    if (bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr)) != 0)
    {
        emit error("bind: " + QString(strerror(errno)));
        goto cleanup;
    }

    // set TTL
    if (setsockopt(sock, IPPROTO_IP, IP_TTL, (char *) &ttl, sizeof(ttl)) != 0)
    {
        emit error("setsockopt IP_TTL: " + QString(strerror(errno)));
        goto cleanup;
    }

    if (::connect(sock, (struct sockaddr *) &dst_addr, sizeof(dst_addr)) < 0)
    {
        emit error("connect: " + QString(strerror(errno)));
        goto cleanup;
    }

    return sock;

cleanup:
    closesocket(sock);
    return -1;
}

bool UdpPing::sendData(PingProbe *probe)
{
    if (send(probe->sock, definition->payload, sizeof(definition->payload), 0) < 0)
    {
        emit error("send: " + QString(strerror(errno)));
        return false;
    }
    return true;
}

void UdpPing::receiveData(PingProbe *probe)
{
    Q_UNUSED(probe);
}

void UdpPing::ping(PingProbe *probe)
{
    PingProbe result;
    QFuture<PingProbe> future;
    sockaddr_any dst_addr;

    // translate domain name to IP address
    getAddress(definition->url, &dst_addr);
    dst_addr.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);

    future = QtConcurrent::run(&receiveLoop, m_capture, *probe, dst_addr);

    if (sendData(probe))
    {
        future.waitForFinished();
        result = future.result();

        if (result.sendTime > 0 && result.recvTime > 0)
        {
            probe->sendTime = result.sendTime;
            probe->recvTime = result.recvTime;

            switch (result.response)
            {
            case DESTINATION_UNREACHABLE:
                emit destinationUnreachable(*probe);
                break;
            case TTL_EXCEEDED:
                emit ttlExceeded(*probe);
                break;
            case UNHANDLED_ICMP:
                emit error("Unhandled ICMP packet (type/code): " + QString::number(result.icmpType)
                           + "/" + QString::number(result.icmpCode));
                break;
            }

        } else if (result.sendTime == 0 && result.recvTime == 0)
        {
            emit error("timeout");
        } else
        {
            emit error("error receiving packets");
        }
    } else
    {
        emit error("error while sending");
    }
}

bool getAddress(const QString &address, sockaddr_any *addr)
{
    struct addrinfo hints;
    struct addrinfo *rp = NULL, *result = NULL;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_flags = AI_FQDN;

    if (getaddrinfo(address.toStdString().c_str(), NULL, &hints, &result))
    {
        return false;
    }

    for (rp = result; rp && rp->ai_family != AF_INET; rp = rp->ai_next)
    {
    }

    if (!rp)
    {
        rp = result;
    }

    memcpy(addr, rp->ai_addr, rp->ai_addrlen);

    freeaddrinfo(result);

    return true;
}

static PingProbe receiveLoop(pcap_t *capture, PingProbe probe, sockaddr_any destination)
{
    struct ipAddress
    {
        u_char byte1;
        u_char byte2;
        u_char byte3;
        u_char byte4;
    };

    int res;
    char sourceAddress[16] = "";
    char destinationAddress[16] = "";
    const u_char *data;
    pcap_pkthdr *header;
    ipAddress *source;
    quint8 *icmpType;
    quint8 *icmpCode;
    quint8 *ipProto;
    PingProbe newProbe;

    memcpy(&newProbe, &probe, sizeof(newProbe));

    for (;;)
    {
        res = pcap_next_ex(capture, &header, &data);

        ipProto = (quint8 *) (data + 23);
        source = (ipAddress *) (data + 26);
        icmpType = (quint8 *) (data + 34);
        icmpCode = (quint8 *) (data + 35);

        switch (res)
        {
        case 0:
            // timed out
            newProbe.sendTime = 0;
            newProbe.recvTime = 0;
            goto exit;
        case -1:
            // error indication
            goto error;
        default:
            // packets received
            // TODO: ensure the packets are really ours by checking them

            // source address of the response packet
            sprintf(sourceAddress, "%d.%d.%d.%d", source->byte1, source->byte2, source->byte3, source->byte4);
            // destination of request packet
            strncpy(destinationAddress, inet_ntoa(destination.sin.sin_addr), sizeof(destinationAddress));

            if (*ipProto == 17)
            {
                // UDP request
                newProbe.sendTime = header->ts.tv_sec * 1e6 + header->ts.tv_usec;
            } else if (*ipProto == 1)
            {
                // ICMP response
                if (*icmpCode == 3 && *icmpType == 3)
                {
                    // destination and port unreachable: this was a successful ping
                    if (strncmp(sourceAddress, destinationAddress, 16) == 0)
                    {
                        newProbe.recvTime = header->ts.tv_sec * 1e6 + header->ts.tv_usec;
                        newProbe.response = DESTINATION_UNREACHABLE;
                        goto exit;
                    }
                } else if (*icmpCode == 0 && *icmpType == 11)
                {
                    /*
                     * TTL exceeded
                     *
                     * Let's missuse source and sourceAddress for the destination of the original IP header.
                     */
                    source = (ipAddress *) (data + 76);
                    sprintf(sourceAddress, "%d.%d.%d.%d", source->byte1, source->byte2, source->byte3, source->byte4);

                    if (strncmp(sourceAddress, destinationAddress, 16) == 0)
                    {
                        newProbe.recvTime = header->ts.tv_sec * 1e6 + header->ts.tv_usec;
                        newProbe.response = TTL_EXCEEDED;
                        goto exit;
                    }
                } else
                {
                    /*
                     * An unhandled ICMP packet has been captured. We need to check this and
                     * handle it if needed.
                     */
                    newProbe.icmpType = *icmpType;
                    newProbe.icmpCode = *icmpCode;
                    newProbe.response = UNHANDLED_ICMP;
                    goto exit;
                }
            } else
            {
                /*
                 * This else-branch exists because of paranoia only.
                 * The WinPCAP filter is set to capture certain ICMP and UDP packets only
                 * and therefore should never end up here.
                 */
                goto error;
            }
        }
    }

error:
    // error indication
    newProbe.sendTime = -1;
    newProbe.recvTime = -1;

exit:
    return newProbe;
}

// vim: set sts=4 sw=4 et:
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace {

// Used to block until a dev tools client window's browser is closed.
class BrowserClosedObserver : public NotificationObserver {
 public:
  BrowserClosedObserver(Browser* browser) {
    registrar_.Add(this, NotificationType::BROWSER_CLOSED,
                   Source<Browser>(browser));
    ui_test_utils::RunMessageLoop();
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    MessageLoopForUI::current()->Quit();
  }

 private:
  NotificationRegistrar registrar_;
  DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver);
};

// The delay waited in some cases where we don't have a notifications for an
// action we take.
const int kActionDelayMs = 500;

const wchar_t kSimplePage[] = L"files/devtools/simple_page.html";
const wchar_t kJsPage[] = L"files/devtools/js_page.html";
const wchar_t kDebuggerTestPage[] = L"files/devtools/debugger_test_page.html";

class DevToolsSanityTest : public InProcessBrowserTest {
 public:
  DevToolsSanityTest() {
    set_show_window(true);
    EnableDOMAutomation();
  }

 protected:
  void RunTest(const std::string& test_name, const std::wstring& test_page) {
    OpenDevToolsWindow(test_page);
    std::string result;
    ASSERT_TRUE(
        ui_test_utils::ExecuteJavaScriptAndExtractString(
            client_contents_,
            L"",
            UTF8ToWide(StringPrintf("uiTests.runTest('%s')", test_name.c_str())),
            &result));
    EXPECT_EQ("[OK]", result);
    CloseDevToolsWindow();
  }

  void OpenDevToolsWindow(const std::wstring& test_page) {
    HTTPTestServer* server = StartHTTPServer();
    GURL url = server->TestServerPageW(test_page);
    ui_test_utils::NavigateToURL(browser(), url);

    TabContents* tab = browser()->GetTabContentsAt(0);
    inspected_rvh_ = tab->render_view_host();
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->OpenDevToolsWindow(inspected_rvh_);

    DevToolsClientHost* client_host =
        devtools_manager->GetDevToolsClientHostFor(inspected_rvh_);
    window_ = client_host->AsDevToolsWindow();
    RenderViewHost* client_rvh = window_->GetRenderViewHost();
    client_contents_ = client_rvh->delegate()->GetAsTabContents();
    ui_test_utils::WaitForNavigation(&client_contents_->controller());
  }

  void CloseDevToolsWindow() {
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_);
    BrowserClosedObserver close_observer(window_->browser());
  }

  TabContents* client_contents_;
  DevToolsWindow* window_;
  RenderViewHost* inspected_rvh_;
};

// WebInspector opens.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHostIsPresent) {
  RunTest("testHostIsPresent", kSimplePage);
}

// Tests elements panel basics.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestElementsTreeRoot) {
  RunTest("testElementsTreeRoot", kSimplePage);
}

// Tests main resource load.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestMainResource) {
  RunTest("testMainResource", kSimplePage);
}

// Tests resources panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestEnableResourcesTab) {
  RunTest("testEnableResourcesTab", kSimplePage);
}

// Tests profiler panel.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestProfilerTab) {
  RunTest("testProfilerTab", kJsPage);
}

// Tests scripta panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestEnableScriptsTab) {
  RunTest("testEnableScriptsTab", kDebuggerTestPage);
}

}  // namespace
<commit_msg>DevTools: fix debugger test, reenable debugger and resources tests.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace {

// Used to block until a dev tools client window's browser is closed.
class BrowserClosedObserver : public NotificationObserver {
 public:
  BrowserClosedObserver(Browser* browser) {
    registrar_.Add(this, NotificationType::BROWSER_CLOSED,
                   Source<Browser>(browser));
    ui_test_utils::RunMessageLoop();
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    MessageLoopForUI::current()->Quit();
  }

 private:
  NotificationRegistrar registrar_;
  DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver);
};

// The delay waited in some cases where we don't have a notifications for an
// action we take.
const int kActionDelayMs = 500;

const wchar_t kSimplePage[] = L"files/devtools/simple_page.html";
const wchar_t kJsPage[] = L"files/devtools/js_page.html";
const wchar_t kDebuggerTestPage[] = L"files/devtools/debugger_test_page.html";

class DevToolsSanityTest : public InProcessBrowserTest {
 public:
  DevToolsSanityTest() {
    set_show_window(true);
    EnableDOMAutomation();
  }

 protected:
  void RunTest(const std::string& test_name, const std::wstring& test_page) {
    OpenDevToolsWindow(test_page);
    std::string result;
    ASSERT_TRUE(
        ui_test_utils::ExecuteJavaScriptAndExtractString(
            client_contents_,
            L"",
            UTF8ToWide(StringPrintf("uiTests.runTest('%s')", test_name.c_str())),
            &result));
    EXPECT_EQ("[OK]", result);
    CloseDevToolsWindow();
  }

  void OpenDevToolsWindow(const std::wstring& test_page) {
    HTTPTestServer* server = StartHTTPServer();
    GURL url = server->TestServerPageW(test_page);
    ui_test_utils::NavigateToURL(browser(), url);

    TabContents* tab = browser()->GetTabContentsAt(0);
    inspected_rvh_ = tab->render_view_host();
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->OpenDevToolsWindow(inspected_rvh_);

    DevToolsClientHost* client_host =
        devtools_manager->GetDevToolsClientHostFor(inspected_rvh_);
    window_ = client_host->AsDevToolsWindow();
    RenderViewHost* client_rvh = window_->GetRenderViewHost();
    client_contents_ = client_rvh->delegate()->GetAsTabContents();
    ui_test_utils::WaitForNavigation(&client_contents_->controller());
  }

  void CloseDevToolsWindow() {
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_);
    BrowserClosedObserver close_observer(window_->browser());
  }

  TabContents* client_contents_;
  DevToolsWindow* window_;
  RenderViewHost* inspected_rvh_;
};

// WebInspector opens.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHostIsPresent) {
  RunTest("testHostIsPresent", kSimplePage);
}

// Tests elements panel basics.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestElementsTreeRoot) {
  RunTest("testElementsTreeRoot", kSimplePage);
}

// Tests main resource load.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestMainResource) {
  RunTest("testMainResource", kSimplePage);
}

// Tests resources panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEnableResourcesTab) {
  RunTest("testEnableResourcesTab", kSimplePage);
}

// Tests profiler panel.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestProfilerTab) {
  RunTest("testProfilerTab", kJsPage);
}

// Tests scripts panel showing.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) {
  RunTest("testShowScriptsTab", kDebuggerTestPage);
}

}  // namespace
<|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 <deque>
#include <string>

#include <process/defer.hpp>
#include <process/dispatch.hpp>
#include <process/future.hpp>
#include <process/help.hpp>
#include <process/http.hpp>
#include <process/id.hpp>
#include <process/owned.hpp>
#include <process/process.hpp>

#include <process/metrics/gauge.hpp>
#include <process/metrics/metrics.hpp>
#include <process/metrics/timer.hpp>

#include <stout/lambda.hpp>
#include <stout/none.hpp>
#include <stout/nothing.hpp>
#include <stout/option.hpp>
#include <stout/protobuf.hpp>

#include "common/type_utils.hpp"

#include "master/registrar.hpp"
#include "master/registry.hpp"

#include "state/protobuf.hpp"

using mesos::internal::state::protobuf::State;
using mesos::internal::state::protobuf::Variable;

using process::dispatch;
using process::spawn;
using process::terminate;
using process::wait; // Necessary on some OS's to disambiguate.

using process::DESCRIPTION;
using process::Failure;
using process::Future;
using process::HELP;
using process::Owned;
using process::Process;
using process::Promise;
using process::TLDR;
using process::USAGE;

using process::http::OK;

using process::metrics::Gauge;
using process::metrics::Timer;

using std::deque;
using std::string;

namespace mesos {
namespace internal {
namespace master {

using process::http::Response;
using process::http::Request;

class RegistrarProcess : public Process<RegistrarProcess>
{
public:
  RegistrarProcess(const Flags& _flags, State* _state)
    : ProcessBase(process::ID::generate("registrar")),
      metrics(*this),
      updating(false),
      flags(_flags),
      state(_state) {}

  virtual ~RegistrarProcess() {}

  // Registrar implementation.
  Future<Registry> recover(const MasterInfo& info);
  Future<bool> apply(Owned<Operation> operation);

protected:
  virtual void initialize()
  {
    route("/registry", registryHelp(), &RegistrarProcess::registry);
  }

private:
  // HTTP handlers.
  // /registrar(N)/registry
  Future<Response> registry(const Request& request);
  static string registryHelp();

  // The 'Recover' operation adds the latest MasterInfo.
  class Recover : public Operation
  {
  public:
    explicit Recover(const MasterInfo& _info) : info(_info) {}

  protected:
    virtual Try<bool> perform(
        Registry* registry,
        hashset<SlaveID>* slaveIDs,
        bool strict)
    {
      registry->mutable_master()->mutable_info()->CopyFrom(info);
      return true; // Mutation.
    }

  private:
    const MasterInfo info;
  };

  // Metrics.
  struct Metrics
  {
    explicit Metrics(const RegistrarProcess& process)
      : queued_operations(
            "registrar/queued_operations",
            defer(process, &RegistrarProcess::_queued_operations)),
        registry_size_bytes(
            "registrar/registry_size_bytes",
            defer(process, &RegistrarProcess::_registry_size_bytes)),
        state_fetch("registrar/state_fetch"),
        state_store("registrar/state_store", Days(1))
    {
      process::metrics::add(queued_operations);
      process::metrics::add(registry_size_bytes);

      process::metrics::add(state_fetch);
      process::metrics::add(state_store);
    }

    ~Metrics()
    {
      process::metrics::remove(queued_operations);
      process::metrics::remove(registry_size_bytes);

      process::metrics::remove(state_fetch);
      process::metrics::remove(state_store);
    }

    Gauge queued_operations;
    Gauge registry_size_bytes;

    Timer<Milliseconds> state_fetch;
    Timer<Milliseconds> state_store;
  } metrics;

  // Gauge handlers
  double _queued_operations()
  {
    return operations.size();
  }

  Future<double> _registry_size_bytes()
  {
    if (variable.isSome()) {
      return variable.get().get().ByteSize();
    }

    return Failure("Not recovered yet");
  }

  // Continuations.
  void _recover(
      const MasterInfo& info,
      const Future<Variable<Registry> >& recovery);
  void __recover(const Future<bool>& recover);
  Future<bool> _apply(Owned<Operation> operation);

  // Helper for updating state (performing store).
  void update();
  void _update(
      const Future<Option<Variable<Registry> > >& store,
      deque<Owned<Operation> > operations);

  // Fails all pending operations and transitions the Registrar
  // into an error state in which all subsequent operations will fail.
  // This ensures we don't attempt to re-acquire log leadership by
  // performing more State storage operations.
  void abort(const string& message);

  Option<Variable<Registry> > variable;
  deque<Owned<Operation> > operations;
  bool updating; // Used to signify fetching (recovering) or storing.

  const Flags flags;
  State* state;

  // Used to compose our operations with recovery.
  Option<Owned<Promise<Registry> > > recovered;

  // When an error is encountered from abort(), we'll fail all
  // subsequent operations.
  Option<Error> error;
};

// Helper for treating State operations that timeout as failures.
template <typename T>
Future<T> timeout(
    const string& operation,
    const Duration& duration,
    Future<T> future)
{
  future.discard();

  return Failure(
      "Failed to perform " + operation + " within " + stringify(duration));
}

// Helper for failing a deque of operations.
void fail(deque<Owned<Operation> >* operations, const string& message)
{
  while (!operations->empty()) {
    const Owned<Operation>& operation = operations->front();
    operations->pop_front();

    operation->fail(message);
  }
}

Future<Response> RegistrarProcess::registry(const Request& request)
{
  JSON::Object result;

  if (variable.isSome()) {
    result = JSON::Protobuf(variable.get().get());
  }

  return OK(result, request.query.get("jsonp"));
}

string RegistrarProcess::registryHelp()
{
  return HELP(
      TLDR(
          "Returns the current contents of the Registry in JSON."),
      USAGE(
          "/registrar(1)/registry"),
      DESCRIPTION(
          "Example:"
          "",
          "```",
          "{",
          "  \"master\":",
          "  {",
          "    \"info\":",
          "    {",
          "      \"hostname\": \"localhost\",",
          "      \"id\": \"20140325-235542-1740121354-5050-33357\",",
          "      \"ip\": 2130706433,",
          "      \"pid\": \"master@127.0.0.1:5050\",",
          "      \"port\": 5050",
          "    }",
          "  },",
          "",
          "  \"slaves\":",
          "  {",
          "    \"slaves\":",
          "    [",
          "      {",
          "        \"info\":",
          "        {",
          "          \"checkpoint\": true,",
          "          \"hostname\": \"localhost\",",
          "          \"id\":",
          "          { ",
          "            \"value\": \"20140325-234618-1740121354-5050-29065-0\"",
          "          },",
          "          \"port\": 5051,",
          "          \"resources\":",
          "          [",
          "            {",
          "              \"name\": \"cpus\",",
          "              \"role\": \"*\",",
          "              \"scalar\": { \"value\": 24 },",
          "              \"type\": \"SCALAR\"",
          "            }",
          "          ],",
          "          \"webui_hostname\": \"localhost\"",
          "        }",
          "      }",
          "    ]",
          "  }",
          "}",
          "```"));
}

Future<Registry> RegistrarProcess::recover(const MasterInfo& info)
{
  if (recovered.isNone()) {
    LOG(INFO) << "Recovering registrar";

    metrics.state_fetch.time(state->fetch<Registry>("registry"))
      .after(flags.registry_fetch_timeout,
             lambda::bind(
                 &timeout<Variable<Registry> >,
                 "fetch",
                 flags.registry_fetch_timeout,
                 lambda::_1))
      .onAny(defer(self(), &Self::_recover, info, lambda::_1));
    updating = true;
    recovered = Owned<Promise<Registry> >(new Promise<Registry>());
  }

  return recovered.get()->future();
}

void RegistrarProcess::_recover(
    const MasterInfo& info,
    const Future<Variable<Registry> >& recovery)
{
  updating = false;

  CHECK(!recovery.isPending());

  if (!recovery.isReady()) {
    recovered.get()->fail("Failed to recover registrar: " +
        (recovery.isFailed() ? recovery.failure() : "discarded"));
  } else {
    // Save the registry.
    variable = recovery.get();

    LOG(INFO) << "Successfully fetched the registry "
              << "(" << Bytes(variable.get().get().ByteSize()) << ")";

    // Perform the Recover operation to add the new MasterInfo.
    Owned<Operation> operation(new Recover(info));
    operations.push_back(operation);
    operation->future()
      .onAny(defer(self(), &Self::__recover, lambda::_1));

    update();
  }
}

void RegistrarProcess::__recover(const Future<bool>& recover)
{
  CHECK(!recover.isPending());

  if (!recover.isReady()) {
    recovered.get()->fail("Failed to recover registrar: "
        "Failed to persist MasterInfo: " +
        (recover.isFailed() ? recover.failure() : "discarded"));
  } else if (!recover.get()) {
    recovered.get()->fail("Failed to recover registrar: "
        "Failed to persist MasterInfo: version mismatch");
  } else {
    LOG(INFO) << "Successfully recovered registrar";

    // At this point _update() has updated 'variable' to contain
    // the Registry with the latest MasterInfo.
    // Set the promise and un-gate any pending operations.
    CHECK_SOME(variable);
    recovered.get()->set(variable.get().get());
  }
}

Future<bool> RegistrarProcess::apply(Owned<Operation> operation)
{
  if (recovered.isNone()) {
    return Failure("Attempted to apply the operation before recovering");
  }

  return recovered.get()->future()
    .then(defer(self(), &Self::_apply, operation));
}

Future<bool> RegistrarProcess::_apply(Owned<Operation> operation)
{
  if (error.isSome()) {
    return Failure(error.get());
  }

  CHECK_SOME(variable);

  operations.push_back(operation);
  Future<bool> future = operation->future();
  if (!updating) {
    update();
  }
  return future;
}

void RegistrarProcess::update()
{
  if (operations.empty()) {
    return; // No-op.
  }

  CHECK(!updating);
  CHECK(error.isNone());

  updating = true;

  LOG(INFO) << "Attempting to update the 'registry'";

  CHECK_SOME(variable);

  // Create a snapshot of the current registry.
  Registry registry = variable.get().get();

  // Create the 'slaveIDs' accumulator.
  hashset<SlaveID> slaveIDs;
  foreach (const Registry::Slave& slave, registry.slaves().slaves()) {
    slaveIDs.insert(slave.info().id());
  }

  foreach (Owned<Operation> operation, operations) {
    // No need to process the result of the operation.
    (*operation)(&registry, &slaveIDs, flags.registry_strict);
  }

  // Perform the store, and time the operation.
  metrics.state_store.time(state->store(variable.get().mutate(registry)))
    .after(flags.registry_store_timeout,
           lambda::bind(
               &timeout<Option<Variable<Registry> > >,
               "store",
               flags.registry_store_timeout,
               lambda::_1))
    .onAny(defer(self(), &Self::_update, lambda::_1, operations));

  // Clear the operations, _update will transition the Promises!
  operations.clear();
}

void RegistrarProcess::_update(
    const Future<Option<Variable<Registry> > >& store,
    deque<Owned<Operation> > applied)
{
  updating = false;

  // Abort if the storage operation did not succeed.
  if (!store.isReady() || store.get().isNone()) {
    string message = "Failed to update 'registry': ";

    if (store.isFailed()) {
      message += store.failure();
    } else if (store.isDiscarded()) {
      message += "discarded";
    } else {
      message += "version mismatch";
    }

    fail(&applied, message);
    abort(message);

    return;
  }

  LOG(INFO) << "Successfully updated 'registry'";
  variable = store.get().get();

  // Remove the operations.
  while (!applied.empty()) {
    Owned<Operation> operation = applied.front();
    applied.pop_front();

    operation->set();
  }

  if (!operations.empty()) {
    update();
  }
}

void RegistrarProcess::abort(const string& message)
{
  error = Error(message);

  LOG(ERROR) << "Registrar aborting: " << message;

  fail(&operations, message);
}

Registrar::Registrar(const Flags& flags, State* state)
{
  process = new RegistrarProcess(flags, state);
  spawn(process);
}

Registrar::~Registrar()
{
  terminate(process);
  wait(process);
  delete process;
}

Future<Registry> Registrar::recover(const MasterInfo& info)
{
  return dispatch(process, &RegistrarProcess::recover, info);
}

Future<bool> Registrar::apply(Owned<Operation> operation)
{
  return dispatch(process, &RegistrarProcess::apply, operation);
}

} // namespace master {
} // namespace internal {
} // namespace mesos {
<commit_msg>MESOS-1376: Fixed an invalid reference in the Registrar.<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 <deque>
#include <string>

#include <process/defer.hpp>
#include <process/dispatch.hpp>
#include <process/future.hpp>
#include <process/help.hpp>
#include <process/http.hpp>
#include <process/id.hpp>
#include <process/owned.hpp>
#include <process/process.hpp>

#include <process/metrics/gauge.hpp>
#include <process/metrics/metrics.hpp>
#include <process/metrics/timer.hpp>

#include <stout/lambda.hpp>
#include <stout/none.hpp>
#include <stout/nothing.hpp>
#include <stout/option.hpp>
#include <stout/protobuf.hpp>

#include "common/type_utils.hpp"

#include "master/registrar.hpp"
#include "master/registry.hpp"

#include "state/protobuf.hpp"

using mesos::internal::state::protobuf::State;
using mesos::internal::state::protobuf::Variable;

using process::dispatch;
using process::spawn;
using process::terminate;
using process::wait; // Necessary on some OS's to disambiguate.

using process::DESCRIPTION;
using process::Failure;
using process::Future;
using process::HELP;
using process::Owned;
using process::Process;
using process::Promise;
using process::TLDR;
using process::USAGE;

using process::http::OK;

using process::metrics::Gauge;
using process::metrics::Timer;

using std::deque;
using std::string;

namespace mesos {
namespace internal {
namespace master {

using process::http::Response;
using process::http::Request;

class RegistrarProcess : public Process<RegistrarProcess>
{
public:
  RegistrarProcess(const Flags& _flags, State* _state)
    : ProcessBase(process::ID::generate("registrar")),
      metrics(*this),
      updating(false),
      flags(_flags),
      state(_state) {}

  virtual ~RegistrarProcess() {}

  // Registrar implementation.
  Future<Registry> recover(const MasterInfo& info);
  Future<bool> apply(Owned<Operation> operation);

protected:
  virtual void initialize()
  {
    route("/registry", registryHelp(), &RegistrarProcess::registry);
  }

private:
  // HTTP handlers.
  // /registrar(N)/registry
  Future<Response> registry(const Request& request);
  static string registryHelp();

  // The 'Recover' operation adds the latest MasterInfo.
  class Recover : public Operation
  {
  public:
    explicit Recover(const MasterInfo& _info) : info(_info) {}

  protected:
    virtual Try<bool> perform(
        Registry* registry,
        hashset<SlaveID>* slaveIDs,
        bool strict)
    {
      registry->mutable_master()->mutable_info()->CopyFrom(info);
      return true; // Mutation.
    }

  private:
    const MasterInfo info;
  };

  // Metrics.
  struct Metrics
  {
    explicit Metrics(const RegistrarProcess& process)
      : queued_operations(
            "registrar/queued_operations",
            defer(process, &RegistrarProcess::_queued_operations)),
        registry_size_bytes(
            "registrar/registry_size_bytes",
            defer(process, &RegistrarProcess::_registry_size_bytes)),
        state_fetch("registrar/state_fetch"),
        state_store("registrar/state_store", Days(1))
    {
      process::metrics::add(queued_operations);
      process::metrics::add(registry_size_bytes);

      process::metrics::add(state_fetch);
      process::metrics::add(state_store);
    }

    ~Metrics()
    {
      process::metrics::remove(queued_operations);
      process::metrics::remove(registry_size_bytes);

      process::metrics::remove(state_fetch);
      process::metrics::remove(state_store);
    }

    Gauge queued_operations;
    Gauge registry_size_bytes;

    Timer<Milliseconds> state_fetch;
    Timer<Milliseconds> state_store;
  } metrics;

  // Gauge handlers
  double _queued_operations()
  {
    return operations.size();
  }

  Future<double> _registry_size_bytes()
  {
    if (variable.isSome()) {
      return variable.get().get().ByteSize();
    }

    return Failure("Not recovered yet");
  }

  // Continuations.
  void _recover(
      const MasterInfo& info,
      const Future<Variable<Registry> >& recovery);
  void __recover(const Future<bool>& recover);
  Future<bool> _apply(Owned<Operation> operation);

  // Helper for updating state (performing store).
  void update();
  void _update(
      const Future<Option<Variable<Registry> > >& store,
      deque<Owned<Operation> > operations);

  // Fails all pending operations and transitions the Registrar
  // into an error state in which all subsequent operations will fail.
  // This ensures we don't attempt to re-acquire log leadership by
  // performing more State storage operations.
  void abort(const string& message);

  Option<Variable<Registry> > variable;
  deque<Owned<Operation> > operations;
  bool updating; // Used to signify fetching (recovering) or storing.

  const Flags flags;
  State* state;

  // Used to compose our operations with recovery.
  Option<Owned<Promise<Registry> > > recovered;

  // When an error is encountered from abort(), we'll fail all
  // subsequent operations.
  Option<Error> error;
};

// Helper for treating State operations that timeout as failures.
template <typename T>
Future<T> timeout(
    const string& operation,
    const Duration& duration,
    Future<T> future)
{
  future.discard();

  return Failure(
      "Failed to perform " + operation + " within " + stringify(duration));
}

// Helper for failing a deque of operations.
void fail(deque<Owned<Operation> >* operations, const string& message)
{
  while (!operations->empty()) {
    Owned<Operation> operation = operations->front();
    operations->pop_front();

    operation->fail(message);
  }
}

Future<Response> RegistrarProcess::registry(const Request& request)
{
  JSON::Object result;

  if (variable.isSome()) {
    result = JSON::Protobuf(variable.get().get());
  }

  return OK(result, request.query.get("jsonp"));
}

string RegistrarProcess::registryHelp()
{
  return HELP(
      TLDR(
          "Returns the current contents of the Registry in JSON."),
      USAGE(
          "/registrar(1)/registry"),
      DESCRIPTION(
          "Example:"
          "",
          "```",
          "{",
          "  \"master\":",
          "  {",
          "    \"info\":",
          "    {",
          "      \"hostname\": \"localhost\",",
          "      \"id\": \"20140325-235542-1740121354-5050-33357\",",
          "      \"ip\": 2130706433,",
          "      \"pid\": \"master@127.0.0.1:5050\",",
          "      \"port\": 5050",
          "    }",
          "  },",
          "",
          "  \"slaves\":",
          "  {",
          "    \"slaves\":",
          "    [",
          "      {",
          "        \"info\":",
          "        {",
          "          \"checkpoint\": true,",
          "          \"hostname\": \"localhost\",",
          "          \"id\":",
          "          { ",
          "            \"value\": \"20140325-234618-1740121354-5050-29065-0\"",
          "          },",
          "          \"port\": 5051,",
          "          \"resources\":",
          "          [",
          "            {",
          "              \"name\": \"cpus\",",
          "              \"role\": \"*\",",
          "              \"scalar\": { \"value\": 24 },",
          "              \"type\": \"SCALAR\"",
          "            }",
          "          ],",
          "          \"webui_hostname\": \"localhost\"",
          "        }",
          "      }",
          "    ]",
          "  }",
          "}",
          "```"));
}

Future<Registry> RegistrarProcess::recover(const MasterInfo& info)
{
  if (recovered.isNone()) {
    LOG(INFO) << "Recovering registrar";

    metrics.state_fetch.time(state->fetch<Registry>("registry"))
      .after(flags.registry_fetch_timeout,
             lambda::bind(
                 &timeout<Variable<Registry> >,
                 "fetch",
                 flags.registry_fetch_timeout,
                 lambda::_1))
      .onAny(defer(self(), &Self::_recover, info, lambda::_1));
    updating = true;
    recovered = Owned<Promise<Registry> >(new Promise<Registry>());
  }

  return recovered.get()->future();
}

void RegistrarProcess::_recover(
    const MasterInfo& info,
    const Future<Variable<Registry> >& recovery)
{
  updating = false;

  CHECK(!recovery.isPending());

  if (!recovery.isReady()) {
    recovered.get()->fail("Failed to recover registrar: " +
        (recovery.isFailed() ? recovery.failure() : "discarded"));
  } else {
    // Save the registry.
    variable = recovery.get();

    LOG(INFO) << "Successfully fetched the registry "
              << "(" << Bytes(variable.get().get().ByteSize()) << ")";

    // Perform the Recover operation to add the new MasterInfo.
    Owned<Operation> operation(new Recover(info));
    operations.push_back(operation);
    operation->future()
      .onAny(defer(self(), &Self::__recover, lambda::_1));

    update();
  }
}

void RegistrarProcess::__recover(const Future<bool>& recover)
{
  CHECK(!recover.isPending());

  if (!recover.isReady()) {
    recovered.get()->fail("Failed to recover registrar: "
        "Failed to persist MasterInfo: " +
        (recover.isFailed() ? recover.failure() : "discarded"));
  } else if (!recover.get()) {
    recovered.get()->fail("Failed to recover registrar: "
        "Failed to persist MasterInfo: version mismatch");
  } else {
    LOG(INFO) << "Successfully recovered registrar";

    // At this point _update() has updated 'variable' to contain
    // the Registry with the latest MasterInfo.
    // Set the promise and un-gate any pending operations.
    CHECK_SOME(variable);
    recovered.get()->set(variable.get().get());
  }
}

Future<bool> RegistrarProcess::apply(Owned<Operation> operation)
{
  if (recovered.isNone()) {
    return Failure("Attempted to apply the operation before recovering");
  }

  return recovered.get()->future()
    .then(defer(self(), &Self::_apply, operation));
}

Future<bool> RegistrarProcess::_apply(Owned<Operation> operation)
{
  if (error.isSome()) {
    return Failure(error.get());
  }

  CHECK_SOME(variable);

  operations.push_back(operation);
  Future<bool> future = operation->future();
  if (!updating) {
    update();
  }
  return future;
}

void RegistrarProcess::update()
{
  if (operations.empty()) {
    return; // No-op.
  }

  CHECK(!updating);
  CHECK(error.isNone());

  updating = true;

  LOG(INFO) << "Attempting to update the 'registry'";

  CHECK_SOME(variable);

  // Create a snapshot of the current registry.
  Registry registry = variable.get().get();

  // Create the 'slaveIDs' accumulator.
  hashset<SlaveID> slaveIDs;
  foreach (const Registry::Slave& slave, registry.slaves().slaves()) {
    slaveIDs.insert(slave.info().id());
  }

  foreach (Owned<Operation> operation, operations) {
    // No need to process the result of the operation.
    (*operation)(&registry, &slaveIDs, flags.registry_strict);
  }

  // Perform the store, and time the operation.
  metrics.state_store.time(state->store(variable.get().mutate(registry)))
    .after(flags.registry_store_timeout,
           lambda::bind(
               &timeout<Option<Variable<Registry> > >,
               "store",
               flags.registry_store_timeout,
               lambda::_1))
    .onAny(defer(self(), &Self::_update, lambda::_1, operations));

  // Clear the operations, _update will transition the Promises!
  operations.clear();
}

void RegistrarProcess::_update(
    const Future<Option<Variable<Registry> > >& store,
    deque<Owned<Operation> > applied)
{
  updating = false;

  // Abort if the storage operation did not succeed.
  if (!store.isReady() || store.get().isNone()) {
    string message = "Failed to update 'registry': ";

    if (store.isFailed()) {
      message += store.failure();
    } else if (store.isDiscarded()) {
      message += "discarded";
    } else {
      message += "version mismatch";
    }

    fail(&applied, message);
    abort(message);

    return;
  }

  LOG(INFO) << "Successfully updated 'registry'";
  variable = store.get().get();

  // Remove the operations.
  while (!applied.empty()) {
    Owned<Operation> operation = applied.front();
    applied.pop_front();

    operation->set();
  }

  if (!operations.empty()) {
    update();
  }
}

void RegistrarProcess::abort(const string& message)
{
  error = Error(message);

  LOG(ERROR) << "Registrar aborting: " << message;

  fail(&operations, message);
}

Registrar::Registrar(const Flags& flags, State* state)
{
  process = new RegistrarProcess(flags, state);
  spawn(process);
}

Registrar::~Registrar()
{
  terminate(process);
  wait(process);
  delete process;
}

Future<Registry> Registrar::recover(const MasterInfo& info)
{
  return dispatch(process, &RegistrarProcess::recover, info);
}

Future<bool> Registrar::apply(Owned<Operation> operation)
{
  return dispatch(process, &RegistrarProcess::apply, operation);
}

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


<commit_before>#include <elves/factorize/BigInt.h>
#include <elves/factorize/cuda/Factorize.h>
#include <elves/factorize/cuda/NumberHelper.h>
#include <elves/cuda-utils/Memory.h>
#include <gtest/gtest.h>
#include <functional>
#include <cstdlib>

extern void testAdd(PNumData left, PNumData right, PNumData result);
extern void testSub(PNumData left, PNumData right, PNumData result);
extern void testMul(PNumData left, PNumData right, PNumData result);
extern void testDiv(PNumData left, PNumData right, PNumData result);
extern void testSmallerThan(PNumData left, PNumData right, bool* result);
extern void testShiftLeft(PNumData left, uint32_t offset, PNumData result);
extern void testShiftRight(PNumData left, uint32_t offset, PNumData result);

using namespace std;

BigInt invokeShiftKernel(const BigInt& left, const uint32_t right, function<void (PNumData, uint32_t, PNumData)> kernelCall)
{
    CudaUtils::Memory<uint32_t> left_d(NumberHelper::BigIntToNumber(left));
    CudaUtils::Memory<uint32_t> out_d(NUM_FIELDS);

    kernelCall(left_d.get(), right, out_d.get());
    return NumberHelper::NumberToBigInt(out_d);
}

bool invokeBoolKernel(const BigInt& left, const BigInt& right, function<void (PNumData, PNumData, bool*)> kernelCall)
{
    bool outputData;

    CudaUtils::Memory<uint32_t> left_d(NumberHelper::BigIntToNumber(left));
    CudaUtils::Memory<uint32_t> right_d(NumberHelper::BigIntToNumber(right));
    CudaUtils::Memory<bool> out_d(1);

    kernelCall(left_d.get(), right_d.get(), out_d.get());
    out_d.transferTo(&outputData);

    return outputData;
}

BigInt invokeKernel(const BigInt& left, const BigInt& right, function<void (PNumData, PNumData, PNumData)> kernelCall)
{
    CudaUtils::Memory<uint32_t> left_d(NumberHelper::BigIntToNumber(left));
    CudaUtils::Memory<uint32_t> right_d(NumberHelper::BigIntToNumber(right));
    CudaUtils::Memory<uint32_t> out_d(NUM_FIELDS);

    kernelCall(left_d.get(), right_d.get(), out_d.get());

    return NumberHelper::NumberToBigInt(out_d);
}

TEST(CudaBigIntTest, testMpzConversion)
{
    BigInt start("1231490623");
    NumData test;
    memset(test, 0, sizeof(uint32_t) * NUM_FIELDS);
    mpz_export(test, nullptr, -1, sizeof(uint32_t), 0, 0, start.get_mpz_t());
    BigInt compare;
    mpz_import(compare.get_mpz_t(), NUM_FIELDS, -1, sizeof(uint32_t), 0, 0, test);

    EXPECT_EQ(start, compare);
}

TEST(CudaBigIntTest, testAddition)
{
    BigInt left("12314906231232141243");
    BigInt right("21317833214213");
    BigInt expected("12314927549065355456");

    auto actual = invokeKernel(left, right, testAdd);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testSubtraction)
{
    BigInt left("90887891231490623");
    BigInt right("779789821317833");
    BigInt expected("90108101410172790");

    auto actual = invokeKernel(left, right, testSub);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testMultiplication)
{
    BigInt left("90887891231490623");
    BigInt right("779789821317833");
    BigInt expected("70873452463358713606126842179959");

    auto actual = invokeKernel(left, right,  testMul);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testMultiplicationSmallNumbers)
{
    BigInt left("5");
    BigInt right("8");
    BigInt expected("40");

    auto actual = invokeKernel(left, right,  testMul);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testDivision)
{
    BigInt left("90887891231490623");
    BigInt right("779789821317833");
    BigInt expected("116");

    auto actual = invokeKernel(left, right,  testDiv);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testDivisionEqualValues)
{
    BigInt left("90887891231490623");
    BigInt right("90887891231490623");
    BigInt expected("1");

    auto actual = invokeKernel(left, right,  testDiv);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testDivisionEqualOperands)
{
    BigInt left("90887891231490623");
    BigInt expected("1");

    auto actual = invokeKernel(left, left,  testDiv);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testSmallerThan)
{
    BigInt left("90887891231490623");
    BigInt right("7797822229821317833");
    bool expected(true);

    auto actual = invokeBoolKernel(left, right, testSmallerThan);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testNotSmallerThan)
{
    BigInt left("90887891231490624");
    BigInt right("90887891231490623");
    bool expected(false);

    auto actual = invokeBoolKernel(left, right, testSmallerThan);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testSmallerThanWithEqualOperands)
{
    BigInt left("90887891231490623");
    BigInt right("90887891231490623");
    bool expected(false);

    auto actual = invokeBoolKernel(left, right, testSmallerThan);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftLeft)
{
    BigInt left("1");
    uint32_t offset(32);
    BigInt expected("4294967296");

    auto actual = invokeShiftKernel(left, offset, testShiftLeft);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftLeftBiggerNumber)
{
    BigInt left("1282943598234");
    uint32_t offset(23);
    BigInt expected("10762110931694518272");

    auto actual = invokeShiftKernel(left, offset, testShiftLeft);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftLeftBiggerNumber2)
{
    BigInt left("1282943598234");
    uint32_t offset(3333);
    BigInt expected("0");

    auto actual = invokeShiftKernel(left, offset, testShiftLeft);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftRight)
{
    BigInt left("4294967296");
    uint32_t offset(32);
    BigInt expected("1");

    auto actual = invokeShiftKernel(left, offset, testShiftRight);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftRightBiggerNumber)
{
    BigInt left("1301820391234234234342");
    uint32_t offset(33);
    BigInt expected("151551839806");

    auto actual = invokeShiftKernel(left, offset, testShiftRight);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftRightBiggerNumber2)
{
    BigInt left("2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936575");
    uint32_t offset(33);
    BigInt expected("248661618204893321077691124073410420050228075398673858720231988446579748506266687766527");

    auto actual = invokeShiftKernel(left, offset, testShiftRight);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftRightOutrageousShiftOffset)
{
    BigInt left("1");
    uint32_t offset(33333);
    BigInt expected("0");

    auto actual = invokeShiftKernel(left, offset, testShiftRight);

    EXPECT_EQ(expected, actual);
}
<commit_msg>renamed cuda bigint testcase<commit_after>#include <elves/factorize/BigInt.h>
#include <elves/factorize/cuda/Factorize.h>
#include <elves/factorize/cuda/NumberHelper.h>
#include <elves/cuda-utils/Memory.h>
#include <gtest/gtest.h>
#include <functional>
#include <cstdlib>

extern void testAdd(PNumData left, PNumData right, PNumData result);
extern void testSub(PNumData left, PNumData right, PNumData result);
extern void testMul(PNumData left, PNumData right, PNumData result);
extern void testDiv(PNumData left, PNumData right, PNumData result);
extern void testSmallerThan(PNumData left, PNumData right, bool* result);
extern void testShiftLeft(PNumData left, uint32_t offset, PNumData result);
extern void testShiftRight(PNumData left, uint32_t offset, PNumData result);

using namespace std;

BigInt invokeShiftKernel(const BigInt& left, const uint32_t right, function<void (PNumData, uint32_t, PNumData)> kernelCall)
{
    CudaUtils::Memory<uint32_t> left_d(NumberHelper::BigIntToNumber(left));
    CudaUtils::Memory<uint32_t> out_d(NUM_FIELDS);

    kernelCall(left_d.get(), right, out_d.get());
    return NumberHelper::NumberToBigInt(out_d);
}

bool invokeBoolKernel(const BigInt& left, const BigInt& right, function<void (PNumData, PNumData, bool*)> kernelCall)
{
    bool outputData;

    CudaUtils::Memory<uint32_t> left_d(NumberHelper::BigIntToNumber(left));
    CudaUtils::Memory<uint32_t> right_d(NumberHelper::BigIntToNumber(right));
    CudaUtils::Memory<bool> out_d(1);

    kernelCall(left_d.get(), right_d.get(), out_d.get());
    out_d.transferTo(&outputData);

    return outputData;
}

BigInt invokeKernel(const BigInt& left, const BigInt& right, function<void (PNumData, PNumData, PNumData)> kernelCall)
{
    CudaUtils::Memory<uint32_t> left_d(NumberHelper::BigIntToNumber(left));
    CudaUtils::Memory<uint32_t> right_d(NumberHelper::BigIntToNumber(right));
    CudaUtils::Memory<uint32_t> out_d(NUM_FIELDS);

    kernelCall(left_d.get(), right_d.get(), out_d.get());

    return NumberHelper::NumberToBigInt(out_d);
}

TEST(CudaBigIntTest, testMpzConversion)
{
    BigInt start("1231490623");
    NumData test;
    memset(test, 0, sizeof(uint32_t) * NUM_FIELDS);
    mpz_export(test, nullptr, -1, sizeof(uint32_t), 0, 0, start.get_mpz_t());
    BigInt compare;
    mpz_import(compare.get_mpz_t(), NUM_FIELDS, -1, sizeof(uint32_t), 0, 0, test);

    EXPECT_EQ(start, compare);
}

TEST(CudaBigIntTest, testAddition)
{
    BigInt left("12314906231232141243");
    BigInt right("21317833214213");
    BigInt expected("12314927549065355456");

    auto actual = invokeKernel(left, right, testAdd);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testSubtraction)
{
    BigInt left("90887891231490623");
    BigInt right("779789821317833");
    BigInt expected("90108101410172790");

    auto actual = invokeKernel(left, right, testSub);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testMultiplication)
{
    BigInt left("90887891231490623");
    BigInt right("779789821317833");
    BigInt expected("70873452463358713606126842179959");

    auto actual = invokeKernel(left, right,  testMul);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testMultiplicationSmallNumbers)
{
    BigInt left("5");
    BigInt right("8");
    BigInt expected("40");

    auto actual = invokeKernel(left, right,  testMul);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testDivision)
{
    BigInt left("90887891231490623");
    BigInt right("779789821317833");
    BigInt expected("116");

    auto actual = invokeKernel(left, right,  testDiv);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testDivisionEqualValues)
{
    BigInt left("90887891231490623");
    BigInt right("90887891231490623");
    BigInt expected("1");

    auto actual = invokeKernel(left, right,  testDiv);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testDivisionEqualOperands)
{
    BigInt left("90887891231490623");
    BigInt expected("1");

    auto actual = invokeKernel(left, left,  testDiv);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testSmallerThan)
{
    BigInt left("90887891231490623");
    BigInt right("7797822229821317833");
    bool expected(true);

    auto actual = invokeBoolKernel(left, right, testSmallerThan);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testNotSmallerThan)
{
    BigInt left("90887891231490624");
    BigInt right("90887891231490623");
    bool expected(false);

    auto actual = invokeBoolKernel(left, right, testSmallerThan);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testSmallerThanWithEqualOperands)
{
    BigInt left("90887891231490623");
    BigInt right("90887891231490623");
    bool expected(false);

    auto actual = invokeBoolKernel(left, right, testSmallerThan);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftLeft)
{
    BigInt left("1");
    uint32_t offset(32);
    BigInt expected("4294967296");

    auto actual = invokeShiftKernel(left, offset, testShiftLeft);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftLeftBiggerNumber)
{
    BigInt left("1282943598234");
    uint32_t offset(23);
    BigInt expected("10762110931694518272");

    auto actual = invokeShiftKernel(left, offset, testShiftLeft);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftLeftWithBigShiftOffset)
{
    BigInt left("1282943598234");
    uint32_t offset(3333);
    BigInt expected("0");

    auto actual = invokeShiftKernel(left, offset, testShiftLeft);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftRight)
{
    BigInt left("4294967296");
    uint32_t offset(32);
    BigInt expected("1");

    auto actual = invokeShiftKernel(left, offset, testShiftRight);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftRightBiggerNumber)
{
    BigInt left("1301820391234234234342");
    uint32_t offset(33);
    BigInt expected("151551839806");

    auto actual = invokeShiftKernel(left, offset, testShiftRight);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftRightBiggerNumber2)
{
    BigInt left("2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936575");
    uint32_t offset(33);
    BigInt expected("248661618204893321077691124073410420050228075398673858720231988446579748506266687766527");

    auto actual = invokeShiftKernel(left, offset, testShiftRight);

    EXPECT_EQ(expected, actual);
}

TEST(CudaBigIntTest, testShiftRightWithBigShiftOffset)
{
    BigInt left("1");
    uint32_t offset(33333);
    BigInt expected("0");

    auto actual = invokeShiftKernel(left, offset, testShiftRight);

    EXPECT_EQ(expected, actual);
}
<|endoftext|>


<commit_before>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 **************************************************************************/

#include "View.h"
#include "ActionHandler.h"
#include "Binding.h"

DC_BEGIN_DREEMCHEST

namespace mvvm {

// ** View::notify
void View::notify( const String& event )
{
    ActionHandlers::Parts& actionHandlers = m_actionHandlers.parts();

    for( ActionHandlers::Parts::iterator i = actionHandlers.begin(), end = actionHandlers.end(); i != end; ++i ) {
        i->second->handleEvent( event );
    }
}

// ** View::clear
void View::clear( void )
{
    m_bindings.clear();
    m_data.clear();
    m_actionHandlers.clear();
}

// ** View::addBinding
void View::addBinding( Binding* instance )
{
    instance->refresh();
    m_bindings.push_back( instance );
}

} // namespace mvvm

DC_END_DREEMCHEST
<commit_msg>Fixed Mvvm::View compilation error<commit_after>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 **************************************************************************/

#include "View.h"
#include "ActionHandler.h"
#include "Binding.h"

DC_BEGIN_DREEMCHEST

namespace mvvm {

// ** View::notify
void View::notify( const String& event )
{
    ActionHandlers::Parts& actionHandlers = m_actionHandlers.parts();

    for( ActionHandlers::Parts::iterator i = actionHandlers.begin(), end = actionHandlers.end(); i != end; ++i ) {
        i->second->handleEvent( event );
    }
}

// ** View::clear
void View::clear( void )
{
    m_bindings.clear();
    m_data.clear();
    m_actionHandlers.clear();
}

// ** View::addBinding
void View::addBinding( Binding* instance )
{
    instance->refreshView();
    m_bindings.push_back( instance );
}

} // namespace mvvm

DC_END_DREEMCHEST
<|endoftext|>