forked from couchbase/couchbase-python-client
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmockserver.py
More file actions
188 lines (153 loc) · 5.9 KB
/
Copy pathmockserver.py
File metadata and controls
188 lines (153 loc) · 5.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# Copyright 2013, Couchbase, Inc.
# All Rights Reserved
#
# Licensed 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.
from subprocess import Popen, PIPE
from couchbase._pyport import urlopen, ulp, basestring
import socket
import json
import os.path
import select
class BucketSpec(object):
def __init__(self, name='default', bucket_type='couchbase', password=''):
self.name = name
self.bucket_type = bucket_type
self.password = password
def __str__(self):
return ':'.join([self.name, self.password, self.bucket_type])
class MockControlClient(object):
def __init__(self, mockport=18091, host='127.0.0.1'):
self.urlbase = "http://{0}:{1}/mock/".format(host, mockport)
def _get_common(self, command, params):
qparams = {}
for k, v in params.items():
qparams[k] = json.dumps(v)
qparams = ulp.urlencode(qparams)
url = self.urlbase + "{0}?{1}".format(command, qparams)
data = urlopen(url).read()
if not isinstance(data, basestring):
data = str(data, "utf-8")
ret = json.loads(data)
return ret
def _params_common(self, key,
bucket=None,
on_master=False,
replica_count=None,
replicas=None,
cas=None,
value=None):
r = {
'Key' : key,
'OnMaster' : on_master
}
if bucket:
r['Bucket'] = bucket
if replica_count is not None:
r['OnReplicas'] = replica_count
else:
r['OnReplicas'] = replicas
if cas is not None:
r['CAS'] = cas
if value is not None:
r['Value'] = value
return r
def _do_request(self, cmd, *args, **kwargs):
params = self._params_common(*args, **kwargs)
return self._get_common(cmd, params)
def keyinfo(self, *args, **kwargs):
return self._do_request("keyinfo", *args, **kwargs)
def persist(self, *args, **kwargs):
return self._do_request("persist", *args, **kwargs)
def endure(self, *args, **kwargs):
return self._do_request("endure", *args, **kwargs)
def cache(self, *args, **kwargs):
return self._do_request("cache", *args, **kwargs)
def uncache(self, *args, **kwargs):
return self._do_request("uncache", *args, **kwargs)
def unpersist(self, *args, **kwargs):
return self._do_request("unpersist", *args, **kwargs)
def purge(self, *args, **kwargs):
return self._do_request("purge", *args, **kwargs)
class CouchbaseMock(object):
def _setup_listener(self):
sock = socket.socket()
sock.bind( ('', 0) )
sock.listen(5)
addr, port = sock.getsockname()
self.listen = sock
self.port = port
def _invoke(self):
self._setup_listener()
args = [
"java", "-client", "-jar", self.runpath,
"--port", "0", "--with-beer-sample",
"--harakiri-monitor", "127.0.0.1:" + str(self.port),
"--nodes", str(self.nodes)
]
if self.vbuckets is not None:
args += ["--vbuckets", str(self.vbuckets)]
if self.replicas is not None:
args += ["--replicas", str(self.replicas)]
bspec = ",".join([str(x) for x in self.buckets])
args += ["--buckets", bspec]
self.po = Popen(args)
# Sometimes we get an invalid JAR file. Unfortunately there is no
# way to determine or "wait for completion". The next best thing
# is to set a maximum of 15 seconds for the process to start (and
# connect to the listening socket);
rlist, w_, x_ = select.select([self.listen], [], [], 15)
if not rlist:
raise Exception('Mock server was not ready in time')
self.harakiri_sock, addr = self.listen.accept()
self.ctlfp = self.harakiri_sock.makefile()
sbuf = ""
while True:
c = self.ctlfp.read(1)
if c == '\0':
break
sbuf += c
self.rest_port = int(sbuf)
def __init__(self, buckets, runpath,
url=None,
replicas=None,
vbuckets=None,
nodes=4):
"""
Creates a new instance of the mock server. You must actually call
'start()' for it to be invoked.
:param list buckets: A list of BucketSpec items
:param string runpath: a string pointing to the location of the mock
:param string url: The URL to use to download the mock. This is only
used if runpath does not exist
:param int replicas: How many replicas should each bucket have
:param int vbuckets: How many vbuckets should each bucket have
:param int nodes: How many total nodes in the cluster
Note that you must have ``java`` in your `PATH`
"""
self.runpath = runpath
self.buckets = buckets
self.nodes = nodes
self.vbuckets = vbuckets
self.replicas = replicas
if not os.path.exists(runpath):
if not url:
raise Exception(runpath + " Does not exist and no URL specified")
fp = open(runpath, "wb")
ulp = urlopen(url)
jarblob = ulp.read()
fp.write(jarblob)
fp.close()
def start(self):
self._invoke()
def stop(self):
self.po.kill()