You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by an...@apache.org on 2018/08/23 14:11:56 UTC
[04/20] zookeeper git commit: ZOOKEEPER-3031: 3.4: MAVEN MIGRATION -
move client dir
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5694559d/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/5694559d/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/5694559d/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..5db4553
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/LibCMocks.cc
@@ -0,0 +1,333 @@
+/**
+ * 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 <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;
+
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5694559d/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/5694559d/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..5378579
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.cc
@@ -0,0 +1,83 @@
+/**
+ * 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"
+
+#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 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/5694559d/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..2f7e0c2
--- /dev/null
+++ b/zookeeper-client/zookeeper-client-c/tests/LibCSymTable.h
@@ -0,0 +1,107 @@
+/**
+ * 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>
+
+#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 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/5694559d/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/5694559d/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/5694559d/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/5694559d/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..8db8815
--- /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_*/
+