Merge remote-tracking branch 'origin/master' into jerry-sandbox
This commit is contained in:
commit
00ceda55dc
|
@ -0,0 +1,15 @@
|
||||||
|
diff --git a/src/lib/arch/unix/ArchPluginUnix.cpp b/src/lib/arch/unix/ArchPluginUnix.cpp
|
||||||
|
index 997c274..3e390f0 100644
|
||||||
|
--- a/src/lib/arch/unix/ArchPluginUnix.cpp
|
||||||
|
+++ b/src/lib/arch/unix/ArchPluginUnix.cpp
|
||||||
|
@@ -76,8 +76,8 @@ ArchPluginUnix::load()
|
||||||
|
void* library = dlopen(path.c_str(), RTLD_LAZY);
|
||||||
|
|
||||||
|
if (library == NULL) {
|
||||||
|
- LOG((CLOG_ERR "failed to load plugin: %s", (*it).c_str()));
|
||||||
|
- throw XArch(dlerror());
|
||||||
|
+ LOG((CLOG_ERR "failed to load plugin '%s', error: %s", (*it).c_str(), dlerror()));
|
||||||
|
+ continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String filename = synergy::string::removeFileExt(*it);
|
|
@ -60,6 +60,9 @@ ArchMiscWindows::cleanup()
|
||||||
void
|
void
|
||||||
ArchMiscWindows::init()
|
ArchMiscWindows::init()
|
||||||
{
|
{
|
||||||
|
// stop windows system error dialogs from showing.
|
||||||
|
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||||
|
|
||||||
s_dialogs = new Dialogs;
|
s_dialogs = new Dialogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,9 @@ ArchPluginWindows::load()
|
||||||
HINSTANCE library = LoadLibrary(path.c_str());
|
HINSTANCE library = LoadLibrary(path.c_str());
|
||||||
|
|
||||||
if (library == NULL) {
|
if (library == NULL) {
|
||||||
LOG((CLOG_ERR "failed to load plugin: %s %d", (*it).c_str(), GetLastError()));
|
String error = XArchEvalWindows().eval();
|
||||||
throw XArch(new XArchEvalWindows);
|
LOG((CLOG_ERR "failed to load plugin '%s', error: %s", (*it).c_str(), error.c_str()));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* lib = reinterpret_cast<void*>(library);
|
void* lib = reinterpret_cast<void*>(library);
|
||||||
|
|
|
@ -22,6 +22,10 @@
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
enum EFileLogOutputter {
|
||||||
|
kFileSizeLimit = 1024 // kb
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// StopLogOutputter
|
// StopLogOutputter
|
||||||
//
|
//
|
||||||
|
@ -252,13 +256,27 @@ FileLogOutputter::setLogFilename(const char* logFile)
|
||||||
bool
|
bool
|
||||||
FileLogOutputter::write(ELevel level, const char *message)
|
FileLogOutputter::write(ELevel level, const char *message)
|
||||||
{
|
{
|
||||||
|
bool moveFile = false;
|
||||||
|
|
||||||
std::ofstream m_handle;
|
std::ofstream m_handle;
|
||||||
m_handle.open(m_fileName.c_str(), std::fstream::app);
|
m_handle.open(m_fileName.c_str(), std::fstream::app);
|
||||||
if (m_handle.is_open() && m_handle.fail() != true) {
|
if (m_handle.is_open() && m_handle.fail() != true) {
|
||||||
m_handle << message << std::endl;
|
m_handle << message << std::endl;
|
||||||
|
|
||||||
|
// when file size exceeds limits, move to 'old log' filename.
|
||||||
|
int p = m_handle.tellp();
|
||||||
|
if (p > (kFileSizeLimit * 1024)) {
|
||||||
|
moveFile = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_handle.close();
|
m_handle.close();
|
||||||
|
|
||||||
|
if (moveFile) {
|
||||||
|
String oldLogFilename = synergy::string::sprintf("%s.1", m_fileName.c_str());
|
||||||
|
remove(oldLogFilename.c_str());
|
||||||
|
rename(m_fileName.c_str(), oldLogFilename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,12 @@
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "base/TMethodJob.h"
|
#include "base/TMethodJob.h"
|
||||||
|
|
||||||
// limit number of log lines sent in one message.
|
enum EIpcLogOutputter {
|
||||||
#define MAX_SEND 100
|
kBufferMaxSize = 1000,
|
||||||
|
kMaxSendLines = 100,
|
||||||
|
kBufferRateWriteLimit = 1000, // writes per kBufferRateTime
|
||||||
|
kBufferRateTimeLimit = 1 // seconds
|
||||||
|
};
|
||||||
|
|
||||||
IpcLogOutputter::IpcLogOutputter(IpcServer& ipcServer) :
|
IpcLogOutputter::IpcLogOutputter(IpcServer& ipcServer) :
|
||||||
m_ipcServer(ipcServer),
|
m_ipcServer(ipcServer),
|
||||||
|
@ -40,7 +44,14 @@ m_sending(false),
|
||||||
m_running(true),
|
m_running(true),
|
||||||
m_notifyCond(ARCH->newCondVar()),
|
m_notifyCond(ARCH->newCondVar()),
|
||||||
m_notifyMutex(ARCH->newMutex()),
|
m_notifyMutex(ARCH->newMutex()),
|
||||||
m_bufferWaiting(false)
|
m_bufferWaiting(false),
|
||||||
|
m_bufferMaxSize(kBufferMaxSize),
|
||||||
|
m_bufferEmptyCond(ARCH->newCondVar()),
|
||||||
|
m_bufferEmptyMutex(ARCH->newMutex()),
|
||||||
|
m_bufferRateWriteLimit(kBufferRateWriteLimit),
|
||||||
|
m_bufferRateTimeLimit(kBufferRateTimeLimit),
|
||||||
|
m_bufferWriteCount(0),
|
||||||
|
m_bufferRateStart(ARCH->time())
|
||||||
{
|
{
|
||||||
m_bufferThread = new Thread(new TMethodJob<IpcLogOutputter>(
|
m_bufferThread = new Thread(new TMethodJob<IpcLogOutputter>(
|
||||||
this, &IpcLogOutputter::bufferThread));
|
this, &IpcLogOutputter::bufferThread));
|
||||||
|
@ -48,15 +59,20 @@ m_bufferWaiting(false)
|
||||||
|
|
||||||
IpcLogOutputter::~IpcLogOutputter()
|
IpcLogOutputter::~IpcLogOutputter()
|
||||||
{
|
{
|
||||||
m_running = false;
|
close();
|
||||||
notifyBuffer();
|
|
||||||
m_bufferThread->wait(5);
|
|
||||||
|
|
||||||
ARCH->closeMutex(m_bufferMutex);
|
ARCH->closeMutex(m_bufferMutex);
|
||||||
delete m_bufferThread;
|
delete m_bufferThread;
|
||||||
|
|
||||||
ARCH->closeCondVar(m_notifyCond);
|
ARCH->closeCondVar(m_notifyCond);
|
||||||
ARCH->closeMutex(m_notifyMutex);
|
ARCH->closeMutex(m_notifyMutex);
|
||||||
|
|
||||||
|
ARCH->closeCondVar(m_bufferEmptyCond);
|
||||||
|
|
||||||
|
#ifndef WINAPI_CARBON
|
||||||
|
// HACK: assert fails on mac debug, can't see why.
|
||||||
|
ARCH->closeMutex(m_bufferEmptyMutex);
|
||||||
|
#endif // WINAPI_CARBON
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -67,6 +83,9 @@ IpcLogOutputter::open(const char* title)
|
||||||
void
|
void
|
||||||
IpcLogOutputter::close()
|
IpcLogOutputter::close()
|
||||||
{
|
{
|
||||||
|
m_running = false;
|
||||||
|
notifyBuffer();
|
||||||
|
m_bufferThread->wait(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -107,7 +126,27 @@ void
|
||||||
IpcLogOutputter::appendBuffer(const String& text)
|
IpcLogOutputter::appendBuffer(const String& text)
|
||||||
{
|
{
|
||||||
ArchMutexLock lock(m_bufferMutex);
|
ArchMutexLock lock(m_bufferMutex);
|
||||||
m_buffer.push(text);
|
|
||||||
|
double elapsed = ARCH->time() - m_bufferRateStart;
|
||||||
|
if (elapsed < m_bufferRateTimeLimit) {
|
||||||
|
if (m_bufferWriteCount >= m_bufferRateWriteLimit) {
|
||||||
|
// discard the log line if we've logged too much.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_bufferWriteCount = 0;
|
||||||
|
m_bufferRateStart = ARCH->time();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_buffer.size() >= m_bufferMaxSize) {
|
||||||
|
// if the queue is exceeds size limit,
|
||||||
|
// throw away the oldest item
|
||||||
|
m_buffer.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_buffer.push_back(text);
|
||||||
|
m_bufferWriteCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -133,6 +172,11 @@ IpcLogOutputter::bufferThread(void*)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_buffer.empty()) {
|
||||||
|
ArchMutexLock lock(m_bufferEmptyMutex);
|
||||||
|
ARCH->broadcastCondVar(m_bufferEmptyCond);
|
||||||
|
}
|
||||||
|
|
||||||
m_bufferWaiting = true;
|
m_bufferWaiting = true;
|
||||||
ARCH->waitCondVar(m_notifyCond, m_notifyMutex, -1);
|
ARCH->waitCondVar(m_notifyCond, m_notifyMutex, -1);
|
||||||
m_bufferWaiting = false;
|
m_bufferWaiting = false;
|
||||||
|
@ -168,7 +212,7 @@ IpcLogOutputter::getChunk(size_t count)
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
chunk.append(m_buffer.front());
|
chunk.append(m_buffer.front());
|
||||||
chunk.append("\n");
|
chunk.append("\n");
|
||||||
m_buffer.pop();
|
m_buffer.pop_front();
|
||||||
}
|
}
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
@ -176,9 +220,34 @@ IpcLogOutputter::getChunk(size_t count)
|
||||||
void
|
void
|
||||||
IpcLogOutputter::sendBuffer()
|
IpcLogOutputter::sendBuffer()
|
||||||
{
|
{
|
||||||
IpcLogLineMessage message(getChunk(MAX_SEND));
|
IpcLogLineMessage message(getChunk(kMaxSendLines));
|
||||||
|
|
||||||
m_sending = true;
|
m_sending = true;
|
||||||
m_ipcServer.send(message, kIpcClientGui);
|
m_ipcServer.send(message, kIpcClientGui);
|
||||||
m_sending = false;
|
m_sending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IpcLogOutputter::bufferMaxSize(UInt16 bufferMaxSize)
|
||||||
|
{
|
||||||
|
m_bufferMaxSize = bufferMaxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt16
|
||||||
|
IpcLogOutputter::bufferMaxSize() const
|
||||||
|
{
|
||||||
|
return m_bufferMaxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IpcLogOutputter::waitForEmpty()
|
||||||
|
{
|
||||||
|
ARCH->waitCondVar(m_bufferEmptyCond, m_bufferEmptyMutex, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IpcLogOutputter::bufferRateLimit(UInt16 writeLimit, double timeLimit)
|
||||||
|
{
|
||||||
|
m_bufferRateWriteLimit = writeLimit;
|
||||||
|
m_bufferRateTimeLimit = timeLimit;
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "arch/IArchMultithread.h"
|
#include "arch/IArchMultithread.h"
|
||||||
#include "base/ILogOutputter.h"
|
#include "base/ILogOutputter.h"
|
||||||
|
|
||||||
#include <queue>
|
#include <deque>
|
||||||
|
|
||||||
class IpcServer;
|
class IpcServer;
|
||||||
class Event;
|
class Event;
|
||||||
|
@ -43,20 +43,56 @@ public:
|
||||||
virtual void show(bool showIfEmpty);
|
virtual void show(bool showIfEmpty);
|
||||||
virtual bool write(ELevel level, const char* message);
|
virtual bool write(ELevel level, const char* message);
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
//! Same as write, but allows message to sidestep anti-recursion mechanism.
|
//! Same as write, but allows message to sidestep anti-recursion mechanism.
|
||||||
bool write(ELevel level, const char* text, bool force);
|
bool write(ELevel level, const char* text, bool force);
|
||||||
|
|
||||||
//! Notify that the buffer should be sent.
|
//! Notify that the buffer should be sent.
|
||||||
void notifyBuffer();
|
void notifyBuffer();
|
||||||
|
|
||||||
|
//! Set the buffer size.
|
||||||
|
/*!
|
||||||
|
Set the maximum size of the buffer to protect memory
|
||||||
|
from runaway logging.
|
||||||
|
*/
|
||||||
|
void bufferMaxSize(UInt16 bufferMaxSize);
|
||||||
|
|
||||||
|
//! Wait for empty buffer
|
||||||
|
/*!
|
||||||
|
Wait on a cond var until the buffer is empty.
|
||||||
|
*/
|
||||||
|
void waitForEmpty();
|
||||||
|
|
||||||
|
//! Set the buffer size.
|
||||||
|
/*!
|
||||||
|
Set the maximum number of \p writeRate for every \p timeRate in seconds.
|
||||||
|
*/
|
||||||
|
void bufferRateLimit(UInt16 writeLimit, double timeLimit);
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Get the buffer size
|
||||||
|
/*!
|
||||||
|
Returns the maximum size of the buffer.
|
||||||
|
*/
|
||||||
|
UInt16 bufferMaxSize() const;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void init();
|
||||||
void bufferThread(void*);
|
void bufferThread(void*);
|
||||||
String getChunk(size_t count);
|
String getChunk(size_t count);
|
||||||
void sendBuffer();
|
void sendBuffer();
|
||||||
void appendBuffer(const String& text);
|
void appendBuffer(const String& text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::queue<String> Buffer;
|
typedef std::deque<String> Buffer;
|
||||||
|
|
||||||
IpcServer& m_ipcServer;
|
IpcServer& m_ipcServer;
|
||||||
Buffer m_buffer;
|
Buffer m_buffer;
|
||||||
|
@ -69,4 +105,11 @@ private:
|
||||||
bool m_bufferWaiting;
|
bool m_bufferWaiting;
|
||||||
IArchMultithread::ThreadID
|
IArchMultithread::ThreadID
|
||||||
m_bufferThreadId;
|
m_bufferThreadId;
|
||||||
|
UInt16 m_bufferMaxSize;
|
||||||
|
ArchCond m_bufferEmptyCond;
|
||||||
|
ArchMutex m_bufferEmptyMutex;
|
||||||
|
UInt16 m_bufferRateWriteLimit;
|
||||||
|
double m_bufferRateTimeLimit;
|
||||||
|
UInt16 m_bufferWriteCount;
|
||||||
|
double m_bufferRateStart;
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,17 +33,20 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer) :
|
IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer) :
|
||||||
m_socket(events, socketMultiplexer),
|
m_mock(false),
|
||||||
m_address(NetworkAddress(IPC_HOST, IPC_PORT)),
|
m_events(events),
|
||||||
m_events(events)
|
m_socketMultiplexer(socketMultiplexer),
|
||||||
|
m_socket(nullptr),
|
||||||
|
m_address(NetworkAddress(IPC_HOST, IPC_PORT))
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port) :
|
IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port) :
|
||||||
m_socket(events, socketMultiplexer),
|
m_mock(false),
|
||||||
m_address(NetworkAddress(IPC_HOST, port)),
|
m_events(events),
|
||||||
m_events(events)
|
m_socketMultiplexer(socketMultiplexer),
|
||||||
|
m_address(NetworkAddress(IPC_HOST, port))
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -51,17 +54,27 @@ IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
|
||||||
void
|
void
|
||||||
IpcServer::init()
|
IpcServer::init()
|
||||||
{
|
{
|
||||||
|
m_socket = new TCPListenSocket(m_events, m_socketMultiplexer);
|
||||||
|
|
||||||
m_clientsMutex = ARCH->newMutex();
|
m_clientsMutex = ARCH->newMutex();
|
||||||
m_address.resolve();
|
m_address.resolve();
|
||||||
|
|
||||||
m_events->adoptHandler(
|
m_events->adoptHandler(
|
||||||
m_events->forIListenSocket().connecting(), &m_socket,
|
m_events->forIListenSocket().connecting(), m_socket,
|
||||||
new TMethodEventJob<IpcServer>(
|
new TMethodEventJob<IpcServer>(
|
||||||
this, &IpcServer::handleClientConnecting));
|
this, &IpcServer::handleClientConnecting));
|
||||||
}
|
}
|
||||||
|
|
||||||
IpcServer::~IpcServer()
|
IpcServer::~IpcServer()
|
||||||
{
|
{
|
||||||
|
if (m_mock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_socket != nullptr) {
|
||||||
|
delete m_socket;
|
||||||
|
}
|
||||||
|
|
||||||
ARCH->lockMutex(m_clientsMutex);
|
ARCH->lockMutex(m_clientsMutex);
|
||||||
ClientList::iterator it;
|
ClientList::iterator it;
|
||||||
for (it = m_clients.begin(); it != m_clients.end(); it++) {
|
for (it = m_clients.begin(); it != m_clients.end(); it++) {
|
||||||
|
@ -71,19 +84,19 @@ IpcServer::~IpcServer()
|
||||||
ARCH->unlockMutex(m_clientsMutex);
|
ARCH->unlockMutex(m_clientsMutex);
|
||||||
ARCH->closeMutex(m_clientsMutex);
|
ARCH->closeMutex(m_clientsMutex);
|
||||||
|
|
||||||
m_events->removeHandler(m_events->forIListenSocket().connecting(), &m_socket);
|
m_events->removeHandler(m_events->forIListenSocket().connecting(), m_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IpcServer::listen()
|
IpcServer::listen()
|
||||||
{
|
{
|
||||||
m_socket.bind(m_address);
|
m_socket->bind(m_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IpcServer::handleClientConnecting(const Event&, void*)
|
IpcServer::handleClientConnecting(const Event&, void*)
|
||||||
{
|
{
|
||||||
synergy::IStream* stream = m_socket.accept();
|
synergy::IStream* stream = m_socket->accept();
|
||||||
if (stream == NULL) {
|
if (stream == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,17 +49,17 @@ public:
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Opens a TCP socket only allowing local connections.
|
//! Opens a TCP socket only allowing local connections.
|
||||||
void listen();
|
virtual void listen();
|
||||||
|
|
||||||
//! Send a message to all clients matching the filter type.
|
//! Send a message to all clients matching the filter type.
|
||||||
void send(const IpcMessage& message, EIpcClientType filterType);
|
virtual void send(const IpcMessage& message, EIpcClientType filterType);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Returns true when there are clients of the specified type connected.
|
//! Returns true when there are clients of the specified type connected.
|
||||||
bool hasClients(EIpcClientType clientType) const;
|
virtual bool hasClients(EIpcClientType clientType) const;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
@ -73,9 +73,20 @@ private:
|
||||||
private:
|
private:
|
||||||
typedef std::list<IpcClientProxy*> ClientList;
|
typedef std::list<IpcClientProxy*> ClientList;
|
||||||
|
|
||||||
TCPListenSocket m_socket;
|
bool m_mock;
|
||||||
|
IEventQueue* m_events;
|
||||||
|
SocketMultiplexer* m_socketMultiplexer;
|
||||||
|
TCPListenSocket* m_socket;
|
||||||
NetworkAddress m_address;
|
NetworkAddress m_address;
|
||||||
ClientList m_clients;
|
ClientList m_clients;
|
||||||
ArchMutex m_clientsMutex;
|
ArchMutex m_clientsMutex;
|
||||||
IEventQueue* m_events;
|
|
||||||
|
#ifdef TEST_ENV
|
||||||
|
public:
|
||||||
|
IpcServer() :
|
||||||
|
m_mock(true),
|
||||||
|
m_events(nullptr),
|
||||||
|
m_socketMultiplexer(nullptr),
|
||||||
|
m_socket(nullptr) { }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,6 +63,7 @@ ToolApp::run(int argc, char** argv)
|
||||||
return kExitFailed;
|
return kExitFailed;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// HACK: send to standard out so watchdog can parse.
|
||||||
std::cout << "activeDesktop:" << name.c_str() << std::endl;
|
std::cout << "activeDesktop:" << name.c_str() << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2015 Synergy Si Ltd.
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file LICENSE that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ipc/IpcServer.h"
|
||||||
|
#include "ipc/IpcMessage.h"
|
||||||
|
|
||||||
|
#include "test/global/gmock.h"
|
||||||
|
|
||||||
|
class IEventQueue;
|
||||||
|
|
||||||
|
class MockIpcServer : public IpcServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockIpcServer() { }
|
||||||
|
|
||||||
|
MOCK_METHOD0(listen, void());
|
||||||
|
MOCK_METHOD2(send, void(const IpcMessage&, EIpcClientType));
|
||||||
|
MOCK_CONST_METHOD1(hasClients, bool(EIpcClientType));
|
||||||
|
};
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2015 Synergy Si Ltd.
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file LICENSE that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TEST_ENV
|
||||||
|
|
||||||
|
#include "test/mock/ipc/MockIpcServer.h"
|
||||||
|
|
||||||
|
#include "mt/Thread.h"
|
||||||
|
#include "ipc/IpcLogOutputter.h"
|
||||||
|
#include "base/String.h"
|
||||||
|
#include "common/common.h"
|
||||||
|
|
||||||
|
#include "test/global/gmock.h"
|
||||||
|
#include "test/global/gtest.h"
|
||||||
|
|
||||||
|
// HACK: ipc logging only used on windows anyway
|
||||||
|
#if WINAPI_MSWINDOWS
|
||||||
|
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::Return;
|
||||||
|
using ::testing::Matcher;
|
||||||
|
using ::testing::MatcherCast;
|
||||||
|
using ::testing::Property;
|
||||||
|
using ::testing::StrEq;
|
||||||
|
|
||||||
|
using namespace synergy;
|
||||||
|
|
||||||
|
inline const Matcher<const IpcMessage&> IpcLogLineMessageEq(const String& s) {
|
||||||
|
const Matcher<const IpcLogLineMessage&> m(
|
||||||
|
Property(&IpcLogLineMessage::logLine, StrEq(s)));
|
||||||
|
return MatcherCast<const IpcMessage&>(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IpcLogOutputterTests, write_bufferSizeWrapping)
|
||||||
|
{
|
||||||
|
MockIpcServer mockServer;
|
||||||
|
|
||||||
|
ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockServer, hasClients(_)).Times(1);
|
||||||
|
EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"), _)).Times(1);
|
||||||
|
|
||||||
|
IpcLogOutputter outputter(mockServer);
|
||||||
|
outputter.bufferMaxSize(2);
|
||||||
|
|
||||||
|
// log more lines than the buffer can contain
|
||||||
|
outputter.write(kNOTE, "mock 1");
|
||||||
|
outputter.write(kNOTE, "mock 2");
|
||||||
|
outputter.write(kNOTE, "mock 3");
|
||||||
|
|
||||||
|
// wait for the buffer to be empty (all lines sent to IPC)
|
||||||
|
outputter.waitForEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IpcLogOutputterTests, write_bufferRateLimit)
|
||||||
|
{
|
||||||
|
MockIpcServer mockServer;
|
||||||
|
|
||||||
|
ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockServer, hasClients(_)).Times(2);
|
||||||
|
EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\n"), _)).Times(1);
|
||||||
|
EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 3\n"), _)).Times(1);
|
||||||
|
|
||||||
|
IpcLogOutputter outputter(mockServer);
|
||||||
|
outputter.bufferRateLimit(1, 0.001); // 1ms
|
||||||
|
|
||||||
|
// log 1 more line than the buffer can accept in time limit.
|
||||||
|
outputter.write(kNOTE, "mock 1");
|
||||||
|
outputter.write(kNOTE, "mock 2");
|
||||||
|
outputter.waitForEmpty();
|
||||||
|
|
||||||
|
// after waiting the time limit send another to make sure
|
||||||
|
// we can log after the time limit passes.
|
||||||
|
ARCH->sleep(0.01); // 10ms
|
||||||
|
outputter.write(kNOTE, "mock 3");
|
||||||
|
outputter.write(kNOTE, "mock 4");
|
||||||
|
outputter.waitForEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WINAPI_MSWINDOWS
|
Loading…
Reference in New Issue