zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From an...@apache.org
Subject [05/22] zookeeper git commit: ZOOKEEPER-3031: MAVEN MIGRATION - Step 1.4 - move client dir
Date Tue, 21 Aug 2018 05:31:05 GMT
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/CollectionUtil.h
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/CollectionUtil.h b/zookeeper-client/zookeeper-client-c/tests/CollectionUtil.h
new file mode 100644
index 0000000..dd34811
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/CollectionUtil.h
@@ -0,0 +1,195 @@
+/**
+ * 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 _COLLECTION_UTIL_H_
+#define _COLLECTION_UTIL_H_
+
+/**
+ * \file
+ * CollectionBuilder and DictionaryBuilder classes and collection utility functions
+ */
+
+namespace Util 
+{
+
+// *********************************************************
+/** A shortcut to use for building collections.
+ * This class is a wrapper around standard STL collection containers such as vector.
+ * It allows one to conveniently build collections at the variable initialization time:
+ * \code
+ * #include "CollectionUtil.h"
+ * #include "Vector.h"  // for ostream << operator overload for STL vector
+ * using Util;
+ * 
+ * int main()
+ * {
+ *   typedef vector<string> MyVector;
+ *   MyVector myVector=CollectionBuilder<MyVector>()("str1")("str2")("str3");
+ *   cout<<myVector;
+ *   // the following output will be produced:
+ *   // [str1,str2,str3]
+ * }
+ * \endcode
+ */
+template <class CONT>
+class CollectionBuilder
+{
+public:
+  /// Type of the collection container. 
+  typedef CONT CollectionType;
+  /// Container's value type.
+  typedef typename CollectionType::value_type value_type;
+  /// Container's constant iterator type.
+  typedef typename CollectionType::const_iterator const_iterator;
+  /// Container's size type.
+  typedef typename CollectionType::size_type size_type;
+
+  /** Operator function call overload to allow call chaining.
+   * \param value the value to be inserted into the container
+   */
+  CollectionBuilder<CONT>& operator()(const value_type& value){
+    return push_back(value);
+  }
+  /** Same as regular STL push_back() but allows call chaining.
+   * \param value the value to be inserted into the container
+   */
+  CollectionBuilder<CONT>& push_back(const value_type& value){
+    collection_.push_back(value);
+    return *this;
+  }
+  /// \name Standard STL container interface
+  /// @{
+  const_iterator begin() const{return collection_.begin();}
+  const_iterator end() const{return collection_.end();}
+  size_type size() const{return collection_.size();}
+  void clear() {collection_.clear();}
+  ///@}
+  /// Explicit typecast operator.
+  operator const CollectionType&() const {return collection_;}
+private:
+  /// \cond PRIVATE
+  CollectionType collection_;
+  /// \endcond
+};
+
+
+// *********************************************************
+/** A shortcut to use for building dictionaries.
+ * This class is a wrapper around standard STL associative containers such as map.
+ * It allows one to conveniently build dictionaries at the variable initialization time:
+ * \code
+ * #include "CollectionUtil.h"
+ * #include "Map.h"  // for ostream << operator overload for STL map
+ * using Util;
+ * 
+ * int main()
+ * {
+ *   typedef map<string,int> MyMap;
+ *   MyMap myMap=DictionaryBuilder<MyMap>()("str1",1)("str2",2)("str3",3);
+ *   cout<<myMap;
+ *   // the following output will be produced:
+ *   // [str1=1,str2=2,str3=3]
+ * }
+ * \endcode
+ */
+template <class CONT>
+class DictionaryBuilder
+{
+public:
+  /// The type of the associative container
+  typedef CONT DictionaryType;
+  /// Container's element type (usually a pair<key_type,mapped_type>)
+  typedef typename DictionaryType::value_type value_type;
+  /// Container's key type
+  typedef typename DictionaryType::key_type key_type;
+  /// Container's value type 
+  typedef typename DictionaryType::mapped_type mapped_type;
+  /// Container's constant iterator type 
+  typedef typename DictionaryType::const_iterator const_iterator;
+  /// Container's writable iterator type   
+  typedef typename DictionaryType::iterator iterator;
+  /// Container's size type
+  typedef typename DictionaryType::size_type size_type;
+ 
+  /** Operator function call overload to allow call chaining.
+   * \param key the value key to be inserted
+   * \param value the value to be inserted into the container
+   * \return a non-const reference to self
+   */
+  DictionaryBuilder<CONT>& operator()(const key_type& key,const mapped_type& value){
+    dict_.insert(value_type(key,value));
+    return *this;
+  }
+  /** Lookup value by key.
+   * \param key the key associated with the value.
+   * \return a non-const iterator pointing to the element whose key matched the \a key parameter
+   */
+  iterator find(const key_type& key){
+    return dict_.find(key);
+  }
+  /** Lookup value by key.
+   * \param key the key associated with the value.
+   * \return a const iterator pointing to the element whose key matched the \a key parameter
+   */
+  const_iterator find(const key_type& key) const{
+    return dict_.find(key);
+  }
+
+  /// \name Standard STL container interface
+  /// @{
+  const_iterator begin() const{return dict_.begin();}
+  const_iterator end() const{return dict_.end();}
+  size_type size() const{return dict_.size();}
+  void clear() {dict_.clear();}
+  ///@}
+  /// Explicit typecast operator.
+  operator const DictionaryType&() const {return dict_;}
+private:
+  DictionaryType dict_;
+};
+
+
+// ***********************************************************
+/** Deletes all dynamically allocated elements of a collection.
+ * C::value_type is expected to be a pointer to a dynamically allocated object, or it won't compile.
+ * The function will iterate over all container elements and call delete for each of them.
+ * \param c a collection (vector,set) whose elements are being deleted.
+ */
+template <class C>
+void clearCollection(C& c){
+  for(typename C::const_iterator it=c.begin();it!=c.end();++it)
+    delete *it;
+  c.clear();
+}
+
+/** Deletes all dynamically allocated values of the assotiative container.
+ * The function expects the M::value_type to be a pair<..., ptr_to_type>, or it won't compile.
+ * It first deletes the objects pointed to by ptr_to_type
+ * and then clears (calls m.clear()) the container.
+ * \param m an associative container (map,hash_map) whose elements are being deleted.
+ */
+template <class M>
+void clearMap(M& m){
+  for(typename M::const_iterator it=m.begin();it!=m.end();++it)
+    delete it->second;
+  m.clear();
+}
+
+} // namespace Util
+
+
+#endif // _COLLECTION_UTIL_H_

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/CppAssertHelper.h
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/CppAssertHelper.h b/zookeeper-client/zookeeper-client-c/tests/CppAssertHelper.h
new file mode 100644
index 0000000..3926f51
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/CppAssertHelper.h
@@ -0,0 +1,37 @@
+/**
+ * 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 CPPASSERTHELPER_H_
+#define CPPASSERTHELPER_H_
+
+#include <cppunit/TestAssert.h>
+
+// make it possible to specify location of the ASSERT call
+#define CPPUNIT_ASSERT_EQUAL_LOC(expected,actual,file,line) \
+  ( CPPUNIT_NS::assertEquals( (expected),              \
+                              (actual),                \
+                              CPPUNIT_NS::SourceLine(file,line),    \
+                              "" ) )
+
+#define CPPUNIT_ASSERT_EQUAL_MESSAGE_LOC(message,expected,actual,file,line) \
+  ( CPPUNIT_NS::assertEquals( (expected),              \
+                              (actual),                \
+                              CPPUNIT_NS::SourceLine(file,line), \
+                              (message) ) )
+
+#endif /*CPPASSERTHELPER_H_*/

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/LibCMocks.cc
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/LibCMocks.cc b/zookeeper-client/zookeeper-client-c/tests/LibCMocks.cc
new file mode 100644
index 0000000..870a554
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/LibCMocks.cc
@@ -0,0 +1,347 @@
+/**
+ * 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 <cstdlib>
+#include <cstdarg>
+#include <iostream>
+#include <unistd.h> // needed for _POSIX_MONOTONIC_CLOCK
+#include <stdarg.h>
+
+#include "Util.h"
+#include "LibCMocks.h"
+
+#undef USING_DUMA
+
+using namespace std;
+
+// *****************************************************************************
+// gethostbyname
+
+struct hostent* gethostbyname(const char *name) {
+    if(!Mock_gethostbyname::mock_)
+        return LIBC_SYMBOLS.gethostbyname(name);
+    return Mock_gethostbyname::mock_->call(name);
+}
+
+Mock_gethostbyname* Mock_gethostbyname::mock_=0;
+
+Mock_gethostbyname::~Mock_gethostbyname(){
+    mock_=0;
+    for(unsigned int i=0;i<gethostbynameReturns.size();i++)
+        delete gethostbynameReturns[i];
+}
+
+Mock_gethostbyname::HostEntry& Mock_gethostbyname::addHostEntry(
+        const char* hostName, short addrtype) {
+    gethostbynameReturns.push_back(new HostEntry(hostName, addrtype));
+    return *gethostbynameReturns.back();
+}
+
+hostent* Mock_gethostbyname::call(const char* name) {
+    assert("Must add one or more mock hostent entries first"&&
+            (gethostbynameReturns.size()!=0));
+    return gethostbynameReturns[current++ % gethostbynameReturns.size()];
+}
+
+static char** appendString(char **list,const char* str,int len=0){
+    const int SIZE_INCREMENT=16;
+    if(list==0)
+        list=(char**)LIBC_SYMBOLS.calloc(SIZE_INCREMENT,sizeof(char*));
+    // find the first available slot
+    int count=0;
+    for(char** ptr=list; *ptr!=0; ptr++,count++);
+    if(((count+1)%SIZE_INCREMENT)==0){
+        list=(char**)LIBC_SYMBOLS.realloc(list,(count+1+SIZE_INCREMENT)*sizeof(char*));
+        memset(list+count+1,0,SIZE_INCREMENT*sizeof(char*));
+    }
+    if(len==0){
+        len=strlen(str)+1;
+    }
+    char* ptr=(char*)malloc(len);
+    memcpy(ptr,str,len);
+    list[count]=ptr;
+    return list;
+}
+
+static void freeList(char **list){
+    if(list==0) return;
+    for(char** ptr=list; *ptr!=0; ptr++)
+        LIBC_SYMBOLS.free((void*)*ptr);
+    LIBC_SYMBOLS.free((void*)list);
+}
+
+Mock_gethostbyname::HostEntry::HostEntry(const char* hostName, short addrtype) {
+    h_name=strdup(hostName);
+    h_addrtype=addrtype;
+    if(addrtype==AF_INET)
+        h_length=4;
+    else{
+#ifdef AF_INET6
+        h_length=6; // TODO: not really sure, verify!
+#else
+        assert("AF_INET6 not supported yet"&&false);
+#endif
+    }
+    h_aliases=h_addr_list=0;
+}
+
+Mock_gethostbyname::HostEntry::~HostEntry(){
+    if(h_name) LIBC_SYMBOLS.free((void*)h_name);
+    freeList(h_aliases); h_aliases=0;
+    freeList(h_addr_list); h_addr_list=0;
+}
+
+Mock_gethostbyname::HostEntry& Mock_gethostbyname::HostEntry::addAlias(
+        const char* alias) {
+    h_aliases=appendString(h_aliases,alias);
+    return *this;
+}
+
+Mock_gethostbyname::HostEntry& Mock_gethostbyname::HostEntry::addAddress(
+        const char* addr4) {
+    h_addr_list=appendString(h_addr_list,addr4,4);
+    return *this;
+}
+
+
+// *****************************************************************************
+// calloc
+#ifndef USING_DUMA
+DECLARE_WRAPPER(void*,calloc,(size_t p1, size_t p2)){
+    if(!Mock_calloc::mock_)
+        return CALL_REAL(calloc,(p1,p2));
+    return Mock_calloc::mock_->call(p1,p2);
+}
+#endif
+
+void* Mock_calloc::call(size_t p1, size_t p2){
+#ifndef USING_DUMA
+    if(counter++ ==callsBeforeFailure){
+        counter=0;
+        errno=errnoOnFailure;
+        return 0;
+    }
+    return CALL_REAL(calloc,(p1,p2));
+#else
+    return 0;
+#endif
+}
+
+Mock_calloc* Mock_calloc::mock_=0;
+
+// *****************************************************************************
+// realloc
+
+#ifndef USING_DUMA
+DECLARE_WRAPPER(void*,realloc,(void* p, size_t s)){
+    if(!Mock_realloc::mock_)
+        return LIBC_SYMBOLS.realloc(p,s);
+    return Mock_realloc::mock_->call(p,s);
+}
+#endif
+
+Mock_realloc* Mock_realloc::mock_=0;
+
+void* Mock_realloc::call(void* p, size_t s){
+    if(counter++ ==callsBeforeFailure){
+        counter=0;
+        errno=errnoOnFailure;
+        return 0;
+    }
+    return LIBC_SYMBOLS.realloc(p,s);
+}
+
+// *****************************************************************************
+// random
+RANDOM_RET_TYPE random(){
+    if(!Mock_random::mock_)
+        return LIBC_SYMBOLS.random();
+    return Mock_random::mock_->call();    
+}
+
+void srandom(unsigned long seed){
+    if (!Mock_random::mock_)
+        LIBC_SYMBOLS.srandom(seed);
+    else
+        Mock_random::mock_->setSeed(seed);
+}
+
+Mock_random* Mock_random::mock_=0;
+
+int Mock_random::call(){
+    assert("Must specify one or more random integers"&&(randomReturns.size()!=0));
+    return randomReturns[currentIdx++ % randomReturns.size()];
+}
+
+// *****************************************************************************
+// free
+#ifndef USING_DUMA
+DECLARE_WRAPPER(void,free,(void* p)){
+    if(Mock_free_noop::mock_ && !Mock_free_noop::mock_->nested)
+        Mock_free_noop::mock_->call(p);
+    else
+        CALL_REAL(free,(p));
+}
+#endif
+
+void Mock_free_noop::call(void* p){
+    // on cygwin libc++ is linked statically
+    // push_back() may call free(), hence the nesting guards
+    synchronized(mx);
+    nested++;
+    callCounter++;
+    requested.push_back(p);
+    nested--;
+}
+void Mock_free_noop::freeRequested(){
+#ifndef USING_DUMA
+    synchronized(mx);
+    for(unsigned i=0; i<requested.size();i++)
+        CALL_REAL(free,(requested[i]));
+#endif
+}
+
+int Mock_free_noop::getFreeCount(void* p){
+    int cnt=0;
+    synchronized(mx);
+    for(unsigned i=0;i<requested.size();i++)
+        if(requested[i]==p)cnt++;
+    return cnt;
+}
+
+bool Mock_free_noop::isFreed(void* p){
+    synchronized(mx);
+    for(unsigned i=0;i<requested.size();i++)
+        if(requested[i]==p)return true;
+    return false;
+}
+
+Mock_free_noop* Mock_free_noop::mock_=0;
+
+// *****************************************************************************
+// socket
+int socket(int domain, int type, int protocol){
+    if (!Mock_socket::mock_)
+        return LIBC_SYMBOLS.socket(domain,type,protocol);
+    return Mock_socket::mock_->callSocket(domain,type,protocol);
+}
+
+int close(int fd){
+    if (!Mock_socket::mock_)
+        return LIBC_SYMBOLS.close(fd);
+    return Mock_socket::mock_->callClose(fd);
+}
+
+int getsockopt(int s,int level,int optname,void *optval,socklen_t *optlen){
+    if (!Mock_socket::mock_)
+        return LIBC_SYMBOLS.getsockopt(s,level,optname,optval,optlen);
+    return Mock_socket::mock_->callGet(s,level,optname,optval,optlen);    
+}
+
+int setsockopt(int s,int level,int optname,const void *optval,socklen_t optlen){
+    if (!Mock_socket::mock_)
+        return LIBC_SYMBOLS.setsockopt(s,level,optname,optval,optlen);
+    return Mock_socket::mock_->callSet(s,level,optname,optval,optlen);      
+}
+int connect(int s,const struct sockaddr *addr,socklen_t len){
+    if (!Mock_socket::mock_)
+        return LIBC_SYMBOLS.connect(s,addr,len);
+    return Mock_socket::mock_->callConnect(s,addr,len);
+}
+ssize_t send(int s,const void *buf,size_t len,int flags){
+    if (!Mock_socket::mock_)
+        return LIBC_SYMBOLS.send(s,buf,len,flags);
+    return Mock_socket::mock_->callSend(s,buf,len,flags);    
+}
+
+ssize_t recv(int s,void *buf,size_t len,int flags){
+    if (!Mock_socket::mock_)
+        return LIBC_SYMBOLS.recv(s,buf,len,flags);
+    return Mock_socket::mock_->callRecv(s,buf,len,flags);        
+}
+
+Mock_socket* Mock_socket::mock_=0;
+
+// *****************************************************************************
+// fcntl
+extern "C" int fcntl(int fd,int cmd,...){
+    va_list va;
+    va_start(va,cmd);
+    void* arg = va_arg(va, void *);
+    va_end (va);
+    if (!Mock_fcntl::mock_)
+        return LIBC_SYMBOLS.fcntl(fd,cmd,arg);
+    return Mock_fcntl::mock_->call(fd,cmd,arg);    
+}
+
+Mock_fcntl* Mock_fcntl::mock_=0;
+
+// *****************************************************************************
+// select
+int select(int nfds,fd_set *rfds,fd_set *wfds,fd_set *efds,struct timeval *timeout){
+    if (!Mock_select::mock_)
+        return LIBC_SYMBOLS.select(nfds,rfds,wfds,efds,timeout);
+    return Mock_select::mock_->call(nfds,rfds,wfds,efds,timeout);        
+}
+
+Mock_select* Mock_select::mock_=0;
+
+// *****************************************************************************
+// poll
+Mock_poll* Mock_poll::mock_=0;
+int poll(struct pollfd *fds, POLL_NFDS_TYPE nfds, int timeout){
+    if (!Mock_poll::mock_)
+        return LIBC_SYMBOLS.poll(fds,nfds,timeout);
+    return Mock_poll::mock_->call(fds,nfds,timeout);        
+    
+}
+
+/*
+ * Recent gcc with -O2 and glibc FORTIFY feature may cause our poll
+ * mock to be ignored.
+ */
+#if __USE_FORTIFY_LEVEL > 0
+int __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout,
+                __SIZE_TYPE__ __fdslen) {
+    return poll(__fds, __nfds, __timeout);
+}
+#endif
+
+// *****************************************************************************
+// gettimeofday
+int gettimeofday(struct timeval *tp, GETTIMEOFDAY_ARG2_TYPE tzp){
+    if (!Mock_gettimeofday::mock_)
+        return LIBC_SYMBOLS.gettimeofday(tp,tzp);
+    return Mock_gettimeofday::mock_->call(tp,tzp);            
+}
+
+Mock_gettimeofday* Mock_gettimeofday::mock_=0;
+
+// *****************************************************************************
+#ifdef _POSIX_MONOTONIC_CLOCK
+// clock_gettime
+int clock_gettime(clockid_t id, struct timespec *tp) {
+    if (!Mock_gettimeofday::mock_)
+        return LIBC_SYMBOLS.clock_gettime(id,tp);
+    struct timeval tv = { 0 };
+    int res = Mock_gettimeofday::mock_->call(&tv, NULL);
+    tp->tv_sec = tv.tv_sec;
+    tp->tv_nsec = tv.tv_usec * 1000;
+    return res;
+}
+#endif

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/LibCMocks.h
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/LibCMocks.h b/zookeeper-client/zookeeper-client-c/tests/LibCMocks.h
new file mode 100644
index 0000000..5b07cda
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/LibCMocks.h
@@ -0,0 +1,408 @@
+/**
+ * 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 LIBCMOCKS_H_
+#define LIBCMOCKS_H_
+
+#include <string>
+#include <vector>
+#include <deque>
+
+#include <errno.h>
+#include <string.h>
+
+#include "MocksBase.h"
+#include "LibCSymTable.h"
+#include "ThreadingUtil.h"
+
+// *****************************************************************************
+// gethostbyname
+
+class Mock_gethostbyname: public Mock
+{
+public:
+    struct HostEntry: public hostent {
+        HostEntry(const char* hostName,short addrtype);
+        ~HostEntry();
+        HostEntry& addAlias(const char* alias);
+        HostEntry& addAddress(const char* addr4);
+    };
+
+    Mock_gethostbyname():current(0){mock_=this;}
+    virtual ~Mock_gethostbyname();
+    HostEntry& addHostEntry(const char* hostName,short addrtype=AF_INET);
+    virtual hostent* call(const char* name);
+
+    typedef std::vector<HostEntry*> HostEntryCollection;
+    HostEntryCollection gethostbynameReturns;
+    int current;
+    static Mock_gethostbyname* mock_;
+};
+
+class MockFailed_gethostbyname: public Mock_gethostbyname
+{
+public:
+    MockFailed_gethostbyname():h_errnoReturn(HOST_NOT_FOUND) {}
+
+    int h_errnoReturn;
+    virtual hostent* call(const char* name) {
+        h_errno=h_errnoReturn;
+        return 0;
+    }
+};
+
+// *****************************************************************************
+// calloc
+
+class Mock_calloc: public Mock
+{
+public:
+    Mock_calloc():errnoOnFailure(ENOMEM),callsBeforeFailure(-1),counter(0) {
+        mock_=this;
+    }
+    virtual ~Mock_calloc() {mock_=0;}
+
+    int errnoOnFailure;
+    int callsBeforeFailure;
+    int counter;
+    virtual void* call(size_t p1, size_t p2);
+
+    static Mock_calloc* mock_;
+};
+
+// *****************************************************************************
+// realloc
+
+class Mock_realloc: public Mock
+{
+public:
+    Mock_realloc():errnoOnFailure(ENOMEM),callsBeforeFailure(-1),counter(0) {
+        mock_=this;
+    }
+    virtual ~Mock_realloc() {mock_=0;}
+
+    int errnoOnFailure;
+    int callsBeforeFailure;
+    int counter;
+    virtual void* call(void* p, size_t s);
+
+    static Mock_realloc* mock_;
+};
+
+// *****************************************************************************
+// random
+
+class Mock_random: public Mock
+{
+public:
+    Mock_random():currentIdx(0) {mock_=this;}
+    virtual ~Mock_random() {mock_=0;}
+
+    int currentIdx;
+    std::vector<int> randomReturns;
+    virtual int call();
+    void setSeed(unsigned long){currentIdx=0;}
+
+    static Mock_random* mock_;
+};
+
+// *****************************************************************************
+// no-op free; keeps track of all deallocation requests
+class Mock_free_noop: public Mock
+{
+    Mutex mx;
+    std::vector<void*> requested;
+public:
+    Mock_free_noop():nested(0),callCounter(0){mock_=this;}
+    virtual ~Mock_free_noop(){
+        mock_=0;
+        freeRequested();
+    }
+    
+    int nested;
+    int callCounter;
+    virtual void call(void* p);
+    void freeRequested();
+    void disable(){mock_=0;}
+    // returns number of times the pointer was freed
+    int getFreeCount(void*);
+    bool isFreed(void*);
+    
+    static Mock_free_noop* mock_;
+};
+
+// *****************************************************************************
+// socket and related system calls
+
+class Mock_socket: public Mock
+{
+public:
+    static const int FD=63;
+    Mock_socket():socketReturns(FD),closeReturns(0),getsocketoptReturns(0),
+        optvalSO_ERROR(0),
+        setsockoptReturns(0),connectReturns(0),connectErrno(0),
+        sendErrno(0),recvErrno(0)
+    {
+        mock_=this;
+    }
+    virtual ~Mock_socket(){mock_=0;}
+
+    int socketReturns;
+    virtual int callSocket(int domain, int type, int protocol){
+        return socketReturns;
+    }
+    int closeReturns;
+    virtual int callClose(int fd){
+        return closeReturns;
+    }
+    int getsocketoptReturns;
+    int optvalSO_ERROR;
+    virtual int callGet(int s,int level,int optname,void *optval,socklen_t *len){
+        if(level==SOL_SOCKET && optname==SO_ERROR){
+            setSO_ERROR(optval,*len);
+        }
+        return getsocketoptReturns;
+    }
+    virtual void setSO_ERROR(void *optval,socklen_t len){
+        memcpy(optval,&optvalSO_ERROR,len);
+    }
+    
+    int setsockoptReturns;
+    virtual int callSet(int s,int level,int optname,const void *optval,socklen_t len){
+        return setsockoptReturns;
+    }
+    int connectReturns;
+    int connectErrno;
+    virtual int callConnect(int s,const struct sockaddr *addr,socklen_t len){
+        errno=connectErrno;
+        return connectReturns;
+    }
+    
+    virtual void notifyBufferSent(const std::string& buffer){}
+    
+    int sendErrno;
+    std::string sendBuffer;
+    virtual ssize_t callSend(int s,const void *buf,size_t len,int flags){
+        if(sendErrno!=0){
+            errno=sendErrno;
+            return -1;
+        }
+        // first call to send() is always the length of the buffer to follow
+        bool sendingLength=sendBuffer.size()==0;
+        // overwrite the length bytes
+        sendBuffer.assign((const char*)buf,len);
+        if(!sendingLength){
+            notifyBufferSent(sendBuffer);
+            sendBuffer.erase();
+        }
+        return len;
+    }
+
+    int recvErrno;
+    std::string recvReturnBuffer;
+    virtual ssize_t callRecv(int s,void *buf,size_t len,int flags){
+        if(recvErrno!=0){
+            errno=recvErrno;
+            return -1;
+        }
+        int k=std::min(len,recvReturnBuffer.length());
+        if(k==0)
+            return 0;
+        memcpy(buf,recvReturnBuffer.data(),k);
+        recvReturnBuffer.erase(0,k);
+        return k;
+    }
+    virtual bool hasMoreRecv() const{
+        return recvReturnBuffer.size()!=0;
+    }
+    static Mock_socket* mock_;
+};
+
+// *****************************************************************************
+// fcntl
+class Mock_fcntl: public Mock
+{
+public:
+    Mock_fcntl():callReturns(0),trapFD(-1){mock_=this;}
+    ~Mock_fcntl(){mock_=0;}
+    
+    int callReturns;
+    int trapFD;
+    virtual int call(int fd, int cmd, void* arg){
+        if(trapFD==-1)
+            return LIBC_SYMBOLS.fcntl(fd,cmd,arg);
+        return callReturns;
+    }
+
+    static Mock_fcntl* mock_;
+};
+
+// *****************************************************************************
+// select
+class Mock_select: public Mock
+{
+public:
+    Mock_select(Mock_socket* s,int fd):sock(s),
+        callReturns(0),myFD(fd),timeout(50)
+    {
+        mock_=this;
+    }
+    ~Mock_select(){mock_=0;}
+    
+    Mock_socket* sock;
+    int callReturns;
+    int myFD;
+    int timeout; //in millis
+    virtual int call(int nfds,fd_set *rfds,fd_set *wfds,fd_set *efds,struct timeval *tv){
+        bool isWritableRequested=(wfds && FD_ISSET(myFD,wfds));
+        if(rfds) FD_CLR(myFD,rfds);
+        if(wfds) FD_CLR(myFD,wfds);
+        // this timeout is only to prevent a tight loop
+        timeval myTimeout={0,0};
+        if(!isWritableRequested && !isFDReadable()){
+            myTimeout.tv_sec=timeout/1000;
+            myTimeout.tv_usec=(timeout%1000)*1000;
+        }
+        LIBC_SYMBOLS.select(nfds,rfds,wfds,efds,&myTimeout);
+        // myFD is always writable
+        if(isWritableRequested) FD_SET(myFD,wfds);
+        // myFD is only readable if the socket has anything to read
+        if(isFDReadable() && rfds) FD_SET(myFD,rfds);
+        return callReturns;
+    }
+
+    virtual bool isFDReadable() const {
+        return sock->hasMoreRecv();
+    }
+    
+    static Mock_select* mock_;
+};
+
+// *****************************************************************************
+// poll
+// the last element of the pollfd array is expected to be test FD
+class Mock_poll: public Mock
+{
+public:
+    Mock_poll(Mock_socket* s,int fd):sock(s),
+        callReturns(1),myFD(fd),timeout(50)
+    {
+        mock_=this;
+    }
+    ~Mock_poll(){mock_=0;}
+    
+    Mock_socket* sock;
+    int callReturns;
+    int myFD;
+    int timeout; //in millis
+    virtual int call(struct pollfd *fds, POLL_NFDS_TYPE nfds, int to) {
+        pollfd* myPoll=0;
+        if(fds[nfds-1].fd==myFD)
+            myPoll=&fds[nfds-1];
+        bool isWritableRequested=false;
+        if(myPoll!=0){
+            isWritableRequested=myPoll->events&POLLOUT;
+            nfds--;
+        }
+        LIBC_SYMBOLS.poll(fds,nfds,(!isWritableRequested&&!isFDReadable())?timeout:0);
+        if(myPoll!=0){
+            // myFD is always writable if requested
+            myPoll->revents=isWritableRequested?POLLOUT:0;
+            // myFD is only readable if the socket has anything to read
+            myPoll->revents|=isFDReadable()?POLLIN:0;
+        }
+        return callReturns;
+    }
+
+    virtual bool isFDReadable() const {
+        return sock->hasMoreRecv();
+    }
+    
+    static Mock_poll* mock_;
+};
+
+// *****************************************************************************
+// gettimeofday
+class Mock_gettimeofday: public Mock
+{
+public:
+    Mock_gettimeofday(){
+        LIBC_SYMBOLS.gettimeofday(&tv,0);
+        mock_=this;
+    }
+    Mock_gettimeofday(const Mock_gettimeofday& other):tv(other.tv){}
+    Mock_gettimeofday(int32_t sec,int32_t usec){
+        tv.tv_sec=sec;
+        tv.tv_usec=usec;
+    }
+    ~Mock_gettimeofday(){mock_=0;}
+    
+    timeval tv;
+    virtual int call(struct timeval *tp, GETTIMEOFDAY_ARG2_TYPE tzp){
+        *tp=tv;
+        return 0;
+    }
+    operator timeval() const{
+        return tv;
+    }
+    // advance secs
+    virtual void tick(int howmuch=1){tv.tv_sec+=howmuch;}
+    // advance milliseconds
+    // can move the clock forward as well as backward by providing a negative
+    // number
+    virtual void millitick(int howmuch=1){
+        int ms=tv.tv_usec/1000+howmuch;
+        tv.tv_sec+=ms/1000;
+        // going backward?
+        if(ms<0){
+            ms=1000-(-ms%1000); //wrap millis around
+        }
+        tv.tv_usec=(ms%1000)*1000;
+    }
+    virtual void tick(const timeval& howmuch){
+        // add milliseconds (discarding microsecond portion)
+        long ms=tv.tv_usec/1000+howmuch.tv_usec/1000;
+        tv.tv_sec+=howmuch.tv_sec+ms/1000;
+        tv.tv_usec=(ms%1000)*1000;
+    }
+    static Mock_gettimeofday* mock_;
+};
+
+// discard microseconds!
+inline bool operator==(const timeval& lhs, const timeval& rhs){
+    return rhs.tv_sec==lhs.tv_sec && rhs.tv_usec/1000==lhs.tv_usec/1000;
+}
+
+// simplistic implementation: no normalization, assume lhs >= rhs,
+// discarding microseconds
+inline timeval operator-(const timeval& lhs, const timeval& rhs){
+    timeval res;
+    res.tv_sec=lhs.tv_sec-rhs.tv_sec;
+    res.tv_usec=(lhs.tv_usec/1000-rhs.tv_usec/1000)*1000;
+    if(res.tv_usec<0){
+        res.tv_sec--;
+        res.tv_usec=1000000+res.tv_usec%1000000; // wrap the millis around
+    }
+    return res;
+}
+
+inline int32_t toMilliseconds(const timeval& tv){
+    return tv.tv_sec*1000+tv.tv_usec/1000;    
+}
+
+#endif /*LIBCMOCKS_H_*/

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.cc
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.cc b/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.cc
new file mode 100644
index 0000000..23862f3
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.cc
@@ -0,0 +1,87 @@
+/**
+ * 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 "LibCSymTable.h" 
+#include <unistd.h> // needed for _POSIX_MONOTONIC_CLOCK
+
+#define LOAD_SYM(sym) \
+    sym=(sym##_sig)dlsym(handle,#sym); \
+    assert("Unable to load "#sym" from libc"&&sym)      
+    
+
+LibCSymTable& LibCSymTable::instance(){
+    static LibCSymTable tbl;
+    return tbl;
+}
+
+//******************************************************************************
+// preload original libc symbols
+LibCSymTable::LibCSymTable()
+{
+    void* handle=getHandle();
+    LOAD_SYM(gethostbyname);
+    LOAD_SYM(calloc);
+    LOAD_SYM(realloc);
+    LOAD_SYM(free);
+    LOAD_SYM(random);
+    LOAD_SYM(srandom);
+    LOAD_SYM(printf);
+    LOAD_SYM(socket);
+    LOAD_SYM(close);
+    LOAD_SYM(getsockopt);
+    LOAD_SYM(setsockopt);
+    LOAD_SYM(fcntl);
+    LOAD_SYM(connect);
+    LOAD_SYM(send);
+    LOAD_SYM(recv);
+    LOAD_SYM(select);
+    LOAD_SYM(poll);
+    LOAD_SYM(gettimeofday);
+#ifdef _POSIX_MONOTONIC_CLOCK
+    LOAD_SYM(clock_gettime);
+#endif
+#ifdef THREADED
+    LOAD_SYM(pthread_create);
+    LOAD_SYM(pthread_detach);
+    LOAD_SYM(pthread_cond_broadcast);
+    LOAD_SYM(pthread_cond_destroy);
+    LOAD_SYM(pthread_cond_init);
+    LOAD_SYM(pthread_cond_signal);
+    LOAD_SYM(pthread_cond_timedwait);
+    LOAD_SYM(pthread_cond_wait);
+    LOAD_SYM(pthread_join);
+    LOAD_SYM(pthread_mutex_destroy);
+    LOAD_SYM(pthread_mutex_init);
+    LOAD_SYM(pthread_mutex_lock);
+    LOAD_SYM(pthread_mutex_trylock);
+    LOAD_SYM(pthread_mutex_unlock);
+#endif
+}
+
+void* LibCSymTable::getHandle(){
+    static void* handle=0;
+    if(!handle){
+#ifdef __CYGWIN__
+        handle=dlopen("cygwin1.dll",RTLD_LAZY);
+        assert("Unable to dlopen global sym table"&&handle);
+#else
+        handle=RTLD_NEXT;
+#endif
+    }
+    return handle;
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.h
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.h b/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.h
new file mode 100644
index 0000000..1b6f9db
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.h
@@ -0,0 +1,111 @@
+/**
+ * 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 LIBCSYMTABLE_H_
+#define LIBCSYMTABLE_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stddef.h>
+#include <dlfcn.h>
+#include <cassert>
+#include <poll.h>
+#include <unistd.h> // needed for _POSIX_MONOTONIC_CLOCK
+
+#ifdef THREADED
+#include <pthread.h>
+#endif
+
+#include "config.h"
+
+// TODO: move all these macros to config.h (generated by autoconf) 
+#ifdef __CYGWIN__
+#if (CYGWIN_VERSION_DLL_MAJOR < 1007)
+#define RANDOM_RET_TYPE int
+#else
+#define RANDOM_RET_TYPE long int
+#endif
+#define GETTIMEOFDAY_ARG2_TYPE void*
+#else
+#define RANDOM_RET_TYPE long int
+#define GETTIMEOFDAY_ARG2_TYPE struct timezone*
+#endif
+
+#define DECLARE_SYM(ret,sym,sig) \
+    typedef ret (*sym##_sig)sig; \
+    static sym##_sig preload_##sym () { \
+        static sym##_sig ptr=0;\
+        if(!ptr){ void* h=getHandle(); ptr=(sym##_sig)dlsym(h,#sym); } \
+        assert("Unable to load "#sym" from libc"&&ptr); \
+        return ptr; \
+    } \
+    sym##_sig sym
+
+#define LIBC_SYMBOLS LibCSymTable::instance()
+
+//******************************************************************************
+// preload original libc symbols
+struct LibCSymTable
+{
+    DECLARE_SYM(hostent*,gethostbyname,(const char*));
+    DECLARE_SYM(void*,calloc,(size_t, size_t));
+    DECLARE_SYM(void*,realloc,(void*, size_t));
+    DECLARE_SYM(void,free,(void*));
+    DECLARE_SYM(RANDOM_RET_TYPE,random,(void));
+    DECLARE_SYM(void,srandom,(unsigned long));
+    DECLARE_SYM(int,printf,(const char*, ...));
+    DECLARE_SYM(int,socket,(int,int,int));
+    DECLARE_SYM(int,close,(int));
+    DECLARE_SYM(int,getsockopt,(int,int,int,void*,socklen_t*));
+    DECLARE_SYM(int,setsockopt,(int,int,int,const void*,socklen_t));
+    DECLARE_SYM(int,fcntl,(int,int,...));
+    DECLARE_SYM(int,connect,(int,const struct sockaddr*,socklen_t));
+    DECLARE_SYM(ssize_t,send,(int,const void*,size_t,int));
+    DECLARE_SYM(ssize_t,recv,(int,const void*,size_t,int));
+    DECLARE_SYM(int,select,(int,fd_set*,fd_set*,fd_set*,struct timeval*));
+    DECLARE_SYM(int,poll,(struct pollfd*,POLL_NFDS_TYPE,int));
+    DECLARE_SYM(int,gettimeofday,(struct timeval*,GETTIMEOFDAY_ARG2_TYPE));
+#ifdef _POSIX_MONOTONIC_CLOCK
+    DECLARE_SYM(int,clock_gettime,(clockid_t clk_id, struct timespec*));
+#endif
+#ifdef THREADED
+    DECLARE_SYM(int,pthread_create,(pthread_t *, const pthread_attr_t *,
+                void *(*)(void *), void *));
+    DECLARE_SYM(int,pthread_detach,(pthread_t));
+    DECLARE_SYM(int,pthread_cond_broadcast,(pthread_cond_t *));
+    DECLARE_SYM(int,pthread_cond_destroy,(pthread_cond_t *));
+    DECLARE_SYM(int,pthread_cond_init,(pthread_cond_t *, const pthread_condattr_t *));
+    DECLARE_SYM(int,pthread_cond_signal,(pthread_cond_t *));
+    DECLARE_SYM(int,pthread_cond_timedwait,(pthread_cond_t *,
+                    pthread_mutex_t *, const struct timespec *));
+    DECLARE_SYM(int,pthread_cond_wait,(pthread_cond_t *, pthread_mutex_t *));
+    DECLARE_SYM(int,pthread_join,(pthread_t, void **));
+    DECLARE_SYM(int,pthread_mutex_destroy,(pthread_mutex_t *));
+    DECLARE_SYM(int,pthread_mutex_init,(pthread_mutex_t *, const pthread_mutexattr_t *));
+    DECLARE_SYM(int,pthread_mutex_lock,(pthread_mutex_t *));
+    DECLARE_SYM(int,pthread_mutex_trylock,(pthread_mutex_t *));
+    DECLARE_SYM(int,pthread_mutex_unlock,(pthread_mutex_t *));
+#endif
+    LibCSymTable();
+    
+    static void* getHandle();
+    static LibCSymTable& instance();
+};
+
+#endif /*LIBCSYMTABLE_H_*/

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/MocksBase.cc
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/MocksBase.cc b/zookeeper-client/zookeeper-client-c/tests/MocksBase.cc
new file mode 100644
index 0000000..60b2c75
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/MocksBase.cc
@@ -0,0 +1,36 @@
+/**
+ * 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 <cstdlib>
+#include <new>
+
+#include "MocksBase.h"
+#include "LibCSymTable.h"
+
+// *****************************************************************************
+// Mock base
+void* Mock::operator new(std::size_t s){
+    void* p=malloc(s);
+    if(!p)
+        throw std::bad_alloc();
+    return p;
+}
+
+void Mock::operator delete(void* p){
+    LIBC_SYMBOLS.free(p);
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/MocksBase.h
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/MocksBase.h b/zookeeper-client/zookeeper-client-c/tests/MocksBase.h
new file mode 100644
index 0000000..5b54251
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/MocksBase.h
@@ -0,0 +1,36 @@
+/**
+ * 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 MOCKSBASE_H_
+#define MOCKSBASE_H_
+
+#include <cstddef>
+
+// *****************************************************************************
+// Mock base
+
+class Mock
+{
+public:
+    virtual ~Mock(){}
+
+    static void* operator new(std::size_t s);
+    static void operator delete(void* p);
+};
+
+#endif /*MOCKSBASE_H_*/

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/PthreadMocks.cc
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/PthreadMocks.cc b/zookeeper-client/zookeeper-client-c/tests/PthreadMocks.cc
new file mode 100644
index 0000000..490cebf
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/PthreadMocks.cc
@@ -0,0 +1,106 @@
+/**
+ * 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 "PthreadMocks.h"
+
+MockPthreadsBase* MockPthreadsBase::mock_=0;
+
+#undef USING_DUMA
+
+#ifndef USING_DUMA
+int pthread_cond_broadcast (pthread_cond_t *c){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_cond_broadcast(c);
+    return MockPthreadsBase::mock_->pthread_cond_broadcast(c);
+}
+int pthread_cond_destroy (pthread_cond_t *c){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_cond_destroy(c);
+    return MockPthreadsBase::mock_->pthread_cond_destroy(c);
+}
+int pthread_cond_init (pthread_cond_t *c, const pthread_condattr_t *a){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_cond_init(c,a);
+    return MockPthreadsBase::mock_->pthread_cond_init(c,a);
+}
+int pthread_cond_signal (pthread_cond_t *c){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_cond_signal(c);
+    return MockPthreadsBase::mock_->pthread_cond_signal(c);
+}
+int pthread_cond_timedwait (pthread_cond_t *c,
+                pthread_mutex_t *m, const struct timespec *t){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_cond_timedwait(c,m,t);
+    return MockPthreadsBase::mock_->pthread_cond_timedwait(c,m,t);
+}
+int pthread_cond_wait (pthread_cond_t *c, pthread_mutex_t *m){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_cond_wait(c,m);
+    return MockPthreadsBase::mock_->pthread_cond_wait(c,m);
+}
+int pthread_create (pthread_t *t, const pthread_attr_t *a,
+            void *(*f)(void *), void *d){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_create(t,a,f,d);
+    return MockPthreadsBase::mock_->pthread_create(t,a,f,d);
+}
+int pthread_detach(pthread_t t){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_detach(t);
+    return MockPthreadsBase::mock_->pthread_detach(t);    
+}
+int pthread_join (pthread_t t, void **r){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_join(t,r);
+    return MockPthreadsBase::mock_->pthread_join(t,r);
+}
+int pthread_mutex_destroy (pthread_mutex_t *m){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_mutex_destroy(m);
+    return MockPthreadsBase::mock_->pthread_mutex_destroy(m);
+}
+int pthread_mutex_init (pthread_mutex_t *m, const pthread_mutexattr_t *a){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_mutex_init(m,a);
+    return MockPthreadsBase::mock_->pthread_mutex_init(m,a);
+}
+
+DECLARE_WRAPPER(int,pthread_mutex_lock,(pthread_mutex_t *m)){
+    if(!MockPthreadsBase::mock_)
+        return CALL_REAL(pthread_mutex_lock,(m));
+    return MockPthreadsBase::mock_->pthread_mutex_lock(m);
+}
+
+int pthread_mutex_trylock (pthread_mutex_t *m){
+    if(!MockPthreadsBase::mock_)
+        return LIBC_SYMBOLS.pthread_mutex_trylock(m);
+    return MockPthreadsBase::mock_->pthread_mutex_trylock(m);
+}
+
+DECLARE_WRAPPER(int,pthread_mutex_unlock,(pthread_mutex_t *m)){
+    if(!MockPthreadsBase::mock_)
+        return CALL_REAL(pthread_mutex_unlock,(m));
+    return MockPthreadsBase::mock_->pthread_mutex_unlock(m);
+}
+#endif
+
+CheckedPthread::ThreadMap CheckedPthread::tmap_;
+CheckedPthread::MutexMap CheckedPthread::mmap_;
+CheckedPthread::CVMap CheckedPthread::cvmap_;
+Mutex CheckedPthread::mx;

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/176bd682/zookeeper-client/zookeeper-client-c/tests/PthreadMocks.h
----------------------------------------------------------------------
diff --git a/zookeeper-client/zookeeper-client-c/tests/PthreadMocks.h b/zookeeper-client/zookeeper-client-c/tests/PthreadMocks.h
new file mode 100644
index 0000000..3584ec3
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/PthreadMocks.h
@@ -0,0 +1,449 @@
+/**
+ * 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 PTHREADMOCKS_H_
+#define PTHREADMOCKS_H_
+
+#include <pthread.h>
+#include <string.h>
+#include <errno.h>
+
+#include "src/zk_adaptor.h"
+
+#include "Util.h"
+#include "MocksBase.h"
+#include "LibCSymTable.h"
+#include "ThreadingUtil.h"
+
+// an ABC for pthreads
+class MockPthreadsBase: public Mock
+{
+public:
+    MockPthreadsBase(){mock_=this;}
+    virtual ~MockPthreadsBase(){mock_=0;}
+    
+    virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
+            void *(*f)(void *), void *d) =0;
+    virtual int pthread_join(pthread_t t, void ** r) =0;
+    virtual int pthread_detach(pthread_t t) =0;
+    virtual int pthread_cond_broadcast(pthread_cond_t *c) =0;
+    virtual int pthread_cond_destroy(pthread_cond_t *c) =0;
+    virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a) =0;
+    virtual int pthread_cond_signal(pthread_cond_t *c) =0;
+    virtual int pthread_cond_timedwait(pthread_cond_t *c,
+            pthread_mutex_t *m, const struct timespec *t) =0;
+    virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) =0;
+    virtual int pthread_mutex_destroy(pthread_mutex_t *m) =0;
+    virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a) =0;
+    virtual int pthread_mutex_lock(pthread_mutex_t *m) =0;
+    virtual int pthread_mutex_trylock(pthread_mutex_t *m) =0;
+    virtual int pthread_mutex_unlock(pthread_mutex_t *m) =0;
+    
+    static MockPthreadsBase* mock_;
+};
+
+// all pthread functions simply return an error code
+// and increment their invocation counter. No actual threads are spawned.
+class MockPthreadsNull: public MockPthreadsBase
+{
+public:
+    MockPthreadsNull():
+    pthread_createReturns(0),pthread_createCounter(0),
+    pthread_joinReturns(0),pthread_joinCounter(0),pthread_joinResultReturn(0),
+    pthread_detachReturns(0),pthread_detachCounter(0),
+    pthread_cond_broadcastReturns(0),pthread_cond_broadcastCounter(0),
+    pthread_cond_destroyReturns(0),pthread_cond_destroyCounter(0),
+    pthread_cond_initReturns(0),pthread_cond_initCounter(0),
+    pthread_cond_signalReturns(0),pthread_cond_signalCounter(0),
+    pthread_cond_timedwaitReturns(0),pthread_cond_timedwaitCounter(0),
+    pthread_cond_waitReturns(0),pthread_cond_waitCounter(0),
+    pthread_mutex_destroyReturns(0),pthread_mutex_destroyCounter(0),
+    pthread_mutex_initReturns(0),pthread_mutex_initCounter(0),
+    pthread_mutex_lockReturns(0),pthread_mutex_lockCounter(0),
+    pthread_mutex_trylockReturns(0),pthread_mutex_trylockCounter(0),
+    pthread_mutex_unlockReturns(0),pthread_mutex_unlockCounter(0)
+    {
+        memset(threads,0,sizeof(threads));
+    }
+    
+    short threads[512];
+    
+    int pthread_createReturns;
+    int pthread_createCounter;
+    virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
+            void *(*f)(void *), void *d){
+        char* p=(char*)&threads[pthread_createCounter++];
+        p[0]='i'; // mark as created
+        *t=(pthread_t)p;
+        return pthread_createReturns; 
+    }
+    int pthread_joinReturns;
+    int pthread_joinCounter;
+    void* pthread_joinResultReturn;
+    virtual int pthread_join(pthread_t t, void ** r){
+        pthread_joinCounter++;
+        if(r!=0)
+            *r=pthread_joinResultReturn;
+        char* p=(char*)t;
+        p[0]='x';p[1]+=1;
+        return pthread_joinReturns; 
+    }
+    int pthread_detachReturns;
+    int pthread_detachCounter;        
+    virtual int pthread_detach(pthread_t t){
+        pthread_detachCounter++;
+        char* p=(char*)t;
+        p[0]='x';p[1]+=1;        
+        return pthread_detachReturns;
+    }
+
+    template<class T>
+    static bool isInitialized(const T& t){
+        return ((char*)t)[0]=='i';
+    }
+    template<class T>
+    static bool isDestroyed(const T& t){
+        return ((char*)t)[0]=='x';
+    }
+    template<class T>
+    static int getDestroyCounter(const T& t){
+        return ((char*)t)[1];
+    }
+    template<class T>
+    static int getInvalidAccessCounter(const T& t){
+        return ((char*)t)[2];
+    }
+    int pthread_cond_broadcastReturns;
+    int pthread_cond_broadcastCounter;
+    virtual int pthread_cond_broadcast(pthread_cond_t *c){
+        pthread_cond_broadcastCounter++;
+        if(isDestroyed(c))((char*)c)[2]++;
+        return pthread_cond_broadcastReturns; 
+    }
+    int pthread_cond_destroyReturns;
+    int pthread_cond_destroyCounter;
+    virtual int pthread_cond_destroy(pthread_cond_t *c){
+        pthread_cond_destroyCounter++;
+        char* p=(char*)c;
+        p[0]='x';p[1]+=1;
+        return pthread_cond_destroyReturns; 
+    }
+    int pthread_cond_initReturns;
+    int pthread_cond_initCounter;
+    virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){
+        pthread_cond_initCounter++;
+        char* p=(char*)c;
+        p[0]='i'; // mark as created
+        p[1]=0;   // destruction counter
+        p[2]=0;   // access after destruction counter
+        return pthread_cond_initReturns; 
+    }
+    int pthread_cond_signalReturns;
+    int pthread_cond_signalCounter;
+    virtual int pthread_cond_signal(pthread_cond_t *c){
+        pthread_cond_signalCounter++;
+        if(isDestroyed(c))((char*)c)[2]++;
+        return pthread_cond_signalReturns; 
+    }
+    int pthread_cond_timedwaitReturns;
+    int pthread_cond_timedwaitCounter;
+    virtual int pthread_cond_timedwait(pthread_cond_t *c,
+            pthread_mutex_t *m, const struct timespec *t){
+        pthread_cond_timedwaitCounter++;
+        if(isDestroyed(c))((char*)c)[2]++;
+        return pthread_cond_timedwaitReturns; 
+    }
+    int pthread_cond_waitReturns;
+    int pthread_cond_waitCounter;
+    virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){
+        pthread_cond_waitCounter++;
+        if(isDestroyed(c))((char*)c)[2]++;
+        return pthread_cond_waitReturns; 
+    }
+    int pthread_mutex_destroyReturns;
+    int pthread_mutex_destroyCounter;
+    virtual int pthread_mutex_destroy(pthread_mutex_t *m){
+        pthread_mutex_destroyCounter++;
+        char* p=(char*)m;
+        p[0]='x';p[1]+=1;
+        return pthread_mutex_destroyReturns; 
+    }
+    int pthread_mutex_initReturns;
+    int pthread_mutex_initCounter;
+    virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){
+        pthread_mutex_initCounter++;
+        char* p=(char*)m;
+        p[0]='i'; // mark as created
+        p[1]=0;   // destruction counter
+        p[2]=0;   // access after destruction counter
+        return pthread_mutex_initReturns; 
+    }
+    int pthread_mutex_lockReturns;
+    int pthread_mutex_lockCounter;
+    virtual int pthread_mutex_lock(pthread_mutex_t *m){
+        pthread_mutex_lockCounter++;
+        if(isDestroyed(m))((char*)m)[2]++;
+        return pthread_mutex_lockReturns; 
+    }
+    int pthread_mutex_trylockReturns;
+    int pthread_mutex_trylockCounter;
+    virtual int pthread_mutex_trylock(pthread_mutex_t *m){
+        pthread_mutex_trylockCounter++;
+        if(isDestroyed(m))((char*)m)[2]++;
+        return pthread_mutex_trylockReturns; 
+    }
+    int pthread_mutex_unlockReturns;
+    int pthread_mutex_unlockCounter;
+    virtual int pthread_mutex_unlock(pthread_mutex_t *m){
+        pthread_mutex_unlockCounter++;
+        if(isDestroyed(m))((char*)m)[2]++;
+        return pthread_mutex_unlockReturns; 
+    }
+};
+
+// simulates the way zookeeper threads make use of api_prolog/epilog and
+// 
+class MockPthreadZKNull: public MockPthreadsNull
+{
+    typedef std::map<pthread_t,zhandle_t*> Map;
+    Map map_;
+public:
+    virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
+            void *(*f)(void *), void *d){
+        int ret=MockPthreadsNull::pthread_create(t,a,f,d);
+        zhandle_t* zh=(zhandle_t*)d;
+        adaptor_threads* ad=(adaptor_threads*)zh->adaptor_priv;
+        api_prolog(zh);
+        ad->threadsToWait--;
+        putValue(map_,*t,zh);
+        return ret;
+    }
+    virtual int pthread_join(pthread_t t, void ** r){
+        zhandle_t* zh=0;
+        if(getValue(map_,t,zh))
+            api_epilog(zh,0);
+        return MockPthreadsNull::pthread_join(t,r);
+    }
+};
+
+struct ThreadInfo{
+    typedef enum {RUNNING,TERMINATED} ThreadState;
+    
+    ThreadInfo():
+        destructionCounter_(0),invalidAccessCounter_(0),state_(RUNNING)
+    {
+    }
+    
+    ThreadInfo& incDestroyed() {
+        destructionCounter_++;
+        return *this;
+    }
+    ThreadInfo& incInvalidAccess(){
+        invalidAccessCounter_++;
+        return *this;
+    }
+    ThreadInfo& setTerminated(){
+        state_=TERMINATED;
+        return *this;
+    }
+    int destructionCounter_;
+    int invalidAccessCounter_;
+    ThreadState state_;
+};
+
+class CheckedPthread: public MockPthreadsBase
+{
+    // first => destruction counter
+    // second => invalid access counter
+    //typedef std::pair<int,int> Entry;
+    typedef ThreadInfo Entry;
+    typedef std::map<pthread_t,Entry> ThreadMap;
+    static ThreadMap tmap_;
+    static ThreadMap& getMap(const TypeOp<pthread_t>::BareT&){return tmap_;}
+    typedef std::map<pthread_mutex_t*,Entry> MutexMap;
+    static MutexMap mmap_;
+    static MutexMap& getMap(const TypeOp<pthread_mutex_t>::BareT&){return mmap_;}
+    typedef std::map<pthread_cond_t*,Entry> CVMap;
+    static CVMap cvmap_;
+    static CVMap& getMap(const TypeOp<pthread_cond_t>::BareT&){return cvmap_;}
+    
+    static Mutex mx;
+    
+    template<class T>
+    static void markDestroyed(T& t){
+        typedef typename TypeOp<T>::BareT Type;
+        Entry e;
+        synchronized(mx);
+        if(getValue(getMap(Type()),t,e)){
+            putValue(getMap(Type()),t,Entry(e).incDestroyed());
+        }else{
+            putValue(getMap(Type()),t,Entry().incDestroyed());
+        }
+    }
+    template<class T>
+    static void markCreated(T& t){
+        typedef typename TypeOp<T>::BareT Type;
+        Entry e;
+        synchronized(mx);
+        if(!getValue(getMap(Type()),t,e))
+            putValue(getMap(Type()),t,Entry());
+    }
+    template<class T>
+    static void checkAccessed(T& t){
+        typedef typename TypeOp<T>::BareT Type;
+        Entry e;
+        synchronized(mx);
+        if(getValue(getMap(Type()),t,e) && e.destructionCounter_>0)
+            putValue(getMap(Type()),t,Entry(e).incInvalidAccess());
+    }
+    static void setTerminated(pthread_t t){
+        Entry e;
+        synchronized(mx);
+        if(getValue(tmap_,t,e))
+            putValue(tmap_,t,Entry(e).setTerminated());
+    }
+public:
+    bool verbose;
+    CheckedPthread():verbose(false){
+        tmap_.clear();
+        mmap_.clear();
+        cvmap_.clear();
+        mx.release();
+    }
+    template <class T>
+    static bool isInitialized(const T& t){
+        typedef typename TypeOp<T>::BareT Type;
+        Entry e;
+        synchronized(mx);
+        return getValue(getMap(Type()),t,e) && e.destructionCounter_==0;
+    }
+    template <class T>
+    static bool isDestroyed(const T& t){
+        typedef typename TypeOp<T>::BareT Type;
+        Entry e;
+        synchronized(mx);
+        return getValue(getMap(Type()),t,e) && e.destructionCounter_>0;
+    }
+    static bool isTerminated(pthread_t t){
+        Entry e;
+        synchronized(mx);
+        return getValue(tmap_,t,e) && e.state_==ThreadInfo::TERMINATED;        
+    }
+    template <class T>
+    static int getDestroyCounter(const T& t){
+        typedef typename TypeOp<T>::BareT Type;
+        Entry e;
+        synchronized(mx);
+        return getValue(getMap(Type()),t,e)?e.destructionCounter_:-1;
+    }
+    template<class T>
+    static int getInvalidAccessCounter(const T& t){
+        typedef typename TypeOp<T>::BareT Type;
+        Entry e;
+        synchronized(mx);
+        return getValue(getMap(Type()),t,e)?e.invalidAccessCounter_:-1;
+    }
+
+    struct ThreadContext{
+        typedef void *(*ThreadFunc)(void *);
+        
+        ThreadContext(ThreadFunc func,void* param):func_(func),param_(param){}
+        ThreadFunc func_;
+        void* param_;        
+    };
+    static void* threadFuncWrapper(void* v){
+        ThreadContext* ctx=(ThreadContext*)v;
+        pthread_t t=pthread_self();
+        markCreated(t);
+        void* res=ctx->func_(ctx->param_);
+        setTerminated(pthread_self());
+        delete ctx;
+        return res;
+    }
+    virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
+            void *(*f)(void *), void *d)
+    {
+        int ret=LIBC_SYMBOLS.pthread_create(t,a,threadFuncWrapper,
+                new ThreadContext(f,d));
+        if(verbose)
+            TEST_TRACE("thread created %p",*t);
+        return ret;
+    }
+    virtual int pthread_join(pthread_t t, void ** r){
+        if(verbose) TEST_TRACE("thread joined %p",t);
+        int ret=LIBC_SYMBOLS.pthread_join(t,r);
+        if(ret==0)
+            markDestroyed(t);
+        return ret;
+    }
+    virtual int pthread_detach(pthread_t t){
+        if(verbose) TEST_TRACE("thread detached %p",t);
+        int ret=LIBC_SYMBOLS.pthread_detach(t);
+        if(ret==0)
+            markDestroyed(t);
+        return ret;
+    }
+    virtual int pthread_cond_broadcast(pthread_cond_t *c){
+        checkAccessed(c);
+        return LIBC_SYMBOLS.pthread_cond_broadcast(c);
+    }
+    virtual int pthread_cond_destroy(pthread_cond_t *c){
+        markDestroyed(c);
+        return LIBC_SYMBOLS.pthread_cond_destroy(c);
+    }
+    virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){
+        markCreated(c);
+        return LIBC_SYMBOLS.pthread_cond_init(c,a);
+    }
+    virtual int pthread_cond_signal(pthread_cond_t *c){
+        checkAccessed(c);
+        return LIBC_SYMBOLS.pthread_cond_signal(c);
+    }
+    virtual int pthread_cond_timedwait(pthread_cond_t *c,
+            pthread_mutex_t *m, const struct timespec *t){
+        checkAccessed(c);
+        return LIBC_SYMBOLS.pthread_cond_timedwait(c,m,t);
+    }
+    virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){
+        checkAccessed(c);
+        return LIBC_SYMBOLS.pthread_cond_wait(c,m);
+    }
+    virtual int pthread_mutex_destroy(pthread_mutex_t *m){
+        markDestroyed(m);
+        return LIBC_SYMBOLS.pthread_mutex_destroy(m);
+    }
+    virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){
+        markCreated(m);
+        return LIBC_SYMBOLS.pthread_mutex_init(m,a);
+    }
+    virtual int pthread_mutex_lock(pthread_mutex_t *m){
+        checkAccessed(m);
+        return LIBC_SYMBOLS.pthread_mutex_lock(m);
+    }
+    virtual int pthread_mutex_trylock(pthread_mutex_t *m){
+        checkAccessed(m);
+        return LIBC_SYMBOLS.pthread_mutex_trylock(m);
+    }
+    virtual int pthread_mutex_unlock(pthread_mutex_t *m){
+        checkAccessed(m);
+        return LIBC_SYMBOLS.pthread_mutex_unlock(m);
+    }    
+};
+
+#endif /*PTHREADMOCKS_H_*/
+


Mime
View raw message