1 package org.apache.lucene.util;
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 import java.io.IOException;
21 import java.util.HashMap;
24 import org.apache.lucene.util.TwoPhaseCommitTool.TwoPhaseCommitWrapper;
26 public class TestTwoPhaseCommitTool extends LuceneTestCase {
28 private static class TwoPhaseCommitImpl implements TwoPhaseCommit {
29 static boolean commitCalled = false;
30 final boolean failOnPrepare;
31 final boolean failOnCommit;
32 final boolean failOnRollback;
33 boolean rollbackCalled = false;
34 Map<String, String> prepareCommitData = null;
35 Map<String, String> commitData = null;
37 public TwoPhaseCommitImpl(boolean failOnPrepare, boolean failOnCommit, boolean failOnRollback) {
38 this.failOnPrepare = failOnPrepare;
39 this.failOnCommit = failOnCommit;
40 this.failOnRollback = failOnRollback;
43 public void prepareCommit() throws IOException {
47 public void prepareCommit(Map<String, String> commitData) throws IOException {
48 this.prepareCommitData = commitData;
49 assertFalse("commit should not have been called before all prepareCommit were", commitCalled);
51 throw new IOException("failOnPrepare");
55 public void commit() throws IOException {
59 public void commit(Map<String, String> commitData) throws IOException {
60 this.commitData = commitData;
63 throw new RuntimeException("failOnCommit");
67 public void rollback() throws IOException {
68 rollbackCalled = true;
70 throw new Error("failOnRollback");
76 public void setUp() throws Exception {
78 TwoPhaseCommitImpl.commitCalled = false; // reset count before every test
81 public void testPrepareThenCommit() throws Exception {
82 // tests that prepareCommit() is called on all objects before commit()
83 TwoPhaseCommitImpl[] objects = new TwoPhaseCommitImpl[2];
84 for (int i = 0; i < objects.length; i++) {
85 objects[i] = new TwoPhaseCommitImpl(false, false, false);
88 // following call will fail if commit() is called before all prepare() were
89 TwoPhaseCommitTool.execute(objects);
92 public void testRollback() throws Exception {
93 // tests that rollback is called if failure occurs at any stage
94 int numObjects = random.nextInt(8) + 3; // between [3, 10]
95 TwoPhaseCommitImpl[] objects = new TwoPhaseCommitImpl[numObjects];
96 for (int i = 0; i < objects.length; i++) {
97 boolean failOnPrepare = random.nextBoolean();
98 // we should not hit failures on commit usually
99 boolean failOnCommit = random.nextDouble() < 0.05;
100 boolean railOnRollback = random.nextBoolean();
101 objects[i] = new TwoPhaseCommitImpl(failOnPrepare, failOnCommit, railOnRollback);
104 boolean anyFailure = false;
106 TwoPhaseCommitTool.execute(objects);
107 } catch (Throwable t) {
112 // if any failure happened, ensure that rollback was called on all.
113 for (TwoPhaseCommitImpl tpc : objects) {
114 assertTrue("rollback was not called while a failure occurred during the 2-phase commit", tpc.rollbackCalled);
119 public void testWrapper() throws Exception {
120 // tests that TwoPhaseCommitWrapper delegates prepare/commit w/ commitData
121 TwoPhaseCommitImpl impl = new TwoPhaseCommitImpl(false, false, false);
122 HashMap<String, String> commitData = new HashMap<String, String>();
123 TwoPhaseCommitWrapper wrapper = new TwoPhaseCommitWrapper(impl, commitData);
125 wrapper.prepareCommit();
126 assertSame(commitData, impl.prepareCommitData);
128 // wrapper should ignore passed commitData
129 wrapper.prepareCommit(new HashMap<String, String>());
130 assertSame(commitData, impl.prepareCommitData);
133 assertSame(commitData, impl.commitData);
135 // wrapper should ignore passed commitData
136 wrapper.commit(new HashMap<String, String>());
137 assertSame(commitData, impl.commitData);
140 public void testNullTPCs() throws Exception {
141 int numObjects = random.nextInt(4) + 3; // between [3, 6]
142 TwoPhaseCommit[] tpcs = new TwoPhaseCommit[numObjects];
143 boolean setNull = false;
144 for (int i = 0; i < tpcs.length; i++) {
145 boolean isNull = random.nextDouble() < 0.3;
150 tpcs[i] = new TwoPhaseCommitImpl(false, false, false);
155 // none of the TPCs were picked to be null, pick one at random
156 int idx = random.nextInt(numObjects);
160 // following call would fail if TPCTool won't handle null TPCs properly
161 TwoPhaseCommitTool.execute(tpcs);