PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/src/test/java/com/couchbase/mock/JMembaseTest.java

http://github.com/couchbase/CouchbaseMock
Java | 391 lines | 307 code | 55 blank | 29 comment | 17 complexity | c8dd34ca3ef15a5b360f03439859ebff MD5 | raw file
  1. /*
  2. * Copyright 2017 Couchbase, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.couchbase.mock;
  17. import com.couchbase.mock.client.FailoverRequest;
  18. import com.couchbase.mock.client.HiccupRequest;
  19. import com.couchbase.mock.client.MockClient;
  20. import com.couchbase.mock.client.MockRequest;
  21. import com.couchbase.mock.client.MockResponse;
  22. import com.couchbase.mock.client.RespawnRequest;
  23. import com.couchbase.mock.harakiri.HarakiriMonitor;
  24. import com.couchbase.mock.util.Base64;
  25. import com.couchbase.mock.util.ReaderUtils;
  26. import com.google.gson.Gson;
  27. import com.google.gson.JsonObject;
  28. import junit.framework.TestCase;
  29. import java.io.BufferedReader;
  30. import java.io.IOException;
  31. import java.io.InputStream;
  32. import java.io.InputStreamReader;
  33. import java.io.OutputStream;
  34. import java.io.OutputStreamWriter;
  35. import java.io.PrintWriter;
  36. import java.io.StringWriter;
  37. import java.net.HttpURLConnection;
  38. import java.net.InetSocketAddress;
  39. import java.net.ServerSocket;
  40. import java.net.Socket;
  41. import java.net.URL;
  42. import java.net.UnknownHostException;
  43. import java.util.List;
  44. import java.util.Map;
  45. import java.util.logging.Level;
  46. import java.util.logging.Logger;
  47. import static com.couchbase.mock.http.HttpAssert.assertResponseNotFound;
  48. import static com.couchbase.mock.http.HttpAssert.assertResponseOK;
  49. import static com.couchbase.mock.http.HttpAssert.assertResponseUnauthorized;
  50. /**
  51. * Basic testing of JMembase
  52. *
  53. * @author Trond Norbye
  54. */
  55. public class JMembaseTest extends TestCase {
  56. public JMembaseTest(String testName) {
  57. super(testName);
  58. }
  59. private CouchbaseMock instance;
  60. static private final int port = 28091;
  61. static private final int numNodes;
  62. static private final int numVBuckets;
  63. static {
  64. final String platform = System.getProperty("os.name");
  65. if (platform.equals("Mac OS X") || platform.equals("Linux")) {
  66. numNodes = 4;
  67. numVBuckets = 16;
  68. } else {
  69. numNodes = 100;
  70. numVBuckets = 1024;
  71. }
  72. }
  73. private boolean serverNotReady(int port) {
  74. Socket socket = null;
  75. try {
  76. socket = new Socket("localhost", port);
  77. return false;
  78. } catch (UnknownHostException ex) {
  79. } catch (IOException ex) {
  80. } finally {
  81. if (socket != null) {
  82. try {
  83. socket.close();
  84. } catch (IOException e) {
  85. }
  86. }
  87. }
  88. return true;
  89. }
  90. @Override
  91. protected void setUp() throws Exception {
  92. super.setUp();
  93. instance = new CouchbaseMock(null, port, numNodes, numVBuckets, "default:,protected:secret");
  94. instance.start();
  95. do {
  96. Thread.sleep(100);
  97. } while (serverNotReady(port));
  98. }
  99. @Override
  100. protected void tearDown() throws Exception {
  101. instance.stop();
  102. super.tearDown();
  103. }
  104. public void testHandleHttpRequest() throws IOException {
  105. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/buckets/protected");
  106. assertResponseOK(url, "protected", "secret");
  107. }
  108. public void testHandleHttpRequestWithTrailingSlash() throws IOException {
  109. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/buckets/protected/");
  110. assertResponseOK(url, "protected", "secret");
  111. }
  112. public void testAdministratorCouldAccessProtectedBuckets() throws IOException {
  113. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/buckets/protected");
  114. assertResponseOK(url, "Administrator", "password");
  115. }
  116. public void testDefaultBucketShouldBeAccessibleForEveryone() throws IOException {
  117. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/buckets/default");
  118. assertResponseOK(url);
  119. }
  120. public void testProtectedBucketsShouldBeFilteredOutFromList() throws IOException {
  121. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/buckets");
  122. HttpURLConnection conn;
  123. try {
  124. conn = (HttpURLConnection) url.openConnection();
  125. assertNotNull(conn);
  126. assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
  127. StringBuilder sb = new StringBuilder();
  128. BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
  129. String line;
  130. while ((line = in.readLine()) != null) {
  131. sb.append(line);
  132. }
  133. List json = JsonUtils.decodeAsList(sb.toString());
  134. assertEquals(1, json.size());
  135. Map<String,Object> bucket = (Map<String,Object>)json.get(0);
  136. assertEquals("default", bucket.get("name"));
  137. } catch (Exception ex) {
  138. fail(ex.getMessage());
  139. }
  140. }
  141. public void testHandleHttpRequestNetwork() throws IOException {
  142. StringWriter sw = new StringWriter();
  143. PrintWriter pw = new PrintWriter(sw);
  144. pw.print("GET /pools/default/buckets/default HTTP/1.1\r\n");
  145. pw.print("Authorization: Basic " + Base64.encode("Administrator:password") + "\r\n");
  146. pw.print("\r\n");
  147. pw.flush();
  148. Socket s = new Socket("localhost", port);
  149. OutputStream out = s.getOutputStream();
  150. out.write(sw.toString().getBytes());
  151. out.flush();
  152. BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
  153. int content_length = 0;
  154. String header;
  155. while ((header = in.readLine()).length() > 0) {
  156. String[] tokens = header.split(": ");
  157. if (tokens[0].equals("Content-Length")) {
  158. content_length = Integer.parseInt(tokens[1]);
  159. }
  160. }
  161. char[] body = new char[content_length];
  162. assertEquals(content_length, in.read(body));
  163. s.close();
  164. }
  165. public void testHandleHttpRequestMissingAuth() throws IOException {
  166. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/buckets/protected");
  167. assertResponseUnauthorized(url);
  168. }
  169. @SuppressWarnings("SpellCheckingInspection")
  170. public void testHandleHttpRequestIncorrectCred() throws IOException {
  171. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/buckets/protected");
  172. assertResponseUnauthorized(url, "Bubba", "TheHut");
  173. }
  174. @SuppressWarnings("SpellCheckingInspection")
  175. public void testHandleHttpRequestIllegalCred() throws IOException {
  176. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/buckets/default");
  177. assertResponseUnauthorized(url, "", "TheHut");
  178. }
  179. public void testHandleHttpRequestUnkownFile() throws IOException {
  180. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/");
  181. assertResponseNotFound(url, "Administrator", "password");
  182. }
  183. // @SuppressWarnings("UnusedAssignment")
  184. // public void testHarakiriMonitorInvalidHost() throws IOException {
  185. // try {
  186. // HarakiriMonitor m = new HarakiriMonitor("ItWouldSuckIfYouHadAHostNamedThis", 0, false, instance.getDispatcher());
  187. // fail("I was not expecting to be able to connect to: \"ItWouldSuckIfYouHadAHostNamedThis:0\"");
  188. // } catch (Throwable t) {
  189. // }
  190. // }
  191. @SuppressWarnings("UnusedAssignment")
  192. public void testHarakiriMonitorInvalidPort() throws IOException {
  193. try {
  194. HarakiriMonitor m = new HarakiriMonitor(instance.getDispatcher());
  195. m.connect(null, 0);
  196. fail("I was not expecting to be able to connect to port 0");
  197. } catch (Throwable t) {
  198. }
  199. }
  200. public void testHarakiriMonitor() throws IOException {
  201. ServerSocket server = new ServerSocket(0);
  202. HarakiriMonitor m;
  203. m = new HarakiriMonitor(instance.getDispatcher());
  204. m.connect(null, server.getLocalPort());
  205. Thread t = new Thread(m);
  206. t.start();
  207. server.close();
  208. while (t.isAlive()) {
  209. try {
  210. t.join();
  211. } catch (InterruptedException ex) {
  212. Logger.getLogger(JMembaseTest.class.getName()).log(Level.SEVERE, null, ex);
  213. }
  214. }
  215. }
  216. private String readConfig(InputStream stream) throws IOException {
  217. int bb, lf = 0;
  218. StringBuilder cfg = new StringBuilder();
  219. do {
  220. bb = stream.read();
  221. if (bb == '\n') {
  222. lf++;
  223. } else {
  224. lf = 0;
  225. cfg.append(bb);
  226. }
  227. } while (lf < 4);
  228. return cfg.toString();
  229. }
  230. private static String readInput(InputStream cin) throws IOException {
  231. byte[] inputBuffer = new byte[4096];
  232. int nr;
  233. StringBuilder sb = new StringBuilder();
  234. while ((nr = cin.read(inputBuffer)) > 0) {
  235. String s = new String(inputBuffer, 0, nr);
  236. sb.append(s);
  237. if (nr < inputBuffer.length) {
  238. break;
  239. }
  240. }
  241. return sb.toString();
  242. }
  243. private boolean readResponse(InputStream in) throws IOException {
  244. String json = readInput(in);
  245. try {
  246. JsonObject response = (new Gson()).fromJson(json, JsonObject.class);
  247. return response.get("status").getAsString().toLowerCase().equals("ok");
  248. } catch (Throwable ex) {
  249. System.err.println("Invalid response received from the server: [" + json + "]");
  250. return false;
  251. }
  252. }
  253. @SuppressWarnings("SpellCheckingInspection")
  254. public void testConfigStreaming() throws IOException {
  255. MockClient mock = new MockClient(new InetSocketAddress("localhost", 0));
  256. instance.startHarakiriMonitor("localhost:" + mock.getPort(), false);
  257. mock.negotiate();
  258. Bucket bucket = instance.getBuckets().get("protected");
  259. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/bucketsStreaming/protected");
  260. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  261. conn.addRequestProperty("Authorization", "Basic " + Base64.encode("protected:secret"));
  262. InputStream stream = conn.getInputStream();
  263. String currCfg, nextCfg;
  264. currCfg = readConfig(stream);
  265. assertEquals(numNodes, bucket.activeServers().size());
  266. assertTrue(mock.request(new FailoverRequest(1, "protected")).isOk());
  267. nextCfg = readConfig(stream);
  268. assertNotSame(currCfg, nextCfg);
  269. assertEquals(numNodes - 1, bucket.activeServers().size());
  270. currCfg = nextCfg;
  271. assertTrue(mock.request(new RespawnRequest(1, "protected")).isOk());
  272. nextCfg = readConfig(stream);
  273. assertNotSame(currCfg, nextCfg);
  274. assertEquals(numNodes, bucket.activeServers().size());
  275. assertTrue(mock.request(new HiccupRequest(10000, 20)).isOk());
  276. assertTrue(mock.request(new FailoverRequest(1)).isOk());
  277. assertTrue(mock.request(new RespawnRequest(1)).isOk());
  278. mock.shutdown();
  279. instance.getMonitor().stop();
  280. }
  281. public void testIllegalMockCommand() throws IOException {
  282. ServerSocket server = new ServerSocket(0);
  283. instance.startHarakiriMonitor("localhost:" + server.getLocalPort(), false);
  284. Socket client = server.accept();
  285. InputStream input = client.getInputStream();
  286. OutputStream output = client.getOutputStream();
  287. readInput(input);
  288. output.write("Yo, this should fail!\n".getBytes());
  289. assertFalse(readResponse(input));
  290. }
  291. public void testUnknownMockCommand() throws IOException {
  292. MockClient mock = new MockClient(new InetSocketAddress("localhost", 0));
  293. instance.startHarakiriMonitor("localhost:" + mock.getPort(), false);
  294. mock.negotiate();
  295. MockRequest request = MockRequest.build("foo");
  296. MockResponse resp = mock.request(request);
  297. assertFalse(resp.isOk());
  298. assertNotNull(resp.getErrorMessage());
  299. }
  300. public void testRestFlush() throws IOException {
  301. URL url = new URL("http://localhost:" + instance.getHttpPort() + "/pools/default/buckets/default/controller/doFlush");
  302. HttpURLConnection conn;
  303. try {
  304. conn = (HttpURLConnection) url.openConnection();
  305. assertNotNull(conn);
  306. assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
  307. } catch (Exception ex) {
  308. fail(ex.getMessage());
  309. }
  310. }
  311. final static String DDOC = "{"
  312. + " \"_id\": \"_design/beer\","
  313. + " \"language\": \"javascript\","
  314. + " \"views\": {"
  315. + " \"all\": {"
  316. + " \"map\": \"function(doc){ emit(doc.id, null); }\""
  317. + " }"
  318. + " }"
  319. + "}";
  320. public void testDesignManagement() throws Exception {
  321. URL url = new URL("http://localhost:"+instance.getHttpPort()+"/default/_design/beer");
  322. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  323. conn.setDoOutput(true);
  324. conn.setRequestMethod("PUT");
  325. conn.setRequestProperty("Content-Type", "application/json");
  326. OutputStreamWriter osw = new OutputStreamWriter(conn.getOutputStream());
  327. osw.write(DDOC);
  328. osw.flush();
  329. osw.close();
  330. conn.getInputStream().close();
  331. // Get it back
  332. conn = (HttpURLConnection) url.openConnection();
  333. String s = ReaderUtils.fromStream(conn.getInputStream());
  334. assertEquals(s, DDOC);
  335. }
  336. }