zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From an...@apache.org
Subject [01/22] zookeeper git commit: ZOOKEEPER-3031: MAVEN MIGRATION - Step 1.4 - move client dir
Date Tue, 21 Aug 2018 05:31:01 GMT
Repository: zookeeper
Updated Branches:
  refs/heads/master 290f1fc4b -> 176bd6822


http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/WatchUtil.h
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/WatchUtil.h b/zookeeper-client/zookeeper-client-c/tests/WatchUtil.h
new file mode 100644
index 0000000..035f26d
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/WatchUtil.h
@@ -0,0 +1,153 @@
+/**
+ * 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.
+ */
+
+#ifndef WATCH_UTIL_H_
+#define WATCH_UTIL_H_
+
+#include <sys/select.h>
+#include <cstring>
+#include <list>
+
+using namespace std;
+
+#include "CollectionUtil.h"
+#include "ThreadingUtil.h"
+
+using namespace Util;
+
+#ifdef THREADED
+    static void yield(zhandle_t *zh, int i)
+    {
+        sleep(i);
+    }
+#else
+    static void yield(zhandle_t *zh, int seconds)
+    {
+        int fd;
+        int interest;
+        int events;
+        struct timeval tv;
+        int rc;
+        time_t expires = time(0) + seconds;
+        time_t timeLeft = seconds;
+        fd_set rfds, wfds, efds;
+        FD_ZERO(&rfds);
+        FD_ZERO(&wfds);
+        FD_ZERO(&efds);
+
+        while(timeLeft >= 0) {
+            zookeeper_interest(zh, &fd, &interest, &tv);
+            if (fd != -1) {
+                if (interest&ZOOKEEPER_READ) {
+                    FD_SET(fd, &rfds);
+                } else {
+                    FD_CLR(fd, &rfds);
+                }
+                if (interest&ZOOKEEPER_WRITE) {
+                    FD_SET(fd, &wfds);
+                } else {
+                    FD_CLR(fd, &wfds);
+                }
+            } else {
+                fd = 0;
+            }
+            FD_SET(0, &rfds);
+            if (tv.tv_sec > timeLeft) {
+                tv.tv_sec = timeLeft;
+            }
+            rc = select(fd+1, &rfds, &wfds, &efds, &tv);
+            timeLeft = expires - time(0);
+            events = 0;
+            if (FD_ISSET(fd, &rfds)) {
+                events |= ZOOKEEPER_READ;
+            }
+            if (FD_ISSET(fd, &wfds)) {
+                events |= ZOOKEEPER_WRITE;
+            }
+            zookeeper_process(zh, events);
+        }
+    }
+#endif
+
+typedef struct evt {
+	string path;
+	int type;
+} evt_t;
+
+typedef struct watchCtx {
+private:
+    list<evt_t> events;
+    watchCtx(const watchCtx&);
+    watchCtx& operator=(const watchCtx&);
+public:
+    bool connected;
+    zhandle_t *zh;
+    Mutex mutex;
+
+    watchCtx() {
+        connected = false;
+        zh = 0;
+    }
+    ~watchCtx() {
+        if (zh) {
+            zookeeper_close(zh);
+            zh = 0;
+        }
+    }
+
+    evt_t getEvent() {
+        evt_t evt;
+        mutex.acquire();
+        CPPUNIT_ASSERT( events.size() > 0);
+        evt = events.front();
+        events.pop_front();
+        mutex.release();
+        return evt;
+    }
+
+    int countEvents() {
+        int count;
+        mutex.acquire();
+        count = events.size();
+        mutex.release();
+        return count;
+    }
+
+    void putEvent(evt_t evt) {
+        mutex.acquire();
+        events.push_back(evt);
+        mutex.release();
+    }
+
+    bool waitForConnected(zhandle_t *zh) {
+        time_t expires = time(0) + 10;
+        while(!connected && time(0) < expires) {
+            yield(zh, 1);
+        }
+        return connected;
+    }
+    bool waitForDisconnected(zhandle_t *zh) {
+        time_t expires = time(0) + 15;
+        while(connected && time(0) < expires) {
+            yield(zh, 1);
+        }
+        return !connected;
+    }
+} watchctx_t;
+
+#endif /*WATCH_UTIL_H_*/

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/ZKMocks.cc
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/ZKMocks.cc b/zookeeper-client/zookeeper-client-c/tests/ZKMocks.cc
new file mode 100644
index 0000000..1310ab9
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/ZKMocks.cc
@@ -0,0 +1,544 @@
+/**
+ * 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 <arpa/inet.h>  // for htonl
+#include <memory>
+
+#include <zookeeper.h>
+#include <proto.h>
+
+#ifdef THREADED
+#include "PthreadMocks.h"
+#endif
+#include "ZKMocks.h"
+
+using namespace std;
+
+TestClientId testClientId;
+const char* TestClientId::PASSWD="1234567890123456";
+
+HandshakeRequest* HandshakeRequest::parse(const std::string& buf) {
+    auto_ptr<HandshakeRequest> req(new HandshakeRequest);
+
+    memcpy(&req->protocolVersion,buf.data(), sizeof(req->protocolVersion));
+    req->protocolVersion = htonl(req->protocolVersion);
+
+    int offset=sizeof(req->protocolVersion);
+
+    memcpy(&req->lastZxidSeen,buf.data()+offset,sizeof(req->lastZxidSeen));
+    req->lastZxidSeen = zoo_htonll(req->lastZxidSeen);
+    offset+=sizeof(req->lastZxidSeen);
+
+    memcpy(&req->timeOut,buf.data()+offset,sizeof(req->timeOut));
+    req->timeOut = htonl(req->timeOut);
+    offset+=sizeof(req->timeOut);
+
+    memcpy(&req->sessionId,buf.data()+offset,sizeof(req->sessionId));
+    req->sessionId = zoo_htonll(req->sessionId);
+    offset+=sizeof(req->sessionId);
+
+    memcpy(&req->passwd_len,buf.data()+offset,sizeof(req->passwd_len));
+    req->passwd_len = htonl(req->passwd_len);
+    offset+=sizeof(req->passwd_len);
+
+    memcpy(req->passwd,buf.data()+offset,sizeof(req->passwd));
+    offset+=sizeof(req->passwd);
+
+    memcpy(&req->readOnly,buf.data()+offset,sizeof(req->readOnly));
+
+    if(testClientId.client_id==req->sessionId &&
+            !memcmp(testClientId.passwd,req->passwd,sizeof(req->passwd)))
+        return req.release();
+    // the request didn't match -- may not be a handshake request after all
+
+    return 0;
+}
+
+// *****************************************************************************
+// watcher action implementation
+void activeWatcher(zhandle_t *zh,
+                   int type, int state, const char *path,void* ctx) {
+
+    if (zh == 0 || ctx == 0)
+      return;
+
+    WatcherAction* action = (WatcherAction *)ctx;
+
+    if (type == ZOO_SESSION_EVENT) {
+        if (state == ZOO_EXPIRED_SESSION_STATE)
+            action->onSessionExpired(zh);
+        else if(state == ZOO_CONNECTING_STATE)
+            action->onConnectionLost(zh);
+        else if(state == ZOO_CONNECTED_STATE)
+            action->onConnectionEstablished(zh);
+    } else if (type == ZOO_CHANGED_EVENT)
+        action->onNodeValueChanged(zh,path);
+    else if (type == ZOO_DELETED_EVENT)
+        action->onNodeDeleted(zh,path);
+    else if (type == ZOO_CHILD_EVENT)
+        action->onChildChanged(zh,path);
+
+    // TODO: implement for the rest of the event types
+
+    action->setWatcherTriggered();
+}
+
+SyncedBoolCondition WatcherAction::isWatcherTriggered() const {
+    return SyncedBoolCondition(triggered_,mx_);
+}
+
+// a set of async completion signatures
+
+void asyncCompletion(int rc, ACL_vector *acl,Stat *stat, const void *data){
+    assert("Completion data is NULL"&&data);
+    static_cast<AsyncCompletion*>((void*)data)->aclCompl(rc,acl,stat);
+}
+
+void asyncCompletion(int rc, const char *value, int len, const Stat *stat,
+        const void *data) {
+    assert("Completion data is NULL"&&data);
+    static_cast<AsyncCompletion*>((void*)data)->dataCompl(rc,value,len,stat);
+}
+
+void asyncCompletion(int rc, const Stat *stat, const void *data) {
+    assert("Completion data is NULL"&&data);
+    static_cast<AsyncCompletion*>((void*)data)->statCompl(rc,stat);
+}
+
+void asyncCompletion(int rc, const char *value, const void *data) {
+    assert("Completion data is NULL"&&data);
+    static_cast<AsyncCompletion*>((void*)data)->stringCompl(rc,value);
+}
+
+void asyncCompletion(int rc,const String_vector *strings, const void *data) {
+    assert("Completion data is NULL"&&data);
+    static_cast<AsyncCompletion*>((void*)data)->stringsCompl(rc,strings);
+}
+
+void asyncCompletion(int rc, const void *data) {
+    assert("Completion data is NULL"&&data);
+    static_cast<AsyncCompletion*>((void*)data)->voidCompl(rc);
+}
+
+// a predicate implementation
+bool IOThreadStopped::operator()() const{
+#ifdef THREADED
+    adaptor_threads* adaptor=(adaptor_threads*)zh_->adaptor_priv;
+    return CheckedPthread::isTerminated(adaptor->io);
+#else
+    assert("IOThreadStopped predicate is only for use with THREADED client" &&
+           false);
+    return false;
+#endif
+}
+
+//******************************************************************************
+//
+DECLARE_WRAPPER(int,flush_send_queue,(zhandle_t*zh, int timeout))
+{
+    if(!Mock_flush_send_queue::mock_)
+        return CALL_REAL(flush_send_queue,(zh,timeout));
+    return Mock_flush_send_queue::mock_->call(zh,timeout);
+}
+
+Mock_flush_send_queue* Mock_flush_send_queue::mock_=0;
+
+//******************************************************************************
+//
+DECLARE_WRAPPER(int32_t,get_xid,())
+{
+    if(!Mock_get_xid::mock_)
+        return CALL_REAL(get_xid,());
+    return Mock_get_xid::mock_->call();
+}
+
+Mock_get_xid* Mock_get_xid::mock_=0;
+
+//******************************************************************************
+// activateWatcher mock
+
+DECLARE_WRAPPER(void,activateWatcher,(zhandle_t *zh, watcher_registration_t* reg, int rc))
+{
+    if(!Mock_activateWatcher::mock_){
+        CALL_REAL(activateWatcher,(zh, reg,rc));
+    }else{
+        Mock_activateWatcher::mock_->call(zh, reg,rc);
+    }
+}
+Mock_activateWatcher* Mock_activateWatcher::mock_=0;
+
+class ActivateWatcherWrapper: public Mock_activateWatcher{
+public:
+    ActivateWatcherWrapper():ctx_(0),activated_(false){}
+
+    virtual void call(zhandle_t *zh, watcher_registration_t* reg, int rc){
+        CALL_REAL(activateWatcher,(zh, reg,rc));
+        synchronized(mx_);
+        if(reg->context==ctx_){
+            activated_=true;
+            ctx_=0;
+        }
+    }
+
+    void setContext(void* ctx){
+        synchronized(mx_);
+        ctx_=ctx;
+        activated_=false;
+    }
+
+    SyncedBoolCondition isActivated() const{
+        return SyncedBoolCondition(activated_,mx_);
+    }
+    mutable Mutex mx_;
+    void* ctx_;
+    bool activated_;
+};
+
+WatcherActivationTracker::WatcherActivationTracker():
+    wrapper_(new ActivateWatcherWrapper)
+{
+}
+
+WatcherActivationTracker::~WatcherActivationTracker(){
+    delete wrapper_;
+}
+
+void WatcherActivationTracker::track(void* ctx){
+    wrapper_->setContext(ctx);
+}
+
+SyncedBoolCondition WatcherActivationTracker::isWatcherActivated() const{
+    return wrapper_->isActivated();
+}
+
+//******************************************************************************
+//
+DECLARE_WRAPPER(void,deliverWatchers,(zhandle_t* zh,int type,int state, const char* path, watcher_object_list_t **list))
+{
+    if(!Mock_deliverWatchers::mock_){
+        CALL_REAL(deliverWatchers,(zh,type,state,path, list));
+    }else{
+        Mock_deliverWatchers::mock_->call(zh,type,state,path, list);
+    }
+}
+
+Mock_deliverWatchers* Mock_deliverWatchers::mock_=0;
+
+struct RefCounterValue{
+    RefCounterValue(zhandle_t* const& zh,int32_t expectedCounter,Mutex& mx):
+        zh_(zh),expectedCounter_(expectedCounter),mx_(mx){}
+    bool operator()() const{
+        {
+            synchronized(mx_);
+            if(zh_==0)
+                return false;
+        }
+        return inc_ref_counter(zh_,0)==expectedCounter_;
+    }
+    zhandle_t* const& zh_;
+    int32_t expectedCounter_;
+    Mutex& mx_;
+};
+
+
+class DeliverWatchersWrapper: public Mock_deliverWatchers{
+public:
+    DeliverWatchersWrapper(int type,int state,bool terminate):
+        type_(type),state_(state),
+        allDelivered_(false),terminate_(terminate),zh_(0),deliveryCounter_(0){}
+    virtual void call(zhandle_t* zh, int type, int state,
+                      const char* path, watcher_object_list **list) {
+        {
+            synchronized(mx_);
+            zh_=zh;
+            allDelivered_=false;
+        }
+        CALL_REAL(deliverWatchers,(zh,type,state,path, list));
+        if(type_==type && state_==state){
+            if(terminate_){
+                // prevent zhandle_t from being prematurely distroyed;
+                // this will also ensure that zookeeper_close() cleanups the
+                //  thread resources by calling finish_adaptor()
+                inc_ref_counter(zh,1);
+                terminateZookeeperThreads(zh);
+            }
+            synchronized(mx_);
+            allDelivered_=true;
+            deliveryCounter_++;
+        }
+    }
+    SyncedBoolCondition isDelivered() const{
+        if(terminate_){
+            int i=ensureCondition(RefCounterValue(zh_,1,mx_),1000);
+            assert(i<1000);
+        }
+        return SyncedBoolCondition(allDelivered_,mx_);
+    }
+    void resetDeliveryCounter(){
+        synchronized(mx_);
+        deliveryCounter_=0;
+    }
+    SyncedIntegerEqual deliveryCounterEquals(int expected) const{
+        if(terminate_){
+            int i=ensureCondition(RefCounterValue(zh_,1,mx_),1000);
+            assert(i<1000);
+        }
+        return SyncedIntegerEqual(deliveryCounter_,expected,mx_);
+    }
+    int type_;
+    int state_;
+    mutable Mutex mx_;
+    bool allDelivered_;
+    bool terminate_;
+    zhandle_t* zh_;
+    int deliveryCounter_;
+};
+
+WatcherDeliveryTracker::WatcherDeliveryTracker(
+        int type,int state,bool terminateCompletionThread):
+    deliveryWrapper_(new DeliverWatchersWrapper(
+            type,state,terminateCompletionThread)){
+}
+
+WatcherDeliveryTracker::~WatcherDeliveryTracker(){
+    delete deliveryWrapper_;
+}
+
+SyncedBoolCondition WatcherDeliveryTracker::isWatcherProcessingCompleted() const {
+    return deliveryWrapper_->isDelivered();
+}
+
+void WatcherDeliveryTracker::resetDeliveryCounter(){
+    deliveryWrapper_->resetDeliveryCounter();
+}
+
+SyncedIntegerEqual WatcherDeliveryTracker::deliveryCounterEquals(int expected) const {
+    return deliveryWrapper_->deliveryCounterEquals(expected);
+}
+
+//******************************************************************************
+//
+string HandshakeResponse::toString() const {
+    string buf;
+    int32_t tmp=htonl(protocolVersion);
+    buf.append((char*)&tmp,sizeof(tmp));
+    tmp=htonl(timeOut);
+    buf.append((char*)&tmp,sizeof(tmp));
+    int64_t tmp64=zoo_htonll(sessionId);
+    buf.append((char*)&tmp64,sizeof(sessionId));
+    tmp=htonl(passwd_len);
+    buf.append((char*)&tmp,sizeof(tmp));
+    buf.append(passwd,sizeof(passwd));
+    buf.append(&readOnly,sizeof(readOnly));
+    // finally set the buffer length
+    tmp=htonl(buf.size()+sizeof(tmp));
+    buf.insert(0,(char*)&tmp, sizeof(tmp));
+    return buf;
+}
+
+string ZooGetResponse::toString() const{
+    oarchive* oa=create_buffer_oarchive();
+
+    ReplyHeader h = {xid_,1,ZOK};
+    serialize_ReplyHeader(oa, "hdr", &h);
+
+    GetDataResponse resp;
+    char buf[1024];
+    assert("GetDataResponse is too long"&&data_.size()<=sizeof(buf));
+    resp.data.len=data_.size();
+    resp.data.buff=buf;
+    data_.copy(resp.data.buff, data_.size());
+    resp.stat=stat_;
+    serialize_GetDataResponse(oa, "reply", &resp);
+    int32_t len=htonl(get_buffer_len(oa));
+    string res((char*)&len,sizeof(len));
+    res.append(get_buffer(oa),get_buffer_len(oa));
+
+    close_buffer_oarchive(&oa,1);
+    return res;
+}
+
+string ZooStatResponse::toString() const{
+    oarchive* oa=create_buffer_oarchive();
+
+    ReplyHeader h = {xid_,1,rc_};
+    serialize_ReplyHeader(oa, "hdr", &h);
+
+    SetDataResponse resp;
+    resp.stat=stat_;
+    serialize_SetDataResponse(oa, "reply", &resp);
+    int32_t len=htonl(get_buffer_len(oa));
+    string res((char*)&len,sizeof(len));
+    res.append(get_buffer(oa),get_buffer_len(oa));
+
+    close_buffer_oarchive(&oa,1);
+    return res;
+}
+
+string ZooGetChildrenResponse::toString() const{
+    oarchive* oa=create_buffer_oarchive();
+
+    ReplyHeader h = {xid_,1,rc_};
+    serialize_ReplyHeader(oa, "hdr", &h);
+
+    GetChildrenResponse resp;
+    // populate the string vector
+    allocate_String_vector(&resp.children,strings_.size());
+    for(int i=0;i<(int)strings_.size();++i)
+        resp.children.data[i]=strdup(strings_[i].c_str());
+    serialize_GetChildrenResponse(oa, "reply", &resp);
+    deallocate_GetChildrenResponse(&resp);
+
+    int32_t len=htonl(get_buffer_len(oa));
+    string res((char*)&len,sizeof(len));
+    res.append(get_buffer(oa),get_buffer_len(oa));
+
+    close_buffer_oarchive(&oa,1);
+    return res;
+}
+
+string ZNodeEvent::toString() const{
+    oarchive* oa=create_buffer_oarchive();
+    struct WatcherEvent evt = {type_,0,(char*)path_.c_str()};
+    struct ReplyHeader h = {WATCHER_EVENT_XID,0,ZOK };
+
+    serialize_ReplyHeader(oa, "hdr", &h);
+    serialize_WatcherEvent(oa, "event", &evt);
+
+    int32_t len=htonl(get_buffer_len(oa));
+    string res((char*)&len,sizeof(len));
+    res.append(get_buffer(oa),get_buffer_len(oa));
+
+    close_buffer_oarchive(&oa,1);
+    return res;
+}
+
+string PingResponse::toString() const{
+    oarchive* oa=create_buffer_oarchive();
+
+    ReplyHeader h = {PING_XID,1,ZOK};
+    serialize_ReplyHeader(oa, "hdr", &h);
+
+    int32_t len=htonl(get_buffer_len(oa));
+    string res((char*)&len,sizeof(len));
+    res.append(get_buffer(oa),get_buffer_len(oa));
+
+    close_buffer_oarchive(&oa,1);
+    return res;
+}
+
+//******************************************************************************
+// Zookeeper server simulator
+//
+bool ZookeeperServer::hasMoreRecv() const{
+  return recvHasMore.get()!=0  || connectionLost;
+}
+
+ssize_t ZookeeperServer::callRecv(int s,void *buf,size_t len,int flags){
+    if(connectionLost){
+        recvReturnBuffer.erase();
+        return 0;
+    }
+    // done transmitting the current buffer?
+    if(recvReturnBuffer.size()==0){
+        synchronized(recvQMx);
+        if(recvQueue.empty()){
+            recvErrno=EAGAIN;
+            return Mock_socket::callRecv(s,buf,len,flags);
+        }
+        --recvHasMore;
+        Element& el=recvQueue.front();
+        if(el.first!=0){
+            recvReturnBuffer=el.first->toString();
+            delete el.first;
+        }
+        recvErrno=el.second;
+        recvQueue.pop_front();
+    }
+    return Mock_socket::callRecv(s,buf,len,flags);
+}
+
+void ZookeeperServer::onMessageReceived(const RequestHeader& rh, iarchive* ia){
+    // no-op by default
+}
+
+void ZookeeperServer::notifyBufferSent(const std::string& buffer){
+    if(HandshakeRequest::isValid(buffer)){
+        // could be a connect request
+        auto_ptr<HandshakeRequest> req(HandshakeRequest::parse(buffer));
+        if(req.get()!=0){
+            // handle the handshake
+            int64_t sessId=sessionExpired?req->sessionId+1:req->sessionId;
+            sessionExpired=false;
+            addRecvResponse(new HandshakeResponse(sessId));
+            return;
+        }
+        // not a connect request -- fall thru
+    }
+    // parse the buffer to extract the request type and its xid
+    iarchive *ia=create_buffer_iarchive((char*)buffer.data(), buffer.size());
+    RequestHeader rh;
+    deserialize_RequestHeader(ia,"hdr",&rh);
+    // notify the "server" a client request has arrived
+    if (rh.xid == -8) {
+        Element e = Element(new ZooStatResponse,0);
+        e.first->setXID(-8);
+        addRecvResponse(e);
+        close_buffer_iarchive(&ia);
+        return;
+    } else {
+        onMessageReceived(rh,ia);
+    }
+    close_buffer_iarchive(&ia);
+    if(rh.type==ZOO_CLOSE_OP){
+        ++closeSent;
+        return; // no reply for close requests
+    }
+    // get the next response from the response queue and append it to the
+    // receive list
+    Element e;
+    {
+        synchronized(respQMx);
+        if(respQueue.empty())
+            return;
+        e=respQueue.front();
+        respQueue.pop_front();
+    }
+    e.first->setXID(rh.xid);
+    addRecvResponse(e);
+}
+
+void forceConnected(zhandle_t* zh){
+    // simulate connected state
+    zh->state=ZOO_CONNECTED_STATE;
+
+    // Simulate we're connected to the first host in our host list
+    zh->fd=ZookeeperServer::FD;
+    assert(zh->addrs.count > 0);
+    zh->addr_cur = zh->addrs.data[0];
+    zh->addrs.next++;
+
+    zh->input_buffer=0;
+    gettimeofday(&zh->last_recv,0);
+    gettimeofday(&zh->last_send,0);
+}
+
+void terminateZookeeperThreads(zhandle_t* zh){
+    // this will cause the zookeeper threads to terminate
+    zh->close_requested=1;
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/ZKMocks.h
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/ZKMocks.h b/zookeeper-client/zookeeper-client-c/tests/ZKMocks.h
new file mode 100644
index 0000000..2717ded
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/ZKMocks.h
@@ -0,0 +1,511 @@
+/**
+ * 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.
+ */
+
+#ifndef ZKMOCKS_H_
+#define ZKMOCKS_H_
+
+#include <zookeeper.h>
+#include "src/zk_adaptor.h"
+
+#include "Util.h"
+#include "LibCMocks.h"
+#include "MocksBase.h"
+
+// *****************************************************************************
+// sets internal zhandle_t members to certain values to simulate the client 
+// connected state. This function should only be used with the single-threaded
+// Async API tests!
+void forceConnected(zhandle_t* zh); 
+
+/**
+ * Gracefully terminates zookeeper I/O and completion threads. 
+ */
+void terminateZookeeperThreads(zhandle_t* zh);
+
+// *****************************************************************************
+// Abstract watcher action
+struct SyncedBoolCondition;
+
+class WatcherAction{
+public:
+    WatcherAction():triggered_(false){}
+    virtual ~WatcherAction(){}
+    
+    virtual void onSessionExpired(zhandle_t*){}
+    virtual void onConnectionEstablished(zhandle_t*){}
+    virtual void onConnectionLost(zhandle_t*){}
+    virtual void onNodeValueChanged(zhandle_t*,const char* path){}
+    virtual void onNodeDeleted(zhandle_t*,const char* path){}
+    virtual void onChildChanged(zhandle_t*,const char* path){}
+    
+    SyncedBoolCondition isWatcherTriggered() const;
+    void setWatcherTriggered(){
+        synchronized(mx_);
+        triggered_=true;
+    }
+
+protected:
+    mutable Mutex mx_;
+    bool triggered_;
+};
+// zh->context is a pointer to a WatcherAction instance
+// based on the event type and state, the watcher calls a specific watcher 
+// action method
+void activeWatcher(zhandle_t *zh, int type, int state, const char *path,void* ctx);
+
+// *****************************************************************************
+// a set of async completion signatures
+class AsyncCompletion{
+public:
+    virtual ~AsyncCompletion(){}
+    virtual void aclCompl(int rc, ACL_vector *acl,Stat *stat){}
+    virtual void dataCompl(int rc, const char *value, int len, const Stat *stat){}
+    virtual void statCompl(int rc, const Stat *stat){}
+    virtual void stringCompl(int rc, const char *value){}
+    virtual void stringsCompl(int rc,const String_vector *strings){}
+    virtual void voidCompl(int rc){}
+};
+void asyncCompletion(int rc, ACL_vector *acl,Stat *stat, const void *data);
+void asyncCompletion(int rc, const char *value, int len, const Stat *stat, 
+        const void *data);
+void asyncCompletion(int rc, const Stat *stat, const void *data);
+void asyncCompletion(int rc, const char *value, const void *data);
+void asyncCompletion(int rc,const String_vector *strings, const void *data);
+void asyncCompletion(int rc, const void *data);
+
+// *****************************************************************************
+// some common predicates to use with ensureCondition():
+// checks if the connection is established
+struct ClientConnected{
+    ClientConnected(zhandle_t* zh):zh_(zh){}
+    bool operator()() const{
+        return zoo_state(zh_)==ZOO_CONNECTED_STATE;
+    }
+    zhandle_t* zh_;
+};
+// check in the session expired
+struct SessionExpired{
+    SessionExpired(zhandle_t* zh):zh_(zh){}
+    bool operator()() const{
+        return zoo_state(zh_)==ZOO_EXPIRED_SESSION_STATE;
+    }
+    zhandle_t* zh_;
+};
+// checks if the IO thread has stopped; CheckedPthread must be active
+struct IOThreadStopped{
+    IOThreadStopped(zhandle_t* zh):zh_(zh){}
+    bool operator()() const;
+    zhandle_t* zh_;
+};
+
+// a synchronized boolean condition
+struct SyncedBoolCondition{
+    SyncedBoolCondition(const bool& cond,Mutex& mx):cond_(cond),mx_(mx){}
+    bool operator()() const{
+        synchronized(mx_);
+        return cond_;
+    }
+    const bool& cond_;
+    Mutex& mx_;
+};
+
+// a synchronized integer comparison
+struct SyncedIntegerEqual{
+    SyncedIntegerEqual(const int& cond,int expected,Mutex& mx):
+        cond_(cond),expected_(expected),mx_(mx){}
+    bool operator()() const{
+        synchronized(mx_);
+        return cond_==expected_;
+    }
+    const int& cond_;
+    const int expected_;
+    Mutex& mx_;
+};
+
+// *****************************************************************************
+// make sure to call zookeeper_close() even in presence of exceptions 
+struct CloseFinally{
+    CloseFinally(zhandle_t** zh):zh_(zh){}
+    ~CloseFinally(){
+        execute();
+    }
+    int execute(){
+        if(zh_==0)return ZOK;
+        zhandle_t* lzh=*zh_;
+        *zh_=0;
+        disarm();
+        return zookeeper_close(lzh);
+    }
+    void disarm(){zh_=0;}
+    zhandle_t ** zh_;
+};
+
+struct TestClientId: clientid_t{
+    static const int SESSION_ID=123456789;
+    static const char* PASSWD;
+    TestClientId(){
+        client_id=SESSION_ID;
+        memcpy(passwd,PASSWD,sizeof(passwd));
+    }
+};
+
+// *****************************************************************************
+// special client id recongnized by the ZK server simulator 
+extern TestClientId testClientId;
+#define TEST_CLIENT_ID &testClientId
+
+// *****************************************************************************
+//
+struct HandshakeRequest: public connect_req
+{
+    static HandshakeRequest* parse(const std::string& buf);
+    static bool isValid(const std::string& buf){
+        // this is just quick and dirty check before we go and parse the request
+        return buf.size()==HANDSHAKE_REQ_SIZE;
+    }
+};
+
+// *****************************************************************************
+// flush_send_queue
+class Mock_flush_send_queue: public Mock
+{
+public:
+    Mock_flush_send_queue():counter(0),callReturns(ZOK){mock_=this;}
+    ~Mock_flush_send_queue(){mock_=0;}
+    
+    int counter;
+    int callReturns;
+    virtual int call(zhandle_t* zh, int timeout){
+        counter++;
+        return callReturns;
+    }
+
+    static Mock_flush_send_queue* mock_;
+};
+
+// *****************************************************************************
+// get_xid
+class Mock_get_xid: public Mock
+{
+public:
+    static const int32_t XID=123456;
+    Mock_get_xid(int retValue=XID):callReturns(retValue){mock_=this;}
+    ~Mock_get_xid(){mock_=0;}
+    
+    int callReturns;
+    virtual int call(){
+        return callReturns;
+    }
+
+    static Mock_get_xid* mock_;
+};
+
+// *****************************************************************************
+// activateWatcher
+class Mock_activateWatcher: public Mock{
+public:
+    Mock_activateWatcher(){mock_=this;}
+    virtual ~Mock_activateWatcher(){mock_=0;}
+    
+    virtual void call(zhandle_t *zh, watcher_registration_t* reg, int rc){}
+    static Mock_activateWatcher* mock_;
+};
+
+class ActivateWatcherWrapper;
+class WatcherActivationTracker{
+public:
+    WatcherActivationTracker();
+    ~WatcherActivationTracker();
+    
+    void track(void* ctx);
+    SyncedBoolCondition isWatcherActivated() const;
+private:
+    ActivateWatcherWrapper* wrapper_;
+};
+
+// *****************************************************************************
+// deliverWatchers
+class Mock_deliverWatchers: public Mock{
+public:
+    Mock_deliverWatchers(){mock_=this;}
+    virtual ~Mock_deliverWatchers(){mock_=0;}
+    
+    virtual void call(zhandle_t* zh,int type,int state, const char* path, watcher_object_list **){}
+    static Mock_deliverWatchers* mock_;
+};
+
+class DeliverWatchersWrapper;
+class WatcherDeliveryTracker{
+public:
+    // filters deliveries by state and type
+    WatcherDeliveryTracker(int type,int state,bool terminateCompletionThread=true);
+    ~WatcherDeliveryTracker();
+    
+    // if the thread termination requested (see the ctor params)
+    // this function will wait for the I/O and completion threads to 
+    // terminate before returning a SyncBoolCondition instance
+    SyncedBoolCondition isWatcherProcessingCompleted() const;
+    void resetDeliveryCounter();
+    SyncedIntegerEqual deliveryCounterEquals(int expected) const;
+private:
+    DeliverWatchersWrapper* deliveryWrapper_;
+};
+
+// *****************************************************************************
+// a zookeeper Stat wrapper
+struct NodeStat: public Stat
+{
+    NodeStat(){
+        czxid=0;
+        mzxid=0;
+        ctime=0;
+        mtime=0;
+        version=1;
+        cversion=0;
+        aversion=0;
+        ephemeralOwner=0;
+    }
+    NodeStat(const Stat& other){
+        memcpy(this,&other,sizeof(*this));
+    }
+};
+
+// *****************************************************************************
+// Abstract server Response
+class Response
+{
+public:
+    virtual ~Response(){}
+    
+    virtual void setXID(int32_t xid){}
+    // this method is used by the ZookeeperServer class to serialize 
+    // the instance of Response
+    virtual std::string toString() const =0;
+};
+
+// *****************************************************************************
+// Handshake response
+class HandshakeResponse: public Response
+{
+public:
+    HandshakeResponse(int64_t sessId=1):
+        protocolVersion(1),timeOut(10000),sessionId(sessId),
+        passwd_len(sizeof(passwd)),readOnly(0)
+    {
+        memcpy(passwd,"1234567890123456",sizeof(passwd));
+    }
+    int32_t protocolVersion;
+    int32_t timeOut;
+    int64_t sessionId;
+    int32_t passwd_len;
+    char passwd[16];
+    char readOnly;
+    virtual std::string toString() const ;
+};
+
+// zoo_get() response
+class ZooGetResponse: public Response
+{
+public:
+    ZooGetResponse(const char* data, int len,int32_t xid=0,int rc=ZOK,const Stat& stat=NodeStat())
+        :xid_(xid),data_(data,len),rc_(rc),stat_(stat)
+    {
+    }
+    virtual std::string toString() const;
+    virtual void setXID(int32_t xid) {xid_=xid;}
+    
+private:
+    int32_t xid_;
+    std::string data_;
+    int rc_;
+    Stat stat_;
+};
+
+// zoo_exists(), zoo_set() response
+class ZooStatResponse: public Response
+{
+public:
+    ZooStatResponse(int32_t xid=0,int rc=ZOK,const Stat& stat=NodeStat())
+        :xid_(xid),rc_(rc),stat_(stat)
+    {
+    }
+    virtual std::string toString() const;
+    virtual void setXID(int32_t xid) {xid_=xid;}
+    
+private:
+    int32_t xid_;
+    int rc_;
+    Stat stat_;
+};
+
+// zoo_get_children()
+class ZooGetChildrenResponse: public Response
+{
+public:
+    typedef std::vector<std::string> StringVector;
+    ZooGetChildrenResponse(const StringVector& v,int rc=ZOK):
+        xid_(0),strings_(v),rc_(rc)
+    {
+    }
+    
+    virtual std::string toString() const;
+    virtual void setXID(int32_t xid) {xid_=xid;}
+
+    int32_t xid_;
+    StringVector strings_;
+    int rc_;
+};
+
+// PING response
+class PingResponse: public Response
+{
+public:
+    virtual std::string toString() const;    
+};
+
+// watcher znode event
+class ZNodeEvent: public Response
+{
+public:
+    ZNodeEvent(int type,const char* path):type_(type),path_(path){}
+    
+    virtual std::string toString() const;
+    
+private:
+    int type_;
+    std::string path_;
+};
+
+// ****************************************************************************
+// Zookeeper server simulator
+
+class ZookeeperServer: public Mock_socket
+{
+public:
+    ZookeeperServer():
+        serverDownSkipCount_(-1),sessionExpired(false),connectionLost(false)
+    {
+        connectReturns=-1;
+        connectErrno=EWOULDBLOCK;        
+    }
+    virtual ~ZookeeperServer(){
+        clearRecvQueue();
+        clearRespQueue();
+    }
+    virtual int callClose(int fd){
+        if(fd!=FD)
+            return LIBC_SYMBOLS.close(fd);
+        clearRecvQueue();
+        clearRespQueue();
+        return Mock_socket::callClose(fd);
+    }
+    // connection handling
+    // what to do when the handshake request comes in?
+    int serverDownSkipCount_;
+    // this will cause getsockopt(zh->fd,SOL_SOCKET,SO_ERROR,&error,&len) return 
+    // a failure after skipCount dropped to zero, thus simulating a server down 
+    // condition
+    // passing skipCount==-1 will make every connect attempt succeed
+    void setServerDown(int skipCount=0){ 
+        serverDownSkipCount_=skipCount;
+        optvalSO_ERROR=0;            
+    }
+    virtual void setSO_ERROR(void *optval,socklen_t len){
+        if(serverDownSkipCount_!=-1){
+            if(serverDownSkipCount_==0)
+                optvalSO_ERROR=ECONNREFUSED;
+            else
+                serverDownSkipCount_--;
+        }
+        Mock_socket::setSO_ERROR(optval,len);
+    }
+
+    // this is a trigger that gets reset back to false
+    // a connect request will return a non-matching session id thus causing 
+    // the client throw SESSION_EXPIRED
+    volatile bool sessionExpired;
+    void returnSessionExpired(){ sessionExpired=true; }
+    
+    // this is a one shot trigger that gets reset back to false
+    // next recv call will return 0 length, thus simulating a connecton loss
+    volatile bool connectionLost;
+    void setConnectionLost() {connectionLost=true;}
+    
+    // recv
+    // this queue is used for server responses: client's recv() system call 
+    // returns next available message from this queue
+    typedef std::pair<Response*,int> Element;
+    typedef std::deque<Element> ResponseList;
+    ResponseList recvQueue;
+    mutable Mutex recvQMx;
+    AtomicInt recvHasMore;
+    ZookeeperServer& addRecvResponse(Response* resp, int errnum=0){
+        synchronized(recvQMx);
+        recvQueue.push_back(Element(resp,errnum));
+        ++recvHasMore;
+        return *this;
+    }
+    ZookeeperServer& addRecvResponse(int errnum){
+        synchronized(recvQMx);
+        recvQueue.push_back(Element(0,errnum));
+        ++recvHasMore;
+        return *this;
+    }
+    ZookeeperServer& addRecvResponse(const Element& e){
+        synchronized(recvQMx);
+        recvQueue.push_back(e);
+        ++recvHasMore;
+        return *this;
+    }
+    void clearRecvQueue(){
+        synchronized(recvQMx);
+        recvHasMore=0;
+        for(unsigned i=0; i<recvQueue.size();i++)
+            delete recvQueue[i].first;
+        recvQueue.clear();
+    }
+
+    virtual ssize_t callRecv(int s,void *buf,size_t len,int flags);
+    virtual bool hasMoreRecv() const;
+    
+    // the operation response queue holds zookeeper operation responses till the
+    // operation request has been sent to the server. After that, the operation
+    // response gets moved on to the recv queue (see above) ready to be read by 
+    // the next recv() system call
+    // send operation doesn't try to match request to the response
+    ResponseList respQueue;
+    mutable Mutex respQMx;
+    ZookeeperServer& addOperationResponse(Response* resp, int errnum=0){
+        synchronized(respQMx);
+        respQueue.push_back(Element(resp,errnum));
+        return *this;
+    }
+    void clearRespQueue(){
+        synchronized(respQMx);
+        for(unsigned i=0; i<respQueue.size();i++)
+            delete respQueue[i].first;
+        respQueue.clear();
+    }
+    AtomicInt closeSent;
+    virtual void notifyBufferSent(const std::string& buffer);
+    // simulates an arrival of a client request
+    // a callback to be implemented by subclasses (no-op by default)
+    virtual void onMessageReceived(const RequestHeader& rh, iarchive* ia);
+};
+
+#endif /*ZKMOCKS_H_*/

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/ZooKeeperQuorumServer.cc
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/ZooKeeperQuorumServer.cc b/zookeeper-client/zookeeper-client-c/tests/ZooKeeperQuorumServer.cc
new file mode 100644
index 0000000..c38e385
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/ZooKeeperQuorumServer.cc
@@ -0,0 +1,230 @@
+/**
+ * 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 "ZooKeeperQuorumServer.h"
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <utility>
+#include <unistd.h>
+
+ZooKeeperQuorumServer::
+ZooKeeperQuorumServer(uint32_t id, uint32_t numServers, std::string config, std::string env) :
+    id_(id),
+    env_(env),
+    numServers_(numServers) {
+    const char* root = getenv("ZKROOT");
+    if (root == NULL) {
+        assert(!"Environment variable 'ZKROOT' is not set");
+    }
+    root_ = root;
+    createConfigFile(config);
+    createDataDirectory();
+    start();
+}
+
+ZooKeeperQuorumServer::
+~ZooKeeperQuorumServer() {
+    stop();
+}
+
+std::string ZooKeeperQuorumServer::
+getHostPort() {
+    std::stringstream ss;
+    ss << "localhost:" << getClientPort();
+    return ss.str();
+}
+
+uint32_t ZooKeeperQuorumServer::
+getClientPort() {
+    return CLIENT_PORT_BASE + id_;
+}
+
+void ZooKeeperQuorumServer::
+start() {
+    std::string command = root_ + "/bin/zkServer.sh start " +
+                          getConfigFileName();
+    if (!env_.empty()) {
+        command = env_ + " " + command;
+    }
+    assert(system(command.c_str()) == 0);
+}
+
+void ZooKeeperQuorumServer::
+stop() {
+    std::string command = root_ + "/bin/zkServer.sh stop " +
+                          getConfigFileName();
+    assert(system(command.c_str()) == 0);
+}
+
+std::string ZooKeeperQuorumServer::
+getMode() {
+    char buf[1024];
+    std::string result;
+    std::string command = root_ + "/bin/zkServer.sh status " +
+                          getConfigFileName();
+    FILE* output = popen(command.c_str(), "r");
+    do {
+        if (fgets(buf, 1024, output) != NULL) {
+            result += buf;
+        }
+    } while (!feof(output));
+    pclose(output);
+    if (result.find("Mode: leader") != std::string::npos) {
+        return "leader";
+    } else if (result.find("Mode: follower") != std::string::npos) {
+        return "follower";
+    } else {
+        printf("%s\n", result.c_str());
+        return "";
+    }
+}
+
+bool ZooKeeperQuorumServer::
+isLeader() {
+    return getMode() == "leader";
+}
+
+bool ZooKeeperQuorumServer::
+isFollower() {
+    return getMode() == "follower";
+}
+
+void ZooKeeperQuorumServer::
+createConfigFile(std::string config) {
+    std::string command = "mkdir -p " + root_ + "/build/test/test-cppunit/conf";
+    assert(system(command.c_str()) == 0);
+    std::ofstream confFile;
+    std::stringstream ss;
+    ss << id_ << ".conf";
+    std::string fileName = root_ + "/build/test/test-cppunit/conf/" + ss.str();
+    confFile.open(fileName.c_str());
+    confFile << "tickTime=2000\n";
+    confFile << "clientPort=" << getClientPort() << "\n";
+    confFile << "initLimit=5\n";
+    confFile << "syncLimit=2\n";
+    confFile << "dataDir=" << getDataDirectory() << "\n";
+    for (int i = 0; i < numServers_; i++) {
+        confFile << getServerString(i) << "\n";
+    }
+    // Append additional config, if any.
+    if (!config.empty()) {
+      confFile << config << std::endl;
+    }
+    confFile.close();
+}
+
+std::string ZooKeeperQuorumServer::
+getConfigFileName() {
+    std::stringstream ss;
+    ss << id_ << ".conf";
+    return root_ + "/build/test/test-cppunit/conf/" + ss.str();
+}
+
+void ZooKeeperQuorumServer::
+createDataDirectory() {
+    std::string dataDirectory = getDataDirectory();
+    std::string command = "rm -rf " + dataDirectory;
+    assert(system(command.c_str()) == 0);
+    command = "mkdir -p " + dataDirectory;
+    assert(system(command.c_str()) == 0);
+    std::ofstream myidFile;
+    std::string fileName = dataDirectory + "/myid";
+    myidFile.open(fileName.c_str());
+    myidFile << id_ << "\n";
+    myidFile.close();
+    setenv("ZOO_LOG_DIR", dataDirectory.c_str(), true);
+}
+
+std::string ZooKeeperQuorumServer::
+getServerString() {
+    return getServerString(id_);
+}
+
+std::string ZooKeeperQuorumServer::
+getServerString(uint32_t id) {
+    std::stringstream ss;
+    ss << "server." << id << "=localhost:" << SERVER_PORT_BASE + id <<
+          ":" << ELECTION_PORT_BASE + id << ":participant;localhost:" <<
+          CLIENT_PORT_BASE + id;
+    return ss.str();
+}
+
+std::string ZooKeeperQuorumServer::
+getDataDirectory() {
+    std::stringstream ss;
+    ss << "data" << id_;
+    return root_ + "/build/test/test-cppunit/" + ss.str();
+}
+
+std::vector<ZooKeeperQuorumServer*> ZooKeeperQuorumServer::
+getCluster(uint32_t numServers) {
+    std::vector<ZooKeeperQuorumServer*> cluster;
+    for (int i = 0; i < numServers; i++) {
+        cluster.push_back(new ZooKeeperQuorumServer(i, numServers));
+    }
+
+    // Wait until all the servers start, and fail if they don't start within 10
+    // seconds.
+    for (int i = 0; i < 10; i++) {
+        int j = 0;
+        for (; j < cluster.size(); j++) {
+            if (cluster[j]->getMode() == "") {
+                // The server hasn't started.
+                sleep(1);
+                break;
+            }
+        }
+        if (j == cluster.size()) {
+            return cluster;
+        }
+    }
+    assert(!"The cluster didn't start for 10 seconds");
+}
+
+std::vector<ZooKeeperQuorumServer*> ZooKeeperQuorumServer::
+getCluster(uint32_t numServers, ZooKeeperQuorumServer::tConfigPairs configs, std::string env) {
+    std::vector<ZooKeeperQuorumServer*> cluster;
+    std::string config;
+    for (ZooKeeperQuorumServer::tConfigPairs::const_iterator iter = configs.begin(); iter != configs.end(); ++iter) {
+        std::pair<std::string, std::string> pair = *iter;
+        config += (pair.first + "=" + pair.second + "\n");
+    }
+    for (int i = 0; i < numServers; i++) {
+        cluster.push_back(new ZooKeeperQuorumServer(i, numServers, config, env));
+    }
+
+    // Wait until all the servers start, and fail if they don't start within 10
+    // seconds.
+    for (int i = 0; i < 10; i++) {
+        int j = 0;
+        for (; j < cluster.size(); j++) {
+            if (cluster[j]->getMode() == "") {
+                // The server hasn't started.
+                sleep(1);
+                break;
+            }
+        }
+        if (j == cluster.size()) {
+            return cluster;
+        }
+    }
+    assert(!"The cluster didn't start for 10 seconds");
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/ZooKeeperQuorumServer.h
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/ZooKeeperQuorumServer.h b/zookeeper-client/zookeeper-client-c/tests/ZooKeeperQuorumServer.h
new file mode 100644
index 0000000..577072e
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/ZooKeeperQuorumServer.h
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+#ifndef ZOOKEEPER_QUORUM_SERVER_H
+#define ZOOKEEPER_QUORUM_SERVER_H
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <utility>
+
+class ZooKeeperQuorumServer {
+  public:
+    ~ZooKeeperQuorumServer();
+    typedef std::vector<std::pair<std::string, std::string> > tConfigPairs;
+    static std::vector<ZooKeeperQuorumServer*> getCluster(uint32_t numServers);
+    static std::vector<ZooKeeperQuorumServer*> getCluster(uint32_t numServers,
+        tConfigPairs configs, /* Additional config options as a list of key/value pairs. */
+        std::string env       /* Additional environment variables when starting zkServer.sh. */);
+    std::string getHostPort();
+    uint32_t getClientPort();
+    void start();
+    void stop();
+    bool isLeader();
+    bool isFollower();
+    std::string getServerString();
+
+  private:
+    ZooKeeperQuorumServer();
+    ZooKeeperQuorumServer(uint32_t id, uint32_t numServers, std::string config = "",
+                          std::string env = "");
+    ZooKeeperQuorumServer(const ZooKeeperQuorumServer& that);
+    const ZooKeeperQuorumServer& operator=(const ZooKeeperQuorumServer& that);
+    void createConfigFile(std::string config = "");
+    std::string getConfigFileName();
+    void createDataDirectory();
+    std::string getDataDirectory();
+    static std::string getServerString(uint32_t id);
+    std::string getMode();
+
+    static const uint32_t SERVER_PORT_BASE = 2000;
+    static const uint32_t ELECTION_PORT_BASE = 3000;
+    static const uint32_t CLIENT_PORT_BASE = 4000;
+
+    uint32_t numServers_;
+    uint32_t id_;
+    std::string root_;
+    std::string env_;
+};
+
+#endif  // ZOOKEEPER_QUORUM_SERVER_H

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/quorum.cfg
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/quorum.cfg b/zookeeper-client/zookeeper-client-c/tests/quorum.cfg
new file mode 100644
index 0000000..cb0aa81
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/quorum.cfg
@@ -0,0 +1,8 @@
+tickTime=500
+initLimit=10
+syncLimit=5
+dataDir=TMPDIR/zkdata
+clientPort=22181
+server.1=localhost:22881:33881
+server.2=localhost:22882:33882
+server.3=localhost:22883:33883

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/wrappers-mt.opt
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/wrappers-mt.opt b/zookeeper-client/zookeeper-client-c/tests/wrappers-mt.opt
new file mode 100644
index 0000000..01046fb
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/wrappers-mt.opt
@@ -0,0 +1,3 @@
+-Wl,--wrap -Wl,pthread_mutex_lock
+-Wl,--wrap -Wl,pthread_mutex_trylock
+-Wl,--wrap -Wl,pthread_mutex_unlock

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/wrappers.opt
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/wrappers.opt b/zookeeper-client/zookeeper-client-c/tests/wrappers.opt
new file mode 100644
index 0000000..bce192f
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/wrappers.opt
@@ -0,0 +1,7 @@
+-Wl,--wrap -Wl,calloc
+-Wl,--wrap -Wl,free
+-Wl,--wrap -Wl,flush_send_queue
+-Wl,--wrap -Wl,get_xid
+-Wl,--wrap -Wl,deliverWatchers
+-Wl,--wrap -Wl,activateWatcher
+-Wl,--wrap -Wl,realloc

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/zkServer.sh
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/zkServer.sh b/zookeeper-client/zookeeper-client-c/tests/zkServer.sh
new file mode 100755
index 0000000..4496309
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/zkServer.sh
@@ -0,0 +1,181 @@
+#!/bin/bash
+#
+# 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.
+
+# This is the port where zookeeper server runs on.
+ZOOPORT=22181
+
+if [ "x$1" == "x" ]
+then
+    echo "USAGE: $0 startClean|start|startReadOnly|stop hostPorts"
+    exit 2
+fi
+
+case "`uname`" in
+    CYGWIN*) cygwin=true ;;
+    *) cygwin=false ;;
+esac
+
+if [ "x$1" == "xstartClean" ]
+then
+    if [ "x${base_dir}" == "x" ]
+    then
+    rm -rf /tmp/zkdata
+    else
+    rm -rf "${base_dir}/build/tmp"
+    fi
+fi
+
+if $cygwin
+then
+    # cygwin has a "kill" in the shell itself, gets confused
+    KILL=/bin/kill
+else
+    KILL=kill
+fi
+
+# Make sure nothing is left over from before
+if [ -r "/tmp/zk.pid" ]
+then
+pid=`cat /tmp/zk.pid`
+$KILL -9 $pid
+rm -f /tmp/zk.pid
+fi
+
+if [ -r "${base_dir}/build/tmp/zk.pid" ]
+then
+pid=`cat "${base_dir}/build/tmp/zk.pid"`
+$KILL -9 $pid
+rm -f "${base_dir}/build/tmp/zk.pid"
+fi
+
+# [ZOOKEEPER-820] If lsof command is present, look for a process listening
+# on ZOOPORT and kill it. 
+which lsof &> /dev/null
+if [ $? -eq 0  ]
+then
+    pid=`lsof -i :$ZOOPORT | grep LISTEN | awk '{print $2}'`
+    if [ -n "$pid" ]
+    then
+        $KILL -9 $pid
+    fi
+fi
+
+if [ "x${base_dir}" == "x" ]
+then
+zk_base="../../../"
+else
+zk_base="${base_dir}"
+fi
+
+CLASSPATH="$CLASSPATH:${zk_base}/build/classes"
+CLASSPATH="$CLASSPATH:${zk_base}/conf"
+
+for i in "${zk_base}"/build/lib/*.jar
+do
+    CLASSPATH="$CLASSPATH:$i"
+done
+
+for i in "${zk_base}"/src/java/lib/*.jar
+do
+    CLASSPATH="$CLASSPATH:$i"
+done
+
+CLASSPATH="$CLASSPATH:${CLOVER_HOME}/lib/clover.jar"
+
+if $cygwin
+then
+    CLASSPATH=`cygpath -wp "$CLASSPATH"`
+fi
+
+case $1 in
+start|startClean)
+    if [ "x${base_dir}" == "x" ]
+    then
+        mkdir -p /tmp/zkdata
+        java -cp "$CLASSPATH" org.apache.zookeeper.server.ZooKeeperServerMain $ZOOPORT /tmp/zkdata 3000 $ZKMAXCNXNS &> /tmp/zk.log &
+        pid=$!
+        echo -n $! > /tmp/zk.pid
+    else
+        mkdir -p "${base_dir}/build/tmp/zkdata"
+        java -cp "$CLASSPATH" org.apache.zookeeper.server.ZooKeeperServerMain $ZOOPORT "${base_dir}/build/tmp/zkdata" 3000 $ZKMAXCNXNS &> "${base_dir}/build/tmp/zk.log" &
+        pid=$!
+        echo -n $pid > "${base_dir}/build/tmp/zk.pid"
+    fi
+
+    # wait max 120 seconds for server to be ready to server clients
+    # this handles testing on slow hosts
+    success=false
+    for i in {1..120}
+    do
+        if ps -p $pid > /dev/null
+        then
+            java -cp "$CLASSPATH" org.apache.zookeeper.ZooKeeperMain -server localhost:$ZOOPORT ls / > /dev/null 2>&1
+            if [ $? -ne 0  ]
+            then
+                # server not up yet - wait
+                sleep 1
+            else
+                # server is up and serving client connections
+                success=true
+                break
+            fi
+        else
+            # server died - exit now
+            echo -n " ZooKeeper server process failed"
+            break
+        fi
+    done
+
+    if $success
+    then
+        ## in case for debug, but generally don't use as it messes up the
+        ## console test output
+        echo -n " ZooKeeper server started"
+    else
+        echo -n " ZooKeeper server NOT started"
+    fi
+
+    ;;
+startReadOnly)
+    if [ "x${base_dir}" == "x" ]
+    then
+        echo "this target is for unit tests only"
+        exit 2
+    else
+        tmpdir="${base_dir}/build/tmp"
+        mkdir -p "${tmpdir}/zkdata"
+        rm -f "${tmpdir}/zkdata/myid" && echo 1 > "${tmpdir}/zkdata/myid"
+
+        sed "s#TMPDIR#${tmpdir}#g" ${base_dir}/zookeeper-client/zookeeper-client-c/tests/quorum.cfg > "${tmpdir}/quorum.cfg"
+
+        # force read-only mode
+        java -cp "$CLASSPATH" -Dreadonlymode.enabled=true org.apache.zookeeper.server.quorum.QuorumPeerMain ${tmpdir}/quorum.cfg &> "${tmpdir}/zk.log" &
+        pid=$!
+        echo -n $pid > "${base_dir}/build/tmp/zk.pid"
+        sleep 3 # wait until read-only server is up
+    fi
+
+    ;;
+stop)
+    # Already killed above
+    ;;
+*)
+    echo "Unknown command " + $1
+    exit 2
+esac
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-contrib/zookeeper-contrib-zkpython/src/python/setup.py
----------------------------------------------------------------------
diff --git a/zookeeper-contrib/zookeeper-contrib-zkpython/src/python/setup.py b/zookeeper-contrib/zookeeper-contrib-zkpython/src/python/setup.py
index c6a1cee..d9fa36b 100755
--- a/zookeeper-contrib/zookeeper-contrib-zkpython/src/python/setup.py
+++ b/zookeeper-contrib/zookeeper-contrib-zkpython/src/python/setup.py
@@ -19,12 +19,12 @@ from distutils.core import setup, Extension
 zookeeper_basedir = "../../../"
 
 zookeepermodule = Extension("zookeeper",
-                            sources=["src/c/zookeeper.c"],
-                            include_dirs=[zookeeper_basedir + "/src/c/include",
+                            sources=["zookeeper-client/zookeeper-client-c/zookeeper.c"],
+                            include_dirs=[zookeeper_basedir + "/zookeeper-client/zookeeper-client-c/include",
                                           zookeeper_basedir + "/build/c",
-                                          zookeeper_basedir + "/src/c/generated"],
+                                          zookeeper_basedir + "/zookeeper-client/zookeeper-client-c/generated"],
                             libraries=["zookeeper_mt"],
-                            library_dirs=[zookeeper_basedir + "/src/c/.libs/",
+                            library_dirs=[zookeeper_basedir + "/zookeeper-client/zookeeper-client-c/.libs/",
                                           zookeeper_basedir + "/build/c/.libs/",
                                           zookeeper_basedir + "/build/test/test-cppunit/.libs",
                                           "/usr/local/lib"

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-docs/src/documentation/content/xdocs/zookeeperProgrammers.xml
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/documentation/content/xdocs/zookeeperProgrammers.xml b/zookeeper-docs/src/documentation/content/xdocs/zookeeperProgrammers.xml
index cca60b3..4c12cbf 100644
--- a/zookeeper-docs/src/documentation/content/xdocs/zookeeperProgrammers.xml
+++ b/zookeeper-docs/src/documentation/content/xdocs/zookeeperProgrammers.xml
@@ -1046,7 +1046,7 @@
 
       <note><para>This is a very simple example which is intended to show
         how to interact with ZooKeeper ACLs
-        specifically. See <filename>.../trunk/src/c/src/cli.c</filename>
+        specifically. See <filename>.../trunk/zookeeper-client/zookeeper-client-c/src/cli.c</filename>
         for an example of a C client implementation</para>
       </note>
 
@@ -1610,11 +1610,11 @@ public abstract class ServerAuthenticationProvider implements AuthenticationProv
             <para>Run <command>ant compile_jute</command> from the ZooKeeper
             top level directory (<filename>.../trunk</filename>).
             This will create a directory named "generated" under
-            <filename>.../trunk/src/c</filename>.</para>
+            <filename>.../trunk/zookeeper-client/zookeeper-client-c</filename>.</para>
           </listitem>
 
           <listitem>
-            <para>Change directory to the<filename>.../trunk/src/c</filename>
+            <para>Change directory to the<filename>.../trunk/zookeeper-client/zookeeper-client-c</filename>
             and run <command>autoreconf -if</command> to bootstrap <emphasis
             role="bold">autoconf</emphasis>, <emphasis
             role="bold">automake</emphasis> and <emphasis
@@ -1626,7 +1626,7 @@ public abstract class ServerAuthenticationProvider implements AuthenticationProv
           <listitem>
             <para>If you are building from a project source package,
             unzip/untar the source tarball and cd to the<filename>
-            zookeeper-x.x.x/src/c</filename> directory.</para>
+            zookeeper-x.x.x/zookeeper-client/zookeeper-client-c</filename> directory.</para>
           </listitem>
 
           <listitem>
@@ -1709,7 +1709,7 @@ public abstract class ServerAuthenticationProvider implements AuthenticationProv
           </listitem>
         </orderedlist>
 
-        <note><para>See <filename>.../trunk/src/c/src/cli.c</filename>
+        <note><para>See <filename>.../trunk/zookeeper-client/zookeeper-client-c/src/cli.c</filename>
           for an example of a C client implementation</para>
         </note>
       </section>

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-recipes/zookeeper-recipes-lock/src/main/c/configure.ac
----------------------------------------------------------------------
diff --git a/zookeeper-recipes/zookeeper-recipes-lock/src/main/c/configure.ac b/zookeeper-recipes/zookeeper-recipes-lock/src/main/c/configure.ac
index 3954123..31c5406 100644
--- a/zookeeper-recipes/zookeeper-recipes-lock/src/main/c/configure.ac
+++ b/zookeeper-recipes/zookeeper-recipes-lock/src/main/c/configure.ac
@@ -48,8 +48,8 @@ DX_PS_FEATURE(OFF)
 DX_INIT_DOXYGEN([zookeeper-locks],[c-doc.Doxyfile],[docs])
 
   
-ZOOKEEPER_PATH=${BUILD_PATH}/../../../../../src/c
-ZOOKEEPER_LD=-L${BUILD_PATH}/../../../../../src/c\ -lzookeeper_mt
+ZOOKEEPER_PATH=${BUILD_PATH}/../../../../zookeeper-client/zookeeper-client-c
+ZOOKEEPER_LD=-L${BUILD_PATH}/../../../../zookeeper-client/zookeeper-client-c\ -lzookeeper_mt
 
 AC_SUBST(ZOOKEEPER_PATH)
 AC_SUBST(ZOOKEEPER_LD)

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-recipes/zookeeper-recipes-queue/src/main/c/configure.ac
----------------------------------------------------------------------
diff --git a/zookeeper-recipes/zookeeper-recipes-queue/src/main/c/configure.ac b/zookeeper-recipes/zookeeper-recipes-queue/src/main/c/configure.ac
index a9fb7b1..23fa8c9 100644
--- a/zookeeper-recipes/zookeeper-recipes-queue/src/main/c/configure.ac
+++ b/zookeeper-recipes/zookeeper-recipes-queue/src/main/c/configure.ac
@@ -48,8 +48,8 @@ DX_PS_FEATURE(OFF)
 DX_INIT_DOXYGEN([zookeeper-queues],[c-doc.Doxyfile],[docs])
 
   
-ZOOKEEPER_PATH=${BUILD_PATH}/../../../../../src/c
-ZOOKEEPER_LD=-L${BUILD_PATH}/../../../../../src/c\ -lzookeeper_mt
+ZOOKEEPER_PATH=${BUILD_PATH}/../../../../zookeeper-client/zookeeper-client-c
+ZOOKEEPER_LD=-L${BUILD_PATH}/../../../../zookeeper-client/zookeeper-client-c\ -lzookeeper_mt
 
 AC_SUBST(ZOOKEEPER_PATH)
 AC_SUBST(ZOOKEEPER_LD)


Mime
View raw message