add tenant list metadata to binding tester

This commit is contained in:
Jon Fu 2022-05-02 13:42:11 -04:00
parent d953b961b7
commit ff216c2f57
9 changed files with 97 additions and 132 deletions

View File

@ -1,91 +0,0 @@
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.KeyValue;
import com.apple.foundationdb.Tenant;
import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.tuple.Tuple;
import com.apple.foundationdb.KeyArrayResult;
import com.apple.foundationdb.TenantManagement;
import com.apple.foundationdb.async.AsyncUtil;
import static com.apple.foundationdb.async.AsyncUtil.collectRemaining;
import com.apple.foundationdb.async.CloseableAsyncIterator;
public class TenantTest {
private FDB fdb;
private Database db;
CloseableAsyncIterator<KeyValue> tenants;
public TenantTest() {
try {
fdb = FDB.selectAPIVersion(710);
fdb.options().setTraceEnable(null);
db = fdb.open();
///*
Tuple t1 = Tuple.from("tenant");
Tuple t2 = Tuple.from("tenant2");
Tuple t3 = Tuple.from("tenant3");
//*/
/*
byte[] t1 = Tuple.from("tenant").pack();
byte[] t2 = Tuple.from("tenant2").pack();
byte[] t3 = Tuple.from("tenant3").pack();
*/
System.out.println(t1);
System.out.println(t2);
System.out.println(t3);
TenantManagement.createTenant(db, t1).join();
TenantManagement.createTenant(db, t2).join();
TenantManagement.createTenant(db, t3).join();
tenants = TenantManagement.listTenants(db, Tuple.from("a").pack(), Tuple.from("z").pack(), 100);
try {
/*
List<KeyValue> result = AsyncUtil.collectRemaining(tenants).join();
System.out.println("Size: " + result.size());
for(int i = 0; i < result.size(); i++) {
System.out.println(i);
KeyValue res = result.get(i);
System.out.println(new String(res.getKey()));
System.out.println(new String(res.getValue()));
}
*/
// /*
while (tenants.hasNext()) {
KeyValue res = tenants.next();
System.out.println(new String(res.getKey()));
System.out.println(new String(res.getValue()));
}
// */
}
finally {
tenants.close();
}
TenantManagement.deleteTenant(db, t1).join();
TenantManagement.deleteTenant(db, t2).join();
TenantManagement.deleteTenant(db, t3).join();
}
catch(Exception e) {
e.printStackTrace();
}
}
public void close() {
db.close();
}
public static void main(String[] args) {
new TenantTest().close();
}
}

View File

@ -38,10 +38,16 @@ The tenant API introduces some new operations:
Unsets the active tenant.
#### TENANT_LIST
#### TENANT_LIST_NAMES
Pops the top 3 items off of the stack as BEGIN, END, & LIMIT. Returns list
of tenants contained in the range BEGIN to END, numbering LIMIT at most.
of tenant names contained in the range BEGIN to END, numbering LIMIT at most.
May optionally push a future onto the stack.
#### TENANT_LIST_METADATA
Pops the top 3 items off of the stack as BEGIN, END, & LIMIT. Returns list
of tenant metadata contained in the range BEGIN to END, numbering LIMIT at most.
May optionally push a future onto the stack.
Updates to Existing Instructions

View File

@ -165,7 +165,7 @@ class ApiTest(Test):
write_conflicts = ['WRITE_CONFLICT_RANGE', 'WRITE_CONFLICT_KEY', 'DISABLE_WRITE_CONFLICT']
txn_sizes = ['GET_APPROXIMATE_SIZE']
storage_metrics = ['GET_ESTIMATED_RANGE_SIZE', 'GET_RANGE_SPLIT_POINTS']
tenants = ['TENANT_CREATE', 'TENANT_DELETE', 'TENANT_SET_ACTIVE', 'TENANT_CLEAR_ACTIVE', 'TENANT_LIST_NAMES']
tenants = ['TENANT_CREATE', 'TENANT_DELETE', 'TENANT_SET_ACTIVE', 'TENANT_CLEAR_ACTIVE', 'TENANT_LIST_NAMES', 'TENANT_LIST_METADATA']
op_choices += reads
op_choices += mutations
@ -604,6 +604,10 @@ class ApiTest(Test):
instructions.push_args(b'', b'\xff', 10000)
instructions.append(op)
self.add_strings(1)
elif op == 'TENANT_LIST_METADATA':
instructions.push_args(b'', b'\xff', 10000)
instructions.append(op)
self.add_strings(1)
else:
assert False, 'Unknown operation: ' + op

View File

@ -509,6 +509,37 @@ public class AsyncStackTester {
inst.push(output);
}, FDB.DEFAULT_EXECUTOR);
}
else if (op == StackOperation.TENANT_LIST_METADATA) {
return inst.popParams(3).thenAcceptAsync(params -> {
byte[] begin = (byte[])params.get(0);
byte[] end = (byte[])params.get(1);
int limit = StackUtils.getInt(params.get(2));
CloseableAsyncIterator<KeyValue> tenantIter =
TenantManagement.listTenants(inst.context.db, begin, end, limit);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
boolean validData = true;
try {
while (tenantIter.hasNext()) {
KeyValue next = tenantIter.next();
String metadata = new String(next.getValue());
// Without a JSON parsing library, we try to validate that the metadata consists
// of a select few properties using simple string comparison
if (metadata.charAt(0) != '{' || metadata.charAt(metadata.length() - 1) != '}' ||
!metadata.contains("id") || !metadata.contains("prefix")) {
validData = false;
break;
}
}
} finally {
tenantIter.close();
}
if (validData) {
inst.push("VALID_TENANT_METADATA".getBytes());
} else {
inst.push("INVALID_TENANT_METADATA".getBytes());
}
}, FDB.DEFAULT_EXECUTOR);
}
else if (op == StackOperation.TENANT_SET_ACTIVE) {
return inst.popParam().thenAcceptAsync(param -> {
byte[] tenantName = (byte[])param;
@ -519,7 +550,7 @@ public class AsyncStackTester {
inst.context.setTenant(Optional.empty());
return AsyncUtil.DONE;
}
else if(op == StackOperation.UNIT_TESTS) {
else if (op == StackOperation.UNIT_TESTS) {
inst.context.db.options().setLocationCacheSize(100001);
return inst.context.db.runAsync(tr -> {
FDB fdb = FDB.instance();
@ -594,7 +625,7 @@ public class AsyncStackTester {
throw new RuntimeException("Unit tests failed: " + t.getMessage());
});
}
else if(op == StackOperation.LOG_STACK) {
else if (op == StackOperation.LOG_STACK) {
return inst.popParam().thenComposeAsync(prefix -> doLogStack(inst, (byte[])prefix), FDB.DEFAULT_EXECUTOR);
}

View File

@ -77,6 +77,7 @@ enum StackOperation {
TENANT_CREATE,
TENANT_DELETE,
TENANT_LIST_NAMES,
TENANT_LIST_METADATA,
TENANT_SET_ACTIVE,
TENANT_CLEAR_ACTIVE,

View File

@ -453,6 +453,36 @@ public class StackTester {
byte[] output = outputStream.toByteArray();
inst.push(output);
}
else if (op == StackOperation.TENANT_LIST_METADATA) {
List<Object> params = inst.popParams(3).join();
byte[] begin = (byte[])params.get(0);
byte[] end = (byte[])params.get(1);
int limit = StackUtils.getInt(params.get(2));
CloseableAsyncIterator<KeyValue> tenantIter =
TenantManagement.listTenants(inst.context.db, begin, end, limit);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
boolean validData = true;
try {
while (tenantIter.hasNext()) {
KeyValue next = tenantIter.next();
String metadata = new String(next.getValue());
// Without a JSON parsing library, we try to validate that the metadata consists
// of a select few properties using simple string comparison
if (metadata.charAt(0) != '{' || metadata.charAt(metadata.length() - 1) != '}' ||
!metadata.contains("id") || !metadata.contains("prefix")) {
validData = false;
break;
}
}
} finally {
tenantIter.close();
}
if (validData) {
inst.push("VALID_TENANT_METADATA".getBytes());
} else {
inst.push("INVALID_TENANT_METADATA".getBytes());
}
}
else if (op == StackOperation.TENANT_SET_ACTIVE) {
byte[] tenantName = (byte[])inst.popParam().join();
inst.context.setTenant(Optional.of(tenantName));
@ -460,7 +490,7 @@ public class StackTester {
else if (op == StackOperation.TENANT_CLEAR_ACTIVE) {
inst.context.setTenant(Optional.empty());
}
else if(op == StackOperation.UNIT_TESTS) {
else if (op == StackOperation.UNIT_TESTS) {
try {
inst.context.db.options().setLocationCacheSize(100001);
inst.context.db.run(tr -> {
@ -538,7 +568,7 @@ public class StackTester {
throw new RuntimeException("Unit tests failed: " + e.getMessage());
}
}
else if(op == StackOperation.LOG_STACK) {
else if (op == StackOperation.LOG_STACK) {
List<Object> params = inst.popParams(1).join();
byte[] prefix = (byte[]) params.get(0);

View File

@ -131,4 +131,4 @@ def list_tenants(db_or_tr, begin, end, limit):
begin = _impl.process_tenant_name(begin)
end = _impl.process_tenant_name(end)
return _list_tenants_impl(db_or_tr, begin, end, limit)
return _list_tenants_impl(db_or_tr, begin, end, limit)

View File

@ -30,6 +30,7 @@ import time
import random
import time
import traceback
import json
sys.path[:0] = [os.path.join(os.path.dirname(__file__), '..')]
import fdb
@ -612,6 +613,22 @@ class Tester:
result += tenant.key
result_bytes = bytes(result)
inst.push(result_bytes)
elif inst.op == six.u("TENANT_LIST_METADATA"):
begin, end, limit = inst.pop(3)
tenant_list = fdb.tenant_management.list_tenants(self.db, begin, end, limit)
valid_data = True
for tenant in tenant_list:
try:
metadata = json.loads(tenant.value)
id = metadata["id"]
prefix = metadata["prefix"]
except (json.decoder.JSONDecodeError, KeyError) as e:
valid_data = False
break
if valid_data:
inst.push(b"VALID_TENANT_METADATA")
else:
inst.push(b"INVALID_TENANT_METADATA")
elif inst.op == six.u("UNIT_TESTS"):
try:
test_db_options(db)

View File

@ -1,33 +0,0 @@
#!/usr/bin/env python3
import fdb
import sys
fdb.api_version(710)
db=fdb.open()
db.options.set_transaction_timeout(2000)
#tenant = b'tenant'
#tenant2 = b'tenant2'
#tenant3 = b'tenant3'
tenant = (u"tenant",)
tenant2 = (u"tenant2",)
tenant3 = (u"tenant3",)
fdb.tenant_management.create_tenant(db, tenant)
fdb.tenant_management.create_tenant(db, tenant2)
fdb.tenant_management.create_tenant(db, tenant3)
res = fdb.tenant_management.list_tenants(db, (u"a",), (u"z",), 10)
#res = fdb.tenant_management.list_tenants(db, b'a', b'z', 10)
for t in res:
print(t.key.decode())
print(t.value.decode())
fdb.tenant_management.delete_tenant(db, tenant)
fdb.tenant_management.delete_tenant(db, tenant2)
fdb.tenant_management.delete_tenant(db, tenant3)
sys.exit(0)