Java tutorial
/* * Copyright 2017 IBM Corporation * * Licensed 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 catalog; import com.cloudant.client.api.CloudantClient; import com.cloudant.client.api.Database; import com.google.gson.*; import com.jayway.restassured.response.Response; import common.Pair; import common.TestUtils; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Date; import java.util.Map; import java.util.Properties; import java.util.UUID; import static com.jayway.restassured.RestAssured.given; import static org.junit.Assert.assertTrue; /** * Basic tests of the cloudant trigger function. */ public class CloudantUtil { public static final String USER_PROPERTY = "user"; public static final String PWD_PROPERTY = "password"; public static final String DBNAME_PROPERTY = "dbname"; public static final String DOC_ID = "testId"; public static final File ATTACHMENT_FILE_PATH = getFileRelativeToCloudantHome("tests/dat/attach.txt"); public static final File INDEX_DDOC_PATH = getFileRelativeToCloudantHome("tests/dat/indexdesigndoc.txt"); public static final File VIEW_AND_SEARCH_DDOC_PATH = getFileRelativeToCloudantHome( "tests/dat/searchdesigndoc.txt"); /** * The root of the Cloudant installation. */ private static final String cloudantHome = getCloudantHome(); private static final String CLOUDANT_INSTALL_FILE = "installCatalog.sh"; private static Gson gson = new Gson(); public static class Credential { public final String user; public final String password; public final String dbname; public String host() { return user + ".cloudant.com"; } public Credential(String user, String password, String dbname) { this.user = user; this.password = password; this.dbname = dbname; } public Credential(Properties props) { this(props.getProperty(USER_PROPERTY), props.getProperty(PWD_PROPERTY), props.getProperty(DBNAME_PROPERTY)); } public static Credential makeFromVCAPFile(String vcapService, String dbNamePrefix) { // Create database name using dbNamePrefix and generated uuid String uniqueSuffix = UUID.randomUUID().toString().replace("-", ""); String dbname = dbNamePrefix.toLowerCase() + "-" + uniqueSuffix; Map<String, String> credentials = TestUtils.getVCAPcredentials(vcapService); String username = credentials.get("username"); String password = credentials.get("password"); Properties props = new Properties(); props.setProperty(USER_PROPERTY, username); props.setProperty(PWD_PROPERTY, password); props.setProperty(DBNAME_PROPERTY, dbname); return new Credential(props); } } public static void setUp(Credential credential) throws Exception { deleteTestDatabase(credential); for (int i = 0; i < 5; i++) { try { Pair<Integer, JsonObject> response = CloudantUtil.createTestDatabase(credential, false); if (response.fst == 201) return; // respond code is sometimes not 201 but still ok // (might be 200 or 202) if (response.snd.has("ok")) { if (response.snd.get("ok").getAsBoolean()) return; } if (response.snd.has("reason")) { String reason = response.snd.get("reason").getAsString(); if (reason.contains("exists")) return; } } catch (Throwable t) { Thread.sleep(1000); } } assertTrue("failed to create database " + credential.dbname, false); } public static void unsetUp(Credential credential) throws Exception { deleteTestDatabase(credential); } /** * Delete a user-specific Cloudant database. * * @throws UnsupportedEncodingException * @throws InterruptedException */ public static JsonObject deleteTestDatabase(Credential credential) throws UnsupportedEncodingException, InterruptedException { return deleteTestDatabase(credential, null); } public static JsonObject deleteTestDatabase(Credential credential, String dbName) throws UnsupportedEncodingException, InterruptedException { // Use DELETE to delete the database. // This could fail if the database already exists, but that's ok. Response response = null; String db = (dbName != null && !dbName.isEmpty()) ? dbName : credential.dbname; assertTrue("failed to determine database name", db != null && !db.isEmpty()); response = given().port(443).baseUri(cloudantAccount(credential.user)).auth() .basic(credential.user, credential.password).when().delete("/" + db); System.out.format("Response of delete database %s: %s\n", db, response.asString()); return (JsonObject) new JsonParser().parse(response.asString()); } /** * Create a user-specific Cloudant database that will be used for this test. * * @throws UnsupportedEncodingException */ public static Pair<Integer, JsonObject> createTestDatabase(Credential credential) throws UnsupportedEncodingException { return createTestDatabase(credential, true); } private static Pair<Integer, JsonObject> createTestDatabase(Credential credential, boolean failIfCannotCreate) throws UnsupportedEncodingException { // Use PUT to create the database. // This could fail if the database already exists, but that's ok. String dbName = credential.dbname; assertTrue("failed to determine database name", dbName != null && !dbName.isEmpty()); Response response = given().port(443).baseUri(cloudantAccount(credential.user)).auth() .basic(credential.user, credential.password).when().put("/" + dbName); System.out.format("Response of create database %s: %s\n", dbName, response.asString()); if (failIfCannotCreate) assertTrue("failed to create database " + dbName, response.statusCode() == 201 || response.statusCode() == 202); return Pair.make(response.statusCode(), (JsonObject) new JsonParser().parse(response.asString())); } /** * read a user-specific Cloudant database to verify database action test * cases. * * @throws UnsupportedEncodingException */ public static Response readTestDatabase(Credential credential) { return readTestDatabase(credential, null); } public static Response readTestDatabase(Credential credential, String dbName) { try { Response response = null; String db = (dbName != null && !dbName.isEmpty()) ? dbName : credential.dbname; response = given().port(443).baseUri(cloudantAccount(credential.user)).auth() .basic(credential.user, credential.password).when().get("/" + db); System.out.format("Response of HTTP GET for database %s: %s\n", credential.dbname, response.asString()); return response; } catch (Exception e) { e.printStackTrace(); return null; } } /** * create a document in the cloudant database * * @throws UnsupportedEncodingException */ public static JsonObject createDocument(Credential credential, String jsonObj) throws UnsupportedEncodingException { JsonObject obj = new JsonParser().parse(jsonObj).getAsJsonObject(); CloudantClient client = new CloudantClient(credential.user, credential.user, credential.password); Database db = client.database(credential.dbname, false); com.cloudant.client.api.model.Response res = db.post(obj); client.shutdown(); JsonObject ret = new JsonObject(); ret.addProperty("ok", true); ret.addProperty("id", res.getId()); ret.addProperty("rev", res.getRev()); return ret; } /** * get a document from the cloudant database * * @throws UnsupportedEncodingException */ public static JsonObject getDocument(Credential credential, String docId) throws UnsupportedEncodingException { // use GET to get the document Response response = given().port(443).baseUri(cloudantAccount(credential.user)).auth() .basic(credential.user, credential.password).get("/" + credential.dbname + "/" + docId); String responseStr = response.asString(); if (responseStr.length() > 500) responseStr = responseStr.substring(0, 500); System.out.format("Response of get document from database %s: %s\n", credential.dbname, responseStr); return (JsonObject) new JsonParser().parse(response.asString()); } /** * delete a document from the cloudant database * * @throws UnsupportedEncodingException */ public static JsonObject deleteDocument(Credential credential, String docId) throws UnsupportedEncodingException { // use GET to get the document Response response = given().port(443).baseUri(cloudantAccount(credential.user)).auth() .basic(credential.user, credential.password).delete("/" + credential.dbname + "/" + docId); System.out.format("Response of delete document in database %s: %s\n", credential.dbname, response.asString()); assertTrue("failed to delete document in database " + credential.dbname, response.statusCode() == 200 || response.statusCode() == 202); return (JsonObject) new JsonParser().parse(response.asString()); } /** * Read bulk documents from the cloudant database * * @throws UnsupportedEncodingException */ public static JsonArray bulkDocuments(Credential credential, JsonArray bulkDocs) throws UnsupportedEncodingException { JsonObject docs = new JsonObject(); docs.add("docs", bulkDocs); // use GET to get the document String dbname = credential.dbname; Response response = given().port(443).baseUri(cloudantAccount(credential.user)).auth() .basic(credential.user, credential.password).contentType("application/json").body(docs) .post("/" + credential.dbname + "/_bulk_docs?include_docs=true"); String responseStr = response.asString(); if (responseStr.length() > 500) responseStr = responseStr.substring(0, 500); System.out.format("Response of get document from database %s: %s\n", dbname, responseStr); return (JsonArray) new JsonParser().parse(response.asString()); } public static JsonObject createDocParameterForWhisk() { return createDocParameterForWhisk(null); } public static JsonObject createDocParameterForWhisk(String doc) { JsonObject cloudantDoc = new JsonObject(); String now = new Date().toString(); cloudantDoc.addProperty("_id", DOC_ID); cloudantDoc.addProperty("date", now); // Create JSON object that will be passed as an argument to whisk cli JsonObject param = new JsonObject(); if (doc != null && !doc.isEmpty()) { param.addProperty("doc", doc); } else { param.addProperty("doc", cloudantDoc.toString()); } return param; } public static JsonArray createDocumentArray(int numDocs) { // Array of docs for bulk JsonArray bulkDocs = new JsonArray(); for (int i = 1; i <= numDocs; i++) { JsonObject cloudantDoc = new JsonObject(); String now = new Date().toString(); cloudantDoc.addProperty("_id", CloudantUtil.DOC_ID + i); cloudantDoc.addProperty("date", now); bulkDocs.add(cloudantDoc); } return bulkDocs; } /** * Only keep _id and _rev for each document in the JSON array. */ public static JsonArray updateDocsWithOnlyIdAndRev(JsonArray docs) { for (int i = 0; i < docs.size(); i++) { JsonElement id = docs.get(i).getAsJsonObject().get("id"); JsonElement rev = docs.get(i).getAsJsonObject().get("rev"); docs.get(i).getAsJsonObject().add("_id", id); docs.get(i).getAsJsonObject().add("_rev", rev); } return docs; } public static JsonArray addDeletedPropertyToDocs(JsonArray docs) { for (int i = 0; i < docs.size(); i++) { JsonElement id = docs.get(i).getAsJsonObject().get("id"); JsonElement rev = docs.get(i).getAsJsonObject().get("rev"); docs.get(i).getAsJsonObject().add("_id", id); docs.get(i).getAsJsonObject().add("_rev", rev); docs.get(i).getAsJsonObject().addProperty("_deleted", true); } return docs; } public static JsonObject createDesignFromFile(File jsonFile) throws JsonSyntaxException, IOException { return gson.fromJson(readFile(jsonFile), JsonObject.class); } public static String readFile(File jsonFile) throws IOException { return new String(Files.readAllBytes(jsonFile.toPath()), StandardCharsets.UTF_8); } /** * Create an index in the cloudant database * * @throws UnsupportedEncodingException */ public static JsonObject createIndex(Credential credential, String jsonObj) throws UnsupportedEncodingException { Response response = given().port(443).baseUri(cloudantAccount(credential.user)).auth() .basic(credential.user, credential.password).contentType("application/json").body(jsonObj).when() .post("/" + credential.dbname + "/_index"); System.out.format("Response of create document in database %s: %s\n", credential.dbname, response.asString()); assertTrue("failed to create index in database " + credential.dbname, response.statusCode() == 200); return (JsonObject) new JsonParser().parse(response.asString()); } /** * Create a document with attachment in a cloudant database * * @throws UnsupportedEncodingException * @throws FileNotFoundException */ public static com.cloudant.client.api.model.Response createDocumentWithAttachment(Credential credential, File attachmentFilePath) throws UnsupportedEncodingException, FileNotFoundException { InputStream attachStream = new FileInputStream(attachmentFilePath); String contentType = "text/plain"; CloudantClient client = new CloudantClient(credential.user, credential.user, credential.password); Database db = client.database(credential.dbname, false); return db.saveAttachment(attachStream, attachmentFilePath.getName(), contentType); } private static String cloudantAccount(String user) { return "https://" + user + ".cloudant.com"; } public static File getFileRelativeToCloudantHome(String name) { return new File(cloudantHome, name); } private static String getCloudantHome() { String dir = System.getProperty("user.dir"); if (dir != null) { // Look in the directory tree recursively. File propfile = findFileRecursively(dir, CLOUDANT_INSTALL_FILE); return propfile != null ? propfile.getParent() : null; } else return null; } private static File findFileRecursively(String dir, String needle) { if (dir != null) { File base = new File(dir); File file = new File(base, needle); if (file.exists()) { return file; } else { return findFileRecursively(base.getParent(), needle); } } else return null; } }