blob: 4fd35d5805832c721e97c2788009fe839c5ea113 [file] [log] [blame]
/*
* 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.bookkeeper.tests.backwardcompat
import com.github.dockerjava.api.DockerClient
import org.apache.bookkeeper.tests.integration.utils.BookKeeperClusterUtils
import org.apache.bookkeeper.tests.integration.utils.MavenClassLoader
import org.apache.bookkeeper.tests.integration.utils.ThreadReaper
import org.jboss.arquillian.junit.Arquillian
import org.jboss.arquillian.test.api.ArquillianResource
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@RunWith(Arquillian.class)
class TestCompatOldClients {
private static final Logger LOG = LoggerFactory.getLogger(TestCompatOldClients.class)
private static byte[] PASSWD = "foobar".getBytes()
// 4.1.0 doesn't work because metadata format changed
private def oldClientVersions = ["4.2.0", "4.2.1", "4.2.2", "4.2.3", "4.2.4",
"4.3.0", "4.3.1", "4.3.2", "4.4.0", "4.5.0", "4.5.1",
"4.6.0", "4.6.1", "4.6.2",
"4.7.0"]
@ArquillianResource
DockerClient docker
private String currentVersion = System.getProperty("currentVersion")
@Before
public void before() throws Exception {
// First test to run, formats metadata and bookies
if (BookKeeperClusterUtils.metadataFormatIfNeeded(docker, currentVersion)) {
BookKeeperClusterUtils.formatAllBookies(docker, currentVersion)
}
// If already started, this has no effect
Assert.assertTrue(BookKeeperClusterUtils.startAllBookiesWithVersion(docker, currentVersion))
}
private void testFencingOldClient(String oldClientVersion, String fencingVersion) {
String zookeeper = BookKeeperClusterUtils.zookeeperConnectString(docker)
def oldCL = MavenClassLoader.forBookKeeperVersion(oldClientVersion)
def oldBK = oldCL.newBookKeeper(zookeeper)
def fencingCL = MavenClassLoader.forBookKeeperVersion(fencingVersion)
def fencingBK = fencingCL.newBookKeeper(zookeeper)
try {
def numEntries = 5
def ledger0 = oldBK.createLedger(3, 2,
oldCL.digestType("CRC32"),
PASSWD)
for (int i = 0; i < numEntries; i++) {
ledger0.addEntry(("foobar" + i).getBytes())
}
ledger0.close()
def ledger1 = fencingBK.openLedger(ledger0.getId(), fencingCL.digestType("CRC32"), PASSWD)
// cannot write any more
try {
ledger0.addEntry("shouldn't work".getBytes())
Assert.fail("Shouldn't have been able to add any more")
} catch (Exception e) {
Assert.assertEquals(e.getClass().getName(),
"org.apache.bookkeeper.client.BKException\$BKLedgerClosedException")
}
// should be able to open it and read it back
def ledger2 = oldBK.openLedger(ledger0.getId(), oldCL.digestType("CRC32"), PASSWD)
def entries = ledger2.readEntries(0, ledger2.getLastAddConfirmed())
Assert.assertEquals(numEntries, ledger2.getLastAddConfirmed() + 1 /* counts from 0 */)
int j = 0
while (entries.hasMoreElements()) {
def e = entries.nextElement()
Assert.assertEquals(new String(e.getEntry()), "foobar"+ j)
j++
}
ledger2.close()
} finally {
oldBK.close()
oldCL.close()
fencingBK.close()
fencingCL.close()
}
}
@Test
public void testNewClientFencesOldClient() throws Exception {
oldClientVersions.each{
def version = it
ThreadReaper.runWithReaper({ testFencingOldClient(version, currentVersion) })
}
}
@Test
public void testOldClientFencesOldClient() throws Exception {
oldClientVersions.each{
def version = it
ThreadReaper.runWithReaper({ testFencingOldClient(version, version) })
}
}
private void testReads(String writeVersion, String readerVersion) throws Exception {
String zookeeper = BookKeeperClusterUtils.zookeeperConnectString(docker)
def writeCL = MavenClassLoader.forBookKeeperVersion(writeVersion)
def writeBK = writeCL.newBookKeeper(zookeeper)
def readCL = MavenClassLoader.forBookKeeperVersion(readerVersion)
def readBK = readCL.newBookKeeper(zookeeper)
try {
def numEntries = 5
def ledger0 = writeBK.createLedger(3, 2,
writeCL.digestType("CRC32"),
PASSWD)
for (int i = 0; i < numEntries; i++) {
ledger0.addEntry(("foobar" + i).getBytes())
}
ledger0.close()
def ledger1 = readBK.openLedger(ledger0.getId(), readCL.digestType("CRC32"), PASSWD)
def entries = ledger1.readEntries(0, ledger1.getLastAddConfirmed())
Assert.assertEquals(numEntries, ledger1.getLastAddConfirmed() + 1 /* counts from 0 */)
int j = 0
while (entries.hasMoreElements()) {
def e = entries.nextElement()
Assert.assertEquals(new String(e.getEntry()), "foobar"+ j)
j++
}
ledger1.close()
} finally {
readBK.close()
readCL.close()
writeBK.close()
writeCL.close()
}
}
private void testReadOpenFailure(String writeVersion, String readerVersion) throws Exception {
String zookeeper = BookKeeperClusterUtils.zookeeperConnectString(docker)
def writeCL = MavenClassLoader.forBookKeeperVersion(writeVersion)
def writeBK = writeCL.newBookKeeper(zookeeper)
def readCL = MavenClassLoader.forBookKeeperVersion(readerVersion)
def readBK = readCL.newBookKeeper(zookeeper)
try {
def numEntries = 5
def ledger0 = writeBK.createLedger(3, 2,
writeCL.digestType("CRC32"),
PASSWD)
for (int i = 0; i < numEntries; i++) {
ledger0.addEntry(("foobar" + i).getBytes())
}
ledger0.close()
try {
def ledger1 = readBK.openLedger(ledger0.getId(), readCL.digestType("CRC32"), PASSWD)
Assert.fail("For older versions Openledger call is expected to fail with ZKException");
} catch (Exception exc) {
Assert.assertEquals(exc.getClass().getName(),
"org.apache.bookkeeper.client.BKException\$ZKException")
}
} finally {
readBK.close()
readCL.close()
writeBK.close()
writeCL.close()
}
}
/**
* Since METADATA_VERSION is upgraded and it is using binary format, the older
* clients which are expecting text format would fail to read ledger metadata.
*/
@Test
public void testOldClientReadsNewClient() throws Exception {
oldClientVersions.each{
def version = it
ThreadReaper.runWithReaper({ testReadOpenFailure(currentVersion, version) })
}
}
@Test
public void testNewClientReadsNewClient() throws Exception {
oldClientVersions.each{
def version = it
ThreadReaper.runWithReaper({ testReads(version, currentVersion) })
}
}
}