blob: fc510d5108ff0225dde58cb5a7c47be7d9b15841 [file] [log] [blame]
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.chef.internal;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.hash.Hashing.md5;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.jclouds.io.ByteSources.asByteSource;
import static org.jclouds.util.Predicates2.retry;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.domain.ChecksumStatus;
import org.jclouds.chef.domain.Client;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.domain.Environment;
import org.jclouds.chef.domain.Node;
import org.jclouds.chef.domain.Resource;
import org.jclouds.chef.domain.Role;
import org.jclouds.chef.domain.SearchResult;
import org.jclouds.chef.domain.UploadSandbox;
import org.jclouds.chef.options.CreateClientOptions;
import org.jclouds.chef.options.SearchOptions;
import org.jclouds.crypto.Pems;
import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.FilePayload;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Closeables;
import com.google.common.primitives.Bytes;
/**
* Tests behavior of {@code ChefApi}
*
* @author Adrian Cole
*/
@Test(groups = { "live", "integration" })
public abstract class BaseChefApiLiveTest<A extends ChefApi> extends BaseChefLiveTest<A> {
public static final String PREFIX = "jcloudstest-" + System.getProperty("user.name");
public static final String ADMIN_PREFIX = "jcloudstest-adm-" + System.getProperty("user.name");
// It may take a bit until the search index is populated
protected int maxWaitForIndexInMs = 60000;
private Node node;
private Role role;
protected DatabagItem databagItem;
public void testCreateNewCookbook() throws Exception {
// define the file you want in the cookbook
FilePayload content = Payloads.newFilePayload(new File(System.getProperty("user.dir"), "pom.xml"));
content.getContentMetadata().setContentType("application/x-binary");
// get an md5 so that you can see if the server already has it or not
Payloads.calculateMD5(content);
// Note that java collections cannot effectively do equals or hashcodes on
// byte arrays,
// so let's convert to a list of bytes.
List<Byte> md5 = Bytes.asList(content.getContentMetadata().getContentMD5());
// request an upload site for this file
UploadSandbox site = api.getUploadSandboxForChecksums(ImmutableSet.of(md5));
try {
assert site.getChecksums().containsKey(md5) : md5 + " not in " + site.getChecksums();
ChecksumStatus status = site.getChecksums().get(md5);
if (status.needsUpload()) {
// context.utils().http().put(status.getUrl(), content);
api.uploadContent(status.getUrl(), content);
}
api.commitSandbox(site.getSandboxId(), true);
} catch (RuntimeException e) {
api.commitSandbox(site.getSandboxId(), false);
}
// create a new cookbook
CookbookVersion cookbook = new CookbookVersion(PREFIX, "0.0.0");
cookbook.getRootFiles().add(new Resource(content));
// upload the cookbook to the remote server
api.updateCookbook(PREFIX, "0.0.0", cookbook);
}
@Test(dependsOnMethods = "testCreateClient")
public void testGenerateKeyForClient() throws Exception {
String credential = Pems.pem(api.generateKeyForClient(PREFIX).getPrivateKey());
assertClientCreated(PREFIX, credential);
}
@Test
public void testListCookbooks() throws Exception {
Set<String> cookbookNames = api.listCookbooks();
assertFalse(cookbookNames.isEmpty());
for (String cookbook : cookbookNames) {
for (String version : api.getVersionsOfCookbook(cookbook)) {
CookbookVersion cookbookO = api.getCookbook(cookbook, version);
for (Resource resource : ImmutableList.<Resource> builder().addAll(cookbookO.getDefinitions())
.addAll(cookbookO.getFiles()).addAll(cookbookO.getLibraries()).addAll(cookbookO.getSuppliers())
.addAll(cookbookO.getRecipes()).addAll(cookbookO.getResources()).addAll(cookbookO.getRootFiles())
.addAll(cookbookO.getTemplates()).build()) {
try {
InputStream stream = api.getResourceContents(resource);
byte[] md5 = asByteSource(stream).hash(md5()).asBytes();
assertEquals(md5, resource.getChecksum());
} catch (NullPointerException e) {
assert false : "resource not found: " + resource;
}
}
}
}
}
@Test(dependsOnMethods = "testCreateNewCookbook")
public void testUpdateCookbook() throws Exception {
CookbookVersion cookbook = api.getCookbook(PREFIX, "0.0.0");
assertNotNull(api.updateCookbook(PREFIX, "0.0.0", cookbook));
}
@Test(dependsOnMethods = { "testCreateNewCookbook", "testUpdateCookbook" })
public void testDeleteCookbook() throws Exception {
assertNotNull(api.deleteCookbook(PREFIX, "0.0.0"));
}
@Test
public void testCreateClient() throws Exception {
api.deleteClient(PREFIX);
String credential = Pems.pem(api.createClient(PREFIX).getPrivateKey());
assertClientCreated(PREFIX, credential);
}
@Test
public void testCreateAdminClient() throws Exception {
api.deleteClient(ADMIN_PREFIX);
String credential = Pems.pem(api.createClient(ADMIN_PREFIX, CreateClientOptions.Builder.admin()).getPrivateKey());
assertClientCreated(ADMIN_PREFIX, credential);
}
@Test
public void testClientExists() throws Exception {
assertNotNull(api.clientExists(identity));
}
@Test
public void testListNodes() throws Exception {
Set<String> nodes = api.listNodes();
assertNotNull(nodes);
}
@Test(dependsOnMethods = "testCreateRole")
public void testCreateNode() throws Exception {
api.deleteNode(PREFIX);
api.createNode(new Node(PREFIX, Collections.singleton("role[" + PREFIX + "]"), "_default"));
node = api.getNode(PREFIX);
// TODO check recipes
assertNotNull(node);
Set<String> nodes = api.listNodes();
assert nodes.contains(PREFIX) : String.format("node %s not in %s", PREFIX, nodes);
}
@Test(dependsOnMethods = "testCreateNode")
public void testNodeExists() throws Exception {
assertNotNull(api.nodeExists(PREFIX));
}
@Test(dependsOnMethods = "testNodeExists")
public void testUpdateNode() throws Exception {
for (String nodename : api.listNodes()) {
Node node = api.getNode(nodename);
api.updateNode(node);
}
}
@Test
public void testListRoles() throws Exception {
Set<String> roles = api.listRoles();
assertNotNull(roles);
}
@Test
public void testCreateRole() throws Exception {
api.deleteRole(PREFIX);
api.createRole(new Role(PREFIX, Collections.singleton("recipe[java]")));
role = api.getRole(PREFIX);
assertNotNull(role);
assertEquals(role.getName(), PREFIX);
assertEquals(role.getRunList(), Collections.singleton("recipe[java]"));
}
@Test(dependsOnMethods = "testCreateRole")
public void testRoleExists() throws Exception {
assertNotNull(api.roleExists(PREFIX));
}
@Test(dependsOnMethods = "testRoleExists")
public void testUpdateRole() throws Exception {
for (String rolename : api.listRoles()) {
Role role = api.getRole(rolename);
api.updateRole(role);
}
}
@Test
public void testListDatabags() throws Exception {
Set<String> databags = api.listDatabags();
assertNotNull(databags);
}
@Test
public void testCreateDatabag() throws Exception {
api.deleteDatabag(PREFIX);
api.createDatabag(PREFIX);
}
@Test(dependsOnMethods = "testCreateDatabag")
public void testDatabagExists() throws Exception {
assertNotNull(api.databagExists(PREFIX));
}
@Test(dependsOnMethods = "testCreateDatabagItem")
public void testListDatabagItems() throws Exception {
Set<String> databagItems = api.listDatabagItems(PREFIX);
assertNotNull(databagItems);
}
@Test(dependsOnMethods = "testCreateDatabag")
public void testCreateDatabagItem() throws Exception {
Properties config = new Properties();
config.setProperty("foo", "bar");
api.deleteDatabagItem(PREFIX, PREFIX);
databagItem = api.createDatabagItem(PREFIX, new DatabagItem("config", json.toJson(config)));
assertNotNull(databagItem);
assertEquals(databagItem.getId(), "config");
// The databagItem json contains extra keys: (the name and the type if the
// item)
Properties props = json.fromJson(databagItem.toString(), Properties.class);
for (Object key : config.keySet()) {
assertTrue(props.containsKey(key));
assertEquals(config.get(key), props.get(key));
}
}
@Test(dependsOnMethods = "testCreateDatabagItem")
public void testDatabagItemExists() throws Exception {
assertNotNull(api.databagItemExists(PREFIX, PREFIX));
}
@Test(dependsOnMethods = "testDatabagItemExists")
public void testUpdateDatabagItem() throws Exception {
for (String databagItemId : api.listDatabagItems(PREFIX)) {
DatabagItem databagItem = api.getDatabagItem(PREFIX, databagItemId);
api.updateDatabagItem(PREFIX, databagItem);
}
}
@Test
public void testListSearchIndexes() throws Exception {
Set<String> indexes = api.listSearchIndexes();
assertNotNull(indexes);
assert indexes.contains("node") : indexes;
assert indexes.contains("client") : indexes;
assert indexes.contains("role") : indexes;
}
@Test
public void testSearchNodes() throws Exception {
SearchResult<? extends Node> results = api.searchNodes();
assertNotNull(results);
}
@Test(dependsOnMethods = { "testListSearchIndexes", "testCreateNode" })
public void testSearchNodesWithOptions() throws Exception {
Predicate<SearchOptions> waitForIndex = retry(new Predicate<SearchOptions>() {
@Override
public boolean apply(SearchOptions input) {
SearchResult<? extends Node> results = api.searchNodes(input);
assertNotNull(results);
if (results.size() > 0) {
assertEquals(results.size(), 1);
assertEquals(results.iterator().next().getName(), PREFIX);
return true;
} else {
// The index may still not be populated
return false;
}
}
}, maxWaitForIndexInMs, 5000L, MILLISECONDS);
SearchOptions options = SearchOptions.Builder.query("name:" + PREFIX);
assertTrue(waitForIndex.apply(options));
}
@Test
public void testSearchClients() throws Exception {
SearchResult<? extends Client> results = api.searchClients();
assertNotNull(results);
}
@Test(dependsOnMethods = { "testListSearchIndexes", "testCreateClient" })
public void testSearchClientsWithOptions() throws Exception {
Predicate<SearchOptions> waitForIndex = retry(new Predicate<SearchOptions>() {
@Override
public boolean apply(SearchOptions input) {
SearchResult<? extends Client> results = api.searchClients(input);
assertNotNull(results);
if (results.size() > 0) {
assertEquals(results.size(), 1);
assertEquals(results.iterator().next().getName(), PREFIX);
return true;
} else {
// The index may still not be populated
return false;
}
}
}, maxWaitForIndexInMs, 5000L, MILLISECONDS);
SearchOptions options = SearchOptions.Builder.query("name:" + PREFIX);
assertTrue(waitForIndex.apply(options));
}
@Test
public void testSearchRoles() throws Exception {
SearchResult<? extends Role> results = api.searchRoles();
assertNotNull(results);
}
@Test(dependsOnMethods = { "testListSearchIndexes", "testCreateRole" })
public void testSearchRolesWithOptions() throws Exception {
Predicate<SearchOptions> waitForIndex = retry(new Predicate<SearchOptions>() {
@Override
public boolean apply(SearchOptions input) {
SearchResult<? extends Role> results = api.searchRoles(input);
assertNotNull(results);
if (results.size() > 0) {
assertEquals(results.size(), 1);
assertEquals(results.iterator().next().getName(), PREFIX);
return true;
} else {
// The index may still not be populated
return false;
}
}
}, maxWaitForIndexInMs, 5000L, MILLISECONDS);
SearchOptions options = SearchOptions.Builder.query("name:" + PREFIX);
assertTrue(waitForIndex.apply(options));
}
@Test(dependsOnMethods = { "testListSearchIndexes", "testDatabagItemExists" })
public void testSearchDatabag() throws Exception {
SearchResult<? extends DatabagItem> results = api.searchDatabag(PREFIX);
assertNotNull(results);
}
@Test(dependsOnMethods = { "testListSearchIndexes", "testDatabagItemExists" })
public void testSearchDatabagWithOptions() throws Exception {
Predicate<SearchOptions> waitForIndex = retry(new Predicate<SearchOptions>() {
@Override
public boolean apply(SearchOptions input) {
SearchResult<? extends DatabagItem> results = api.searchDatabag(PREFIX, input);
assertNotNull(results);
if (results.size() > 0) {
assertEquals(results.size(), 1);
assertEquals(results.iterator().next().getId(), databagItem.getId());
return true;
} else {
// The index may still not be populated
return false;
}
}
}, maxWaitForIndexInMs, 5000L, MILLISECONDS);
SearchOptions options = SearchOptions.Builder.query("id:" + databagItem.getId());
assertTrue(waitForIndex.apply(options));
}
@Test(expectedExceptions = ResourceNotFoundException.class, dependsOnMethods = "testListSearchIndexes")
public void testSearchDatabagNotFound() throws Exception {
SearchResult<? extends DatabagItem> results = api.searchDatabag("whoopie");
assertNotNull(results);
}
@Test
public void testCreateEnvironment() {
api.deleteEnvironment(PREFIX);
api.createEnvironment(new Environment(PREFIX, PREFIX));
Environment env = api.getEnvironment(PREFIX);
assertNotNull(env);
assertEquals(env.getName(), PREFIX);
assertEquals(env.getDescription(), PREFIX);
}
@Test(dependsOnMethods = "testCreateEnvironment")
public void testListEnvironment() {
Set<String> envList = api.listEnvironments();
assertNotNull(envList);
assertTrue(envList.contains(PREFIX));
}
@Test(dependsOnMethods = "testCreateEnvironment")
public void testSearchEnvironments() throws Exception {
SearchResult<? extends Environment> results = api.searchEnvironments();
assertNotNull(results);
}
@Test(dependsOnMethods = { "testListSearchIndexes", "testCreateEnvironment" })
public void testSearchEnvironmentsWithOptions() throws Exception {
Predicate<SearchOptions> waitForIndex = retry(new Predicate<SearchOptions>() {
@Override
public boolean apply(SearchOptions input) {
SearchResult<? extends Environment> results = api.searchEnvironments(input);
assertNotNull(results);
if (results.size() > 0) {
assertEquals(results.size(), 1);
assertEquals(results.iterator().next().getName(), PREFIX);
return true;
} else {
// The index may still not be populated
return false;
}
}
}, maxWaitForIndexInMs, 5000L, MILLISECONDS);
SearchOptions options = SearchOptions.Builder.query("name:" + PREFIX);
assertTrue(waitForIndex.apply(options));
}
@Test
public void testListCookbookVersionsWithChefService() throws Exception {
Iterable<? extends CookbookVersion> cookbooks = chefService.listCookbookVersions();
assertNotNull(cookbooks);
}
@AfterClass(groups = { "live", "integration" })
@Override
public void tearDown() {
api.deleteClient(PREFIX);
api.deleteClient(ADMIN_PREFIX);
api.deleteNode(PREFIX);
api.deleteRole(PREFIX);
api.deleteDatabag(PREFIX);
api.deleteEnvironment(PREFIX);
super.tearDown();
}
private void assertClientCreated(String identity, String credential) {
Properties overrides = super.setupProperties();
overrides.setProperty(provider + ".identity", identity);
overrides.setProperty(provider + ".credential", credential);
A clientApi = create(overrides, setupModules());
try {
Client client = clientApi.getClient(identity);
assertNotNull(client);
} finally {
try {
Closeables.close(clientApi, true);
} catch (IOException e) {
throw propagate(e);
}
}
}
}