/* * 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. */ package org.apache.zookeeper.test; import org.apache.log4j.Logger; import org.apache.zookeeper.*; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.server.ServerCnxnFactory; import org.apache.zookeeper.server.SyncRequestProcessor; import org.apache.zookeeper.server.ZooKeeperServer; import org.apache.zookeeper.OpResult.ErrorResult; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.ArrayList; import org.apache.zookeeper.data.Stat; import static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT; public class MultiTransactionTest extends ZKTestCase implements Watcher { private static final Logger LOG = Logger.getLogger(MultiTransactionTest.class); private static final String HOSTPORT = "127.0.0.1:" + PortAssignment.unique(); private ZooKeeper zk; private ServerCnxnFactory serverFactory; @Override public void process(WatchedEvent event) { // ignore } @Before public void setupZk() throws Exception { File tmpDir = ClientBase.createTmpDir(); ClientBase.setupTestEnv(); ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000); SyncRequestProcessor.setSnapCount(150); final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]); serverFactory = ServerCnxnFactory.createFactory(PORT, -1); serverFactory.startup(zks); LOG.info("starting up the zookeeper server .. waiting"); Assert.assertTrue("waiting for server being up", ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT)); zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this); } @After public void shutdownServer() throws Exception { zk.close(); serverFactory.shutdown(); } @Test public void testCreate() throws Exception { List<OpResult> results = new ArrayList<OpResult>(); results = zk.multi(Arrays.asList( Op.create("/multi0", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.create("/multi1", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.create("/multi2", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT) )); zk.getData("/multi0", false, null); zk.getData("/multi1", false, null); zk.getData("/multi2", false, null); } @Test public void testCreateDelete() throws Exception { zk.multi(Arrays.asList( Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.delete("/multi", 0) )); // '/multi' should have been deleted Assert.assertNull(zk.exists("/multi", null)); } @Test public void testInvalidVersion() throws Exception { try { zk.multi(Arrays.asList( Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.delete("/multi", 1) )); Assert.fail("delete /multi should have failed"); } catch (KeeperException e) { /* PASS */ } } @Test public void testNestedCreate() throws Exception { zk.multi(Arrays.asList( /* Create */ Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.create("/multi/a", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.create("/multi/a/1", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), /* Delete */ Op.delete("/multi/a/1", 0), Op.delete("/multi/a", 0), Op.delete("/multi", 0) )); //Verify tree deleted Assert.assertNull(zk.exists("/multi/a/1", null)); Assert.assertNull(zk.exists("/multi/a", null)); Assert.assertNull(zk.exists("/multi", null)); } @Test public void testSetData() throws Exception { String[] names = {"/multi0", "/multi1", "/multi2"}; List<Op> ops = new ArrayList<Op>(); for (int i = 0; i < names.length; i++) { ops.add(Op.create(names[i], new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)); ops.add(Op.setData(names[i], names[i].getBytes(), 0)); } zk.multi(ops) ; for (int i = 0; i < names.length; i++) { Assert.assertArrayEquals(names[i].getBytes(), zk.getData(names[i], false, null)); } } @Test public void testUpdateConflict() throws Exception { Assert.assertNull(zk.exists("/multi", null)); try { zk.multi(Arrays.asList( Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.setData("/multi", "X".getBytes(), 0), Op.setData("/multi", "Y".getBytes(), 0) )); Assert.fail("Should have thrown a KeeperException for invalid version"); } catch (KeeperException e) { //PASS LOG.error("STACKTRACE: " + e); } Assert.assertNull(zk.exists("/multi", null)); //Updating version solves conflict -- order matters zk.multi(Arrays.asList( Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.setData("/multi", "X".getBytes(), 0), Op.setData("/multi", "Y".getBytes(), 1) )); Assert.assertArrayEquals(zk.getData("/multi", false, null), "Y".getBytes()); } @Test public void TestDeleteUpdateConflict() throws Exception { /* Delete of a node folowed by an update of the (now) deleted node */ try { zk.multi(Arrays.asList( Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.delete("/multi", 0), Op.setData("/multi", "Y".getBytes(), 0) )); Assert.fail("/multi should have been deleted so setData should have failed"); } catch (KeeperException e) { /* PASS */ } // '/multi' should never have been created as entire op should fail Assert.assertNull(zk.exists("/multi", null)) ; } @Test public void TestGetResults() throws Exception { /* Delete of a node folowed by an update of the (now) deleted node */ try { zk.multi(Arrays.asList( Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), Op.delete("/multi", 0), Op.setData("/multi", "Y".getBytes(), 0), Op.create("/foo", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT) )); Assert.fail("/multi should have been deleted so setData should have failed"); } catch (KeeperException e) { // '/multi' should never have been created as entire op should fail Assert.assertNull(zk.exists("/multi", null)); for (OpResult r : e.getResults()) { LOG.info("RESULT==> " + r); if (r instanceof ErrorResult) { ErrorResult er = (ErrorResult) r; LOG.info("ERROR RESULT: " + er + " ERR=>" + KeeperException.Code.get(er.getErr())); } } } } }