http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/ohai/config/OhaiModule.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/ohai/config/OhaiModule.java b/apis/chef/src/main/java/org/jclouds/ohai/config/OhaiModule.java new file mode 100644 index 0000000..650fe9e --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/ohai/config/OhaiModule.java @@ -0,0 +1,183 @@ +/* + * 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.jclouds.ohai.config; + +import static org.jclouds.chef.util.ChefUtils.ohaiAutomaticAttributeBinder; +import static org.jclouds.chef.util.ChefUtils.toOhaiTime; + +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.jclouds.domain.JsonBall; +import org.jclouds.json.Json; +import org.jclouds.ohai.Automatic; +import org.jclouds.ohai.AutomaticSupplier; +import org.jclouds.ohai.functions.ByteArrayToMacAddress; +import org.jclouds.ohai.functions.MapSetToMultimap; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.collect.Multimap; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; +import com.google.inject.multibindings.MapBinder; + +/** + * Wires the components needed to parse ohai data + */ +@ConfiguresOhai +public class OhaiModule extends AbstractModule { + + @Override + protected void configure() { + bind(new TypeLiteral<Function<byte[], String>>() { + }).to(new TypeLiteral<ByteArrayToMacAddress>() { + }); + bindOhai(); + } + + @Provides + @Automatic + protected Supplier<Map<String, JsonBall>> provideAutomatic(AutomaticSupplier in) { + return in; + } + + @Provides + @Automatic + Multimap<String, Supplier<JsonBall>> provideAutomatic(MapSetToMultimap<String, Supplier<JsonBall>> converter, + @Automatic Map<String, Set<Supplier<JsonBall>>> input) { + return converter.apply(input); + + } + + @Named("systemProperties") + @Provides + protected Properties systemProperties() { + return System.getProperties(); + } + + public MapBinder<String, Supplier<JsonBall>> bindOhai() { + MapBinder<String, Supplier<JsonBall>> mapbinder = ohaiAutomaticAttributeBinder(binder()).permitDuplicates(); + mapbinder.addBinding("ohai_time").to(OhaiTimeProvider.class); + mapbinder.addBinding("jvm/system").to(SystemPropertiesProvider.class); + mapbinder.addBinding("platform").to(PlatformProvider.class); + mapbinder.addBinding("platform_version").to(PlatformVersionProvider.class); + mapbinder.addBinding("current_user").to(CurrentUserProvider.class); + return mapbinder; + } + + @Singleton + public static class OhaiTimeProvider implements Supplier<JsonBall> { + private final Provider<Long> timeProvider; + + @Inject + OhaiTimeProvider(Provider<Long> timeProvider) { + this.timeProvider = timeProvider; + } + + @Override + public JsonBall get() { + return toOhaiTime(timeProvider.get()); + } + + } + + @Provides + protected Long millis() { + return System.currentTimeMillis(); + } + + @Singleton + public static class SystemPropertiesProvider implements Supplier<JsonBall> { + + private final Json json; + private final Properties systemProperties; + + @Inject + SystemPropertiesProvider(Json json, @Named("systemProperties") Properties systemProperties) { + this.json = json; + this.systemProperties = systemProperties; + } + + @Override + public JsonBall get() { + return new JsonBall(json.toJson(systemProperties)); + } + + } + + @Singleton + public static class PlatformProvider extends SystemPropertyProvider { + + @Inject + PlatformProvider(@Named("systemProperties") Properties systemProperties) { + super("os.name", systemProperties); + } + + @Override + public JsonBall get() { + JsonBall returnValue = super.get(); + return returnValue != null ? new JsonBall(returnValue.toString().replaceAll("[ -]", "").toLowerCase()) : null; + } + + } + + @Singleton + public static class PlatformVersionProvider extends SystemPropertyProvider { + + @Inject + PlatformVersionProvider(@Named("systemProperties") Properties systemProperties) { + super("os.version", systemProperties); + } + + } + + @Singleton + public static class CurrentUserProvider extends SystemPropertyProvider { + + @Inject + CurrentUserProvider(@Named("systemProperties") Properties systemProperties) { + super("user.name", systemProperties); + } + + } + + public static class SystemPropertyProvider implements Supplier<JsonBall> { + private final Properties systemProperties; + private final String property; + + @Inject + SystemPropertyProvider(String property, @Named("systemProperties") Properties systemProperties) { + this.property = property; + this.systemProperties = systemProperties; + } + + @Override + public JsonBall get() { + return systemProperties.containsKey(property) ? new JsonBall(systemProperties.getProperty(property)) : null; + } + + } + +}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/ohai/functions/ByteArrayToMacAddress.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/ohai/functions/ByteArrayToMacAddress.java b/apis/chef/src/main/java/org/jclouds/ohai/functions/ByteArrayToMacAddress.java new file mode 100644 index 0000000..be7e46a --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/ohai/functions/ByteArrayToMacAddress.java @@ -0,0 +1,51 @@ +/* + * 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.jclouds.ohai.functions; + +import static com.google.common.collect.Iterables.transform; +import static com.google.common.collect.Lists.partition; +import static com.google.common.io.BaseEncoding.base16; +import static com.google.common.primitives.Bytes.asList; +import static com.google.common.primitives.Bytes.toArray; + +import java.util.List; + +import javax.inject.Singleton; + +import com.google.common.base.Function; +import com.google.common.base.Joiner; + +/** + * + * Creates a string in the form: {@code 00:26:bb:09:e6:c4 } + */ +@Singleton +public class ByteArrayToMacAddress implements Function<byte[], String> { + + @Override + public String apply(byte[] from) { + return Joiner.on(':').join(transform(partition(asList(from), 1), new Function<List<Byte>, String>() { + + @Override + public String apply(List<Byte> from) { + return base16().lowerCase().encode(toArray(from)); + } + + })); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/ohai/functions/MapSetToMultimap.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/ohai/functions/MapSetToMultimap.java b/apis/chef/src/main/java/org/jclouds/ohai/functions/MapSetToMultimap.java new file mode 100644 index 0000000..4ef3c87 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/ohai/functions/MapSetToMultimap.java @@ -0,0 +1,42 @@ +/* + * 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.jclouds.ohai.functions; + +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import javax.inject.Singleton; + +import com.google.common.base.Function; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; + +@Singleton +public class MapSetToMultimap<K, V> implements Function<Map<K, Set<V>>, Multimap<K, V>> { + + @Override + public Multimap<K, V> apply(Map<K, Set<V>> from) { + Multimap<K, V> returnV = LinkedHashMultimap.create(); + for (Entry<K, Set<V>> entry : from.entrySet()) { + for (V value : entry.getValue()) + returnV.put(entry.getKey(), value); + } + return returnV; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/ohai/functions/NestSlashKeys.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/ohai/functions/NestSlashKeys.java b/apis/chef/src/main/java/org/jclouds/ohai/functions/NestSlashKeys.java new file mode 100644 index 0000000..c709463 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/ohai/functions/NestSlashKeys.java @@ -0,0 +1,156 @@ +/* + * 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.jclouds.ohai.functions; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.domain.JsonBall; +import org.jclouds.json.Json; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import com.google.inject.TypeLiteral; + +@Singleton +public class NestSlashKeys implements Function<Multimap<String, Supplier<JsonBall>>, Map<String, JsonBall>> { + + private final Json json; + + @Inject + NestSlashKeys(Json json) { + this.json = checkNotNull(json, "json"); + } + + @Override + public Map<String, JsonBall> apply(Multimap<String, Supplier<JsonBall>> from) { + + Map<String, JsonBall> autoAttrs = mergeSameKeys(from); + + Map<String, JsonBall> modifiableFlatMap = Maps.newLinkedHashMap(Maps.filterKeys(autoAttrs, + new Predicate<String>() { + + @Override + public boolean apply(String input) { + return input.indexOf('/') == -1; + } + + })); + Map<String, JsonBall> withSlashesMap = Maps.difference(autoAttrs, modifiableFlatMap).entriesOnlyOnLeft(); + for (Entry<String, JsonBall> entry : withSlashesMap.entrySet()) { + List<String> keyParts = Lists.newArrayList(Splitter.on('/').split(entry.getKey())); + JsonBall toInsert = entry.getValue(); + try { + putUnderContext(keyParts, toInsert, modifiableFlatMap); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("error inserting value in entry: " + entry.getKey(), e); + } + } + return modifiableFlatMap; + } + + private Map<String, JsonBall> mergeSameKeys(Multimap<String, Supplier<JsonBall>> from) { + Map<String, JsonBall> merged = Maps.newLinkedHashMap(); + for (Entry<String, Supplier<JsonBall>> entry : from.entries()) { + if (merged.containsKey(entry.getKey())) { + mergeAsPeer(entry.getKey(), entry.getValue().get(), merged); + } else { + merged.put(entry.getKey(), entry.getValue().get()); + } + } + return merged; + } + + @VisibleForTesting + void mergeAsPeer(String key, JsonBall value, Map<String, JsonBall> insertionContext) { + Map<String, JsonBall> immutableValueContext = json.fromJson(insertionContext.get(key).toString(), mapLiteral); + Map<String, JsonBall> valueContext = Maps.newHashMap(immutableValueContext); + Map<String, JsonBall> toPut = json.<Map<String, JsonBall>> fromJson(value.toString(), mapLiteral); + Set<String> uniques = Sets.difference(toPut.keySet(), valueContext.keySet()); + for (String k : uniques) { + valueContext.put(k, toPut.get(k)); + } + Set<String> conflicts = Sets.difference(toPut.keySet(), uniques); + for (String k : conflicts) { + JsonBall v = toPut.get(k); + if (v.toString().matches("^\\{.*\\}$")) { + mergeAsPeer(k, v, valueContext); + } else { + // replace + valueContext.put(k, v); + } + } + insertionContext.put(key, new JsonBall(json.toJson(valueContext, mapLiteral))); + } + + /** + * @param keyParts + * @param toInsert + * @param destination + * @throws IllegalArgumentException + * <p/> + * if destination.get(keyParts(0)) is not a map * + * <p/> + * keyParts is zero length + */ + void putUnderContext(List<String> keyParts, JsonBall toInsert, Map<String, JsonBall> destination) { + checkNotNull(keyParts, "keyParts"); + checkArgument(keyParts.size() >= 1, "keyParts must contain at least one element"); + + checkNotNull(toInsert, "toInsert"); + checkNotNull(destination, "destination"); + + String rootKey = keyParts.remove(0); + String rootValue = destination.containsKey(rootKey) ? destination.get(rootKey).toString() : "{}"; + + checkArgument(rootValue.matches("^\\{.*\\}$"), "value must be a hash: %s", rootValue); + Map<String, JsonBall> immutableInsertionContext = json.fromJson(rootValue, mapLiteral); + Map<String, JsonBall> insertionContext = Maps.newHashMap(immutableInsertionContext); + if (keyParts.size() == 1) { + if (!insertionContext.containsKey(keyParts.get(0))) { + insertionContext.put(keyParts.get(0), toInsert); + } else { + String key = keyParts.get(0); + mergeAsPeer(key, toInsert, insertionContext); + } + } else { + putUnderContext(keyParts, toInsert, insertionContext); + } + destination.put(rootKey, new JsonBall(json.toJson(insertionContext, mapLiteral))); + } + + final Type mapLiteral = new TypeLiteral<Map<String, JsonBall>>() { + }.getType(); + final Type listLiteral = new TypeLiteral<List<JsonBall>>() { + }.getType(); +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/ohai/suppliers/UptimeSecondsSupplier.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/ohai/suppliers/UptimeSecondsSupplier.java b/apis/chef/src/main/java/org/jclouds/ohai/suppliers/UptimeSecondsSupplier.java new file mode 100644 index 0000000..9713902 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/ohai/suppliers/UptimeSecondsSupplier.java @@ -0,0 +1,44 @@ +/* + * 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.jclouds.ohai.suppliers; + +import java.lang.management.RuntimeMXBean; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.domain.JsonBall; + +import com.google.common.base.Supplier; + +@Singleton +public class UptimeSecondsSupplier implements Supplier<JsonBall> { + + @Inject + UptimeSecondsSupplier(RuntimeMXBean runtime) { + this.runtime = runtime; + } + + private final RuntimeMXBean runtime; + + @Override + public JsonBall get() { + long uptimeInSeconds = runtime.getUptime() / 1000; + return new JsonBall(uptimeInSeconds); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/apis/chef/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata new file mode 100644 index 0000000..07e3240 --- /dev/null +++ b/apis/chef/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata @@ -0,0 +1,2 @@ +org.jclouds.chef.test.TransientChefApiMetadata +org.jclouds.chef.ChefApiMetadata \ No newline at end of file http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/test/clojure/org/jclouds/chef_test.clj ---------------------------------------------------------------------- diff --git a/apis/chef/src/test/clojure/org/jclouds/chef_test.clj b/apis/chef/src/test/clojure/org/jclouds/chef_test.clj new file mode 100644 index 0000000..bc542f1 --- /dev/null +++ b/apis/chef/src/test/clojure/org/jclouds/chef_test.clj @@ -0,0 +1,70 @@ +; +; 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. +; + +(ns org.jclouds.chef-test + (:use [org.jclouds.chef] :reload-all) + (:use [clojure.test])) + +(defn clean-stub-fixture + "This should allow basic tests to easily be run with another service." + [service account key & options] + (fn [f] + (with-chef-service [(apply chef-service service account key options)] +(doseq [databag (databags)] + (delete-databag databag)) +(f)))) + +(use-fixtures :each (clean-stub-fixture "transientchef" "" "")) + +(deftest chef-service?-test + (is (chef-service? *chef*))) + +(deftest as-chef-service-test + (is (chef-service? (chef-service "transientchef" "" ""))) + (is (chef-service? (as-chef-service *chef*))) + (is (chef-service? (as-chef-service (chef-context *chef*))))) + +(deftest create-existing-databag-test + (is (not (databag-exists? ""))) + (create-databag "fred") + (is (databag-exists? "fred"))) + +(deftest create-databag-test + (create-databag "fred") + (is (databag-exists? "fred"))) + +(deftest databags-test + (is (empty? (databags))) + (create-databag "fred") + (is (= 1 (count (databags))))) + +(deftest databag-items-test + (create-databag "databag") + (is (empty? (databag-items "databag"))) + (is (create-databag-item "databag" {:id "databag-item1" :value "databag-value1"})) + (is (create-databag-item "databag" {:id "databag-item2" :value "databag-value2"})) + (is (= 2 (count (databag-items "databag"))))) + +(deftest databag-item-test + (create-databag "databag") + (is (create-databag-item "databag" {:id "databag-item1" :value "databag-value1"})) + (is (create-databag-item "databag" {:id "databag-item2" :value "databag-value2"})) + (is (= {:id "databag-item2" :value "databag-value2"} (databag-item "databag" "databag-item2")))) + +(deftest run-list-test + (update-run-list #{"recipe[foo]"} "tag") + (is (= ["recipe[foo]"] (run-list "tag")))) http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/test/java/org/jclouds/chef/BaseChefApiExpectTest.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/test/java/org/jclouds/chef/BaseChefApiExpectTest.java b/apis/chef/src/test/java/org/jclouds/chef/BaseChefApiExpectTest.java new file mode 100644 index 0000000..23013a9 --- /dev/null +++ b/apis/chef/src/test/java/org/jclouds/chef/BaseChefApiExpectTest.java @@ -0,0 +1,44 @@ +/* + * 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.jclouds.chef; + +import org.jclouds.chef.filters.SignedHeaderAuth; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.rest.internal.BaseRestApiExpectTest; + +import com.google.common.base.Functions; +import com.google.common.collect.ImmutableMap; + +/** + * Base class for Chef Api expect tests. + */ +public abstract class BaseChefApiExpectTest<S> extends BaseRestApiExpectTest<S> { + public static final String PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAyb2ZJJqGm0KKR+8nfQJNsSd+F9tXNMV7CfOcW6jsqs8EZgiV\nR09hD1IYOj4YqM0qJONlgyg4xRWewdSG7QTPj1lJpVAida9sXy2+kzyagZA1Am0O\nZcbqb5hoeIDgcX+eDa79s0u0DomjcfO9EKhvHLBz+zM+3QqPRkPV8nYTbfs+HjVz\nzOU6D1B0XR3+IPZZl2AnWs2d0qhnStHcDUvnRVQ0P482YwN9VgceOZtpPz0DCKEJ\n5Tx5STub8k0/zt/VAMHQafLSuQMLd2s4ZLuOZptN//uAsTmxireqd37z+8ZTdBbJ\n8LEpJ+iCXuSfm5aUh7iw6oxvToY2AL53+jK2UQIDAQABAoIBAQDA88B3i/xWn0vX\nBVxFamCYoecuNjGwXXkSyZew616A+EOCu47bh4aTurdFbYL0YFaAtaWvzlaN2eHg\nDb+HDuTefE29+WkcGk6SshPmiz5T0XOCAICWw6wSVDkHmGwS4jZvbAFm7W8nwGk9\nYhxgxFiRngswJZFopOLoF5WXs2td8guIYNslMpo7tu50iFnBHwKO2ZsPAk8t9nnS\nxlDavKruymEmqHCr3+dtio5eaenJcp3fjoXBQOKUk3ipII29XRB8NqeCVV/7Kxwq\nckqOBEbRwBclckyIbD+RiAgKvOelORjEiE9R42vuqvxRA6k9kd9o7utlX0AUtpEn\n3gZc6LepAoGBAP9ael5Y75+sK2JJUNOOhO8ae45cdsilp2yI0X+UBaSuQs2+dyPp\nkpEHAxd4pmmSvn/8c9TlEZhr+qYbABXVPlDncxpIuw2Ajbk7s/S4XaSKsRqpXL57\nzj/QOqLkRk8+OVV9q6lMeQNqLtEj1u6JPviX70Ro+FQtRttNOYbfdP/fAoGBA MpA\nXjR5woV5sUb+REg9vEuYo8RSyOarxqKFCIXVUNsLOx+22+AK4+CQpbueWN7jotrl\nYD6uT6svWi3AAC7kiY0UI/fjVPRCUi8tVoQUE0TaU5VLITaYOB+W/bBaDE4M9560\n1NuDWO90baA5dfU44iuzva02rGJXK9+nS3o8nk/PAoGBALOL6djnDe4mwAaG6Jco\ncd4xr8jkyPzCRZuyBCSBbwphIUXLc7hDprPky064ncJD1UDmwIdkXd/fpMkg2QmA\n/CUk6LEFjMisqHojOaCL9gQZJPhLN5QUN2x1PJWGjs1vQh8Tkx0iUUCOa8bQPXNR\n+34OTsW6TUna4CSZAycLfhffAoGBAIggVsefBCvuQkF0NeUhmDCRZfhnd8y55RHR\n1HCvqKIlpv+rhcX/zmyBLuteopYyRJRsOiE2FW00i8+rIPRu4Z3Q5nybx7w3PzV9\noHN5R5baE9OyI4KpZWztpYYitZF67NcnAvVULHHOvVJQGnKYfLHJYmrJF7GA1ojM\nAuMdFbjFAoGAPxUhxwFy8gaqBahKUEZn4F81HFP5ihGhkT4QL6AFPO2e+JhIGjuR\n27+85hcFqQ+HHVtFsm81b/a+R7P4UuCRgc8eCjxQMoJ1Xl4n7VbjPbHMnIN0Ryvd\nO4ZpWDWYnCO021JTOUUOJ4J/y0416Bvkw0z59y7sNX7wDBBHHbK/XCc=\n-----END RSA PRIVATE KEY-----\n"; + + protected SignedHeaderAuth signedHeaderAuth; + + public BaseChefApiExpectTest() { + credential = PRIVATE_KEY; + signedHeaderAuth = createInjector(Functions.forMap(ImmutableMap.<HttpRequest, HttpResponse> of()), + createModule(), setupProperties()).getInstance(SignedHeaderAuth.class); + } + + protected HttpRequest signed(HttpRequest input) { + return signedHeaderAuth.filter(input); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/test/java/org/jclouds/chef/ChefApiExpectTest.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/test/java/org/jclouds/chef/ChefApiExpectTest.java b/apis/chef/src/test/java/org/jclouds/chef/ChefApiExpectTest.java new file mode 100644 index 0000000..ea4070d --- /dev/null +++ b/apis/chef/src/test/java/org/jclouds/chef/ChefApiExpectTest.java @@ -0,0 +1,279 @@ +/* + * 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.jclouds.chef; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Set; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.chef.config.ChefHttpApiModule; +import org.jclouds.chef.domain.CookbookDefinition; +import org.jclouds.chef.domain.Role; +import org.jclouds.chef.domain.SearchResult; +import org.jclouds.chef.options.SearchOptions; +import org.jclouds.date.TimeStamp; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.rest.ConfiguresRestClient; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; +import com.google.inject.Module; + +/** + * Expect tests for the {@link ChefApi} class. + */ +@Test(groups = "unit", testName = "ChefApiExpectTest") +public class ChefApiExpectTest extends BaseChefApiExpectTest<ChefApi> { + public ChefApiExpectTest() { + provider = "chef"; + } + + private HttpRequest.Builder<?> getHttpRequestBuilder(String method, String endPoint) { + return HttpRequest.builder() // + .method(method) // + .endpoint("http://localhost:4000" + endPoint) // + .addHeader("X-Chef-Version", ChefApiMetadata.DEFAULT_API_VERSION) // + .addHeader("Accept", MediaType.APPLICATION_JSON); + } + + public void testListClientsReturnsValidSet() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/clients").build()), + HttpResponse.builder().statusCode(200) // + .payload(payloadFromResourceWithContentType("/clients_list.json", MediaType.APPLICATION_JSON)) // + .build()); + Set<String> nodes = api.listClients(); + assertEquals(nodes.size(), 3); + assertTrue(nodes.contains("adam"), String.format("Expected nodes to contain 'adam' but was: %s", nodes)); + } + + public void testListClientsReturnsEmptySetOn404() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/clients").build()), + HttpResponse.builder().statusCode(404) + .build()); + Set<String> clients = api.listClients(); + assertTrue(clients.isEmpty(), String.format("Expected clients to be empty but was: %s", clients)); + } + + public void testListNodesReturnsValidSet() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/nodes").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/nodes_list.json", MediaType.APPLICATION_JSON)) // + .build()); + Set<String> nodes = api.listNodes(); + assertEquals(nodes.size(), 3); + assertTrue(nodes.contains("blah"), String.format("Expected nodes to contain 'blah' but was: %s", nodes)); + } + + public void testListNodesReturnsEmptySetOn404() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/nodes").build()), + HttpResponse.builder().statusCode(404).build()); + Set<String> nodes = api.listNodes(); + assertTrue(nodes.isEmpty(), String.format("Expected nodes to be empty but was: %s", nodes)); + } + + public void testListRecipesInEnvironmentReturnsValidSet() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/environments/dev/recipes").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/environment_recipes.json", MediaType.APPLICATION_JSON)) // + .build()); + Set<String> recipes = api.listRecipesInEnvironment("dev"); + assertEquals(recipes.size(), 3); + assertTrue(recipes.contains("apache2"), String.format("Expected recipes to contain 'apache2' but was: %s", recipes)); + } + + public void testListRecipesInEnvironmentReturnsEmptySetOn404() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/environments/dev/recipes").build()), + HttpResponse.builder().statusCode(404).build()); + Set<String> recipes = api.listRecipesInEnvironment("dev"); + assertTrue(recipes.isEmpty(), String.format("Expected recipes to be empty but was: %s", recipes)); + } + + public void testListNodesInEnvironmentReturnsValidSet() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/environments/dev/nodes").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/nodes_list.json", MediaType.APPLICATION_JSON)) // + .build()); + Set<String> nodes = api.listNodesInEnvironment("dev"); + assertEquals(nodes.size(), 3); + assertTrue(nodes.contains("blah"), String.format("Expected nodes to contain 'blah' but was: %s", nodes)); + } + + public void testListNodesInEnvironmentReturnsEmptySetOn404() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/environments/dev/nodes").build()), + HttpResponse.builder().statusCode(404).build()); + Set<String> nodes = api.listNodesInEnvironment("dev"); + assertTrue(nodes.isEmpty(), String.format("Expected nodes to be empty but was: %s", nodes)); + } + + public void testListCookbooksReturnsValidSet() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/cookbooks").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/env_cookbooks.json", MediaType.APPLICATION_JSON)) // + .build()); + Set<String> cookbooks = api.listCookbooks(); + assertEquals(cookbooks.size(), 2); + assertTrue(cookbooks.contains("apache2"), String.format("Expected cookbooks to contain 'apache2' but was: %s", cookbooks)); + } + + public void testListCookbooksReturnsEmptySetOn404() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/cookbooks").build()), + HttpResponse.builder().statusCode(404).build()); + Set<String> cookbooks = api.listCookbooks(); + assertTrue(cookbooks.isEmpty(), String.format("Expected cookbooks to be empty but was: %s", cookbooks)); + } + + public void testListCookbooksInEnvironmentReturnsValidSet() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/environments/dev/cookbooks").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/env_cookbooks.json", MediaType.APPLICATION_JSON)) // + .build()); + Set<CookbookDefinition> cookbooks = api.listCookbooksInEnvironment("dev"); + assertEquals(cookbooks.size(), 2); + } + + public void testListCookbooksInEnvironmentReturnsEmptySetOn404() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/environments/dev/cookbooks").build()), + HttpResponse.builder().statusCode(404).build()); + Set<CookbookDefinition> cookbooks = api.listCookbooksInEnvironment("dev"); + assertTrue(cookbooks.isEmpty(), String.format("Expected cookbooks to be empty but was: %s", cookbooks)); + } + + public void testListCookbooksInEnvironmentWithNumVersionReturnsEmptySetOn404() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/environments/dev/cookbooks").addQueryParam("num_versions", "2").build()), + HttpResponse.builder().statusCode(404).build()); + Set<CookbookDefinition> cookbooks = api.listCookbooksInEnvironment("dev", "2"); + assertTrue(cookbooks.isEmpty(), String.format("Expected cookbooks to be empty but was: %s", cookbooks)); + } + + public void testSearchRolesReturnsValidResult() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/search/role").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/search_role.json", MediaType.APPLICATION_JSON)) // + .build()); + SearchResult<? extends Role> result = api.searchRoles(); + assertEquals(result.size(), 1); + assertEquals(result.iterator().next().getName(), "webserver"); + } + + public void testSearchRolesReturnsEmptyResult() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/search/role").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/search_role_empty.json", MediaType.APPLICATION_JSON)) // + .build()); + SearchResult<? extends Role> result = api.searchRoles(); + assertTrue(result.isEmpty(), String.format("Expected search result to be empty but was: %s", result)); + } + + public void testSearchRolesWithOptionsReturnsValidResult() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/search/role").addQueryParam("q", "name:webserver").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/search_role.json", MediaType.APPLICATION_JSON)) // + .build()); + SearchOptions options = SearchOptions.Builder.query("name:webserver"); + SearchResult<? extends Role> result = api.searchRoles(options); + assertEquals(result.size(), 1); + assertEquals(result.iterator().next().getName(), "webserver"); + } + + public void testSearchRolesWithOptionsReturnsEmptyResult() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/search/role").addQueryParam("q", "name:dummy").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/search_role_empty.json", MediaType.APPLICATION_JSON)) // + .build()); + SearchOptions options = SearchOptions.Builder.query("name:dummy"); + SearchResult<? extends Role> result = api.searchRoles(options); + assertTrue(result.isEmpty(), String.format("Expected search result to be empty but was: %s", result)); + } + + public void testListRolesReturnsValidSet() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/roles").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/roles_list.json", MediaType.APPLICATION_JSON)) // + .build()); + Set<String> roles = api.listRoles(); + assertEquals(roles.size(), 2); + assertTrue(roles.contains("webserver"), String.format("Expected roles to contain 'websever' but was: %s", roles)); + } + + public void testListRolesReturnsEmptySetOn404() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/roles").build()), + HttpResponse.builder().statusCode(404).build()); + Set<String> roles = api.listRoles(); + assertTrue(roles.isEmpty(), String.format("Expected roles to be empty but was: %s", roles)); + } + + public void testListDatabagsReturnsValidSet() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/data").build()), + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/data_list.json", MediaType.APPLICATION_JSON)) // + .build()); + Set<String> databags = api.listDatabags(); + assertEquals(databags.size(), 2); + assertTrue(databags.contains("applications"), String.format("Expected databags to contain 'applications' but was: %s", databags)); + } + + public void testListDatabagsReturnsEmptySetOn404() { + ChefApi api = requestSendsResponse( + signed(getHttpRequestBuilder("GET", "/data").build()), + HttpResponse.builder().statusCode(404).build()); + Set<String> databags = api.listDatabags(); + assertTrue(databags.isEmpty(), String.format("Expected databags to be empty but was: %s", databags)); + } + + @Override + protected Module createModule() { + return new TestChefRestClientModule(); + } + + @ConfiguresRestClient + static class TestChefRestClientModule extends ChefHttpApiModule { + @Override + protected String provideTimeStamp(@TimeStamp Supplier<String> cache) { + return "timestamp"; + } + } + + @Override + protected ChefApiMetadata createApiMetadata() { + return new ChefApiMetadata(); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/test/java/org/jclouds/chef/ChefApiLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/test/java/org/jclouds/chef/ChefApiLiveTest.java b/apis/chef/src/test/java/org/jclouds/chef/ChefApiLiveTest.java new file mode 100644 index 0000000..e4ad583 --- /dev/null +++ b/apis/chef/src/test/java/org/jclouds/chef/ChefApiLiveTest.java @@ -0,0 +1,32 @@ +/* + * 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.jclouds.chef; + +import org.jclouds.chef.internal.BaseChefApiLiveTest; +import org.testng.annotations.Test; + +/** + * Tests behavior of {@code ChefApi} against a Chef Server <= 0.9.8. + */ +@Test(groups = { "live" }) +public class ChefApiLiveTest extends BaseChefApiLiveTest<ChefApi> { + + protected ChefApiLiveTest() { + provider = "chef"; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/test/java/org/jclouds/chef/ChefApiMetadataTest.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/test/java/org/jclouds/chef/ChefApiMetadataTest.java b/apis/chef/src/test/java/org/jclouds/chef/ChefApiMetadataTest.java new file mode 100644 index 0000000..a78c20a --- /dev/null +++ b/apis/chef/src/test/java/org/jclouds/chef/ChefApiMetadataTest.java @@ -0,0 +1,33 @@ +/* + * 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.jclouds.chef; + +import org.jclouds.View; +import org.jclouds.rest.internal.BaseHttpApiMetadataTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; + +@Test(groups = "unit", testName = "ChefApiMetadataTest") +public class ChefApiMetadataTest extends BaseHttpApiMetadataTest { + + // no config management abstraction, yet + public ChefApiMetadataTest() { + super(new ChefApiMetadata(), ImmutableSet.<TypeToken<? extends View>> of()); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/test/java/org/jclouds/chef/ChefApiTest.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/test/java/org/jclouds/chef/ChefApiTest.java b/apis/chef/src/test/java/org/jclouds/chef/ChefApiTest.java new file mode 100644 index 0000000..434c22c --- /dev/null +++ b/apis/chef/src/test/java/org/jclouds/chef/ChefApiTest.java @@ -0,0 +1,741 @@ +/* + * 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.jclouds.chef; + +import static com.google.common.io.BaseEncoding.base16; +import static com.google.common.primitives.Bytes.asList; +import static org.jclouds.reflect.Reflection2.method; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.net.URI; +import java.util.Properties; +import java.util.Set; + +import org.jclouds.Constants; +import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.Fallbacks.VoidOnNotFoundOr404; +import org.jclouds.apis.ApiMetadata; +import org.jclouds.chef.config.ChefHttpApiModule; +import org.jclouds.chef.domain.CookbookVersion; +import org.jclouds.chef.domain.DatabagItem; +import org.jclouds.chef.domain.Node; +import org.jclouds.chef.domain.Resource; +import org.jclouds.chef.domain.Role; +import org.jclouds.chef.filters.SignedHeaderAuth; +import org.jclouds.chef.filters.SignedHeaderAuthTest; +import org.jclouds.chef.functions.ParseCookbookVersionsCheckingChefVersion; +import org.jclouds.chef.functions.ParseKeySetFromJson; +import org.jclouds.chef.functions.ParseSearchClientsFromJson; +import org.jclouds.chef.functions.ParseSearchDatabagFromJson; +import org.jclouds.chef.functions.ParseSearchNodesFromJson; +import org.jclouds.chef.options.CreateClientOptions; +import org.jclouds.chef.options.SearchOptions; +import org.jclouds.date.TimeStamp; +import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.functions.ParseFirstJsonValueNamed; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.http.functions.ReleasePayloadAndReturn; +import org.jclouds.http.functions.ReturnInputStream; +import org.jclouds.io.Payload; +import org.jclouds.io.payloads.StringPayload; +import org.jclouds.reflect.Invocation; +import org.jclouds.rest.ConfiguresRestClient; +import org.jclouds.rest.internal.BaseAsyncApiTest; +import org.jclouds.rest.internal.GeneratedHttpRequest; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.Invokable; +import com.google.inject.Module; + +/** + * Tests annotation parsing of {@code ChefApi}. + */ +@Test(groups = { "unit" }) +public class ChefApiTest extends BaseAsyncApiTest<ChefApi> { + + public void testCommitSandbox() throws SecurityException, NoSuchMethodException, IOException { + + Invokable<?, ?> method = method(ChefApi.class, "commitSandbox", String.class, boolean.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("0189e76ccc476701d6b374e5a1a27347", true))); + assertRequestLineEquals(httpRequest, + "PUT http://localhost:4000/sandboxes/0189e76ccc476701d6b374e5a1a27347 HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"is_completed\":true}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testCreateUploadSandboxForChecksums() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "createUploadSandboxForChecksums", Set.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList + .<Object> of(ImmutableSet.of(asList(base16().lowerCase().decode("0189e76ccc476701d6b374e5a1a27347")), + asList(base16().lowerCase().decode("0c5ecd7788cf4f6c7de2a57193897a6c")), asList(base16().lowerCase() + .decode("1dda05ed139664f1f89b9dec482b77c0")))))); + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/sandboxes HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, + "{\"checksums\":{\"0189e76ccc476701d6b374e5a1a27347\":null,\"0c5ecd7788cf4f6c7de2a57193897a6c\":null," + + "\"1dda05ed139664f1f89b9dec482b77c0\":null}}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + } + + public void testUploadContent() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "uploadContent", URI.class, Payload.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of(URI.create("http://foo/bar"), new StringPayload("{\"foo\": \"bar\"}")))); + assertRequestLineEquals(httpRequest, "PUT http://foo/bar HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"foo\": \"bar\"}", "application/x-binary", false); + + assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testGetCookbook() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "getCookbook", String.class, String.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("cookbook", "1.0.0"))); + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/cookbooks/cookbook/1.0.0 HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, NullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testDeleteCookbook() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "deleteCookbook", String.class, String.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("cookbook", "1.0.0"))); + assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/cookbooks/cookbook/1.0.0 HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, NullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testUpdateCookbook() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "updateCookbook", String.class, String.class, + CookbookVersion.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("cookbook", "1.0.1", CookbookVersion.builder("cookbook", "1.0.1").build()))); + + assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/cookbooks/cookbook/1.0.1 HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, + "{\"name\":\"cookbook-1.0.1\",\"definitions\":[],\"attributes\":[],\"files\":[]," + + "\"metadata\":{\"suggestions\":{},\"dependencies\":{},\"conflicting\":{},\"providing\":{}," + + "\"platforms\":{},\"recipes\":{},\"replacing\":{}," + + "\"groupings\":{},\"attributes\":{},\"recommendations\":{}}," + + "\"providers\":[],\"cookbook_name\":\"cookbook\",\"resources\":[],\"templates\":[]," + + "\"libraries\":[],\"version\":\"1.0.1\"," + + "\"recipes\":[],\"root_files\":[],\"json_class\":\"Chef::CookbookVersion\"," + + "\"chef_type\":\"cookbook_version\"}", "application/json", false); + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testListVersionsOfCookbook() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "listVersionsOfCookbook", String.class); + GeneratedHttpRequest httpRequest = processor + .apply(Invocation.create(method, ImmutableList.<Object> of("apache2"))); + + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/cookbooks/apache2 HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseCookbookVersionsCheckingChefVersion.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testDeleteClient() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "deleteClient", String.class); + GeneratedHttpRequest httpRequest = processor + .apply(Invocation.create(method, ImmutableList.<Object> of("client"))); + assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/clients/client HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, NullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testCreateApi() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "createClient", String.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList.<Object> of("api"))); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/clients HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"name\":\"api\"}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testCreateAdminApi() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "createClient", String.class, CreateClientOptions.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("api", CreateClientOptions.Builder.admin()))); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/clients HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"name\":\"api\",\"admin\":true}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testGenerateKeyForClient() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "generateKeyForClient", String.class); + GeneratedHttpRequest httpRequest = processor + .apply(Invocation.create(method, ImmutableList.<Object> of("client"))); + assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/clients/client HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"name\":\"client\", \"private_key\": true}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testDeleteNode() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "deleteNode", String.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList.<Object> of("node"))); + assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/nodes/node HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, NullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testCreateNode() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "createNode", Node.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create( + method, + ImmutableList.<Object> of(Node.builder().name("testnode").runListElement("recipe[java]") + .environment("_default").build()))); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/nodes HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, + "{\"name\":\"testnode\",\"normal\":{},\"override\":{},\"default\":{},\"automatic\":{}," + + "\"run_list\":[\"recipe[java]\"],\"chef_environment\":\"_default\",\"json_class\":\"Chef::Node\"," + + "\"chef_type\":\"node\"}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testUpdateNode() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "updateNode", Node.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create( + method, + ImmutableList.<Object> of(Node.builder().name("testnode").runListElement("recipe[java]") + .environment("_default").build()))); + + assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/nodes/testnode HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, + "{\"name\":\"testnode\",\"normal\":{},\"override\":{},\"default\":{},\"automatic\":{}," + + "\"run_list\":[\"recipe[java]\"],\"chef_environment\":\"_default\",\"json_class\":\"Chef::Node\"," + + "\"chef_type\":\"node\"}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testDeleteRole() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "deleteRole", String.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList.<Object> of("role"))); + assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/roles/role HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, NullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testCreateRole() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "createRole", Role.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of(Role.builder().name("testrole").runListElement("recipe[java]").build()))); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/roles HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"name\":\"testrole\",\"override_attributes\":{},\"default_attributes\":{}," + + "\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::Role\",\"chef_type\":\"role\"}", + "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testUpdateRole() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "updateRole", Role.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of(Role.builder().name("testrole").runListElement("recipe[java]").build()))); + + assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/roles/testrole HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"name\":\"testrole\",\"override_attributes\":{},\"default_attributes\":{}," + + "\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::Role\",\"chef_type\":\"role\"}", + "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testDeleteDatabag() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "deleteDatabag", String.class); + GeneratedHttpRequest httpRequest = processor + .apply(Invocation.create(method, ImmutableList.<Object> of("databag"))); + assertRequestLineEquals(httpRequest, "DELETE http://localhost:4000/data/databag HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, VoidOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testCreateDatabag() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "createDatabag", String.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList.<Object> of("name"))); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"name\":\"name\"}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testDeleteDatabagItem() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "deleteDatabagItem", String.class, String.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("name", "databagItem"))); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseFirstJsonValueNamed.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, NullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testCreateDatabagItemThrowsIllegalArgumentOnPrimitive() throws SecurityException, NoSuchMethodException, + IOException { + Invokable<?, ?> method = method(ChefApi.class, "createDatabagItem", String.class, DatabagItem.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("name", new DatabagItem("id", "100")))); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data/name HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals( + httpRequest, + "{\"name\":\"testdatabagItem\",\"override_attributes\":{},\"default_attributes\":{}," + + "\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::DatabagItem\",\"chef_type\":\"databagItem\"}", + "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testCreateDatabagItemThrowsIllegalArgumentOnWrongId() throws SecurityException, NoSuchMethodException, + IOException { + Invokable<?, ?> method = method(ChefApi.class, "createDatabagItem", String.class, DatabagItem.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("name", new DatabagItem("id", "{\"id\": \"item1\",\"my_key\": \"my_data\"}")))); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data/name HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals( + httpRequest, + "{\"name\":\"testdatabagItem\",\"override_attributes\":{},\"default_attributes\":{}," + + "\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::DatabagItem\",\"chef_type\":\"databagItem\"}", + "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testCreateDatabagItem() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "createDatabagItem", String.class, DatabagItem.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("name", new DatabagItem("id", "{\"id\": \"id\",\"my_key\": \"my_data\"}")))); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data/name HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"id\": \"id\",\"my_key\": \"my_data\"}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testCreateDatabagItemEvenWhenUserForgotId() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "createDatabagItem", String.class, DatabagItem.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("name", new DatabagItem("id", "{\"my_key\": \"my_data\"}")))); + + assertRequestLineEquals(httpRequest, "POST http://localhost:4000/data/name HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, "{\"id\":\"id\",\"my_key\": \"my_data\"}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testUpdateDatabagItem() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "updateDatabagItem", String.class, DatabagItem.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("name", new DatabagItem("id", "{\"my_key\": \"my_data\"}")))); + + assertRequestLineEquals(httpRequest, "PUT http://localhost:4000/data/name/id HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + + assertPayloadEquals(httpRequest, "{\"id\":\"id\",\"my_key\": \"my_data\"}", "application/json", false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testListDatabagItems() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "listDatabagItems", String.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList.<Object> of("name"))); + + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/data/name HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testListSearchIndexes() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "listSearchIndexes"); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList.of())); + + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseKeySetFromJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + + public void testSearchClients() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "searchClients"); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList.of())); + + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/client HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseSearchClientsFromJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, MapHttp4xxCodesToExceptions.class); + + checkFilters(httpRequest); + + } + + public void testSearchClientsWithOptions() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "searchClients", SearchOptions.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of(SearchOptions.Builder.query("text").rows(5)))); + + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/client?q=text&rows=5 HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseSearchClientsFromJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, MapHttp4xxCodesToExceptions.class); + + checkFilters(httpRequest); + + } + + public void testSearchNodes() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "searchNodes"); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList.of())); + + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/node HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseSearchNodesFromJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, MapHttp4xxCodesToExceptions.class); + + checkFilters(httpRequest); + + } + + public void testSearchNodesWithOptions() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "searchNodes", SearchOptions.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of(SearchOptions.Builder.query("foo:foo").start(3)))); + + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/node?q=foo%3Afoo&start=3 HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseSearchNodesFromJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, MapHttp4xxCodesToExceptions.class); + + checkFilters(httpRequest); + + } + + public void testSearchDatabagItems() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "searchDatabagItems", String.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, ImmutableList.<Object> of("foo"))); + + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/foo HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseSearchDatabagFromJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, MapHttp4xxCodesToExceptions.class); + + checkFilters(httpRequest); + + } + + public void testSearchDatabagItemsWithOptions() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "searchDatabagItems", String.class, SearchOptions.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of("foo", SearchOptions.Builder.query("bar").sort("name DESC")))); + + assertRequestLineEquals(httpRequest, "GET http://localhost:4000/search/foo?q=bar&sort=name%20DESC HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseSearchDatabagFromJson.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, MapHttp4xxCodesToExceptions.class); + + checkFilters(httpRequest); + + } + + public void testGetResourceContents() throws SecurityException, NoSuchMethodException, IOException { + Invokable<?, ?> method = method(ChefApi.class, "getResourceContents", Resource.class); + GeneratedHttpRequest httpRequest = processor.apply(Invocation.create(method, + ImmutableList.<Object> of(Resource.builder().name("test").url(URI.create("http://foo/bar")).build()))); + + assertRequestLineEquals(httpRequest, "GET http://foo/bar HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION + + "-test\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ReturnInputStream.class); + assertSaxResponseParserClassEquals(method, null); + assertFallbackClassEquals(method, NullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + @Override + protected void checkFilters(HttpRequest request) { + assertEquals(request.getFilters().size(), 1); + assertEquals(request.getFilters().get(0).getClass(), SignedHeaderAuth.class); + } + + @Override + protected Module createModule() { + return new TestChefRestClientModule(); + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + props.put(Constants.PROPERTY_API_VERSION, ChefApiMetadata.DEFAULT_API_VERSION + "-test"); + return props; + } + + @ConfiguresRestClient + static class TestChefRestClientModule extends ChefHttpApiModule { + @Override + protected String provideTimeStamp(@TimeStamp Supplier<String> cache) { + return "timestamp"; + } + } + + @Override + public ApiMetadata createApiMetadata() { + identity = "user"; + credential = SignedHeaderAuthTest.PRIVATE_KEY; + return new ChefApiMetadata(); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/test/java/org/jclouds/chef/binders/BindHexEncodedMD5sToJsonPayloadTest.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/test/java/org/jclouds/chef/binders/BindHexEncodedMD5sToJsonPayloadTest.java b/apis/chef/src/test/java/org/jclouds/chef/binders/BindHexEncodedMD5sToJsonPayloadTest.java new file mode 100644 index 0000000..7648732 --- /dev/null +++ b/apis/chef/src/test/java/org/jclouds/chef/binders/BindHexEncodedMD5sToJsonPayloadTest.java @@ -0,0 +1,70 @@ +/* + * 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.jclouds.chef.binders; + +import static com.google.common.io.BaseEncoding.base16; +import static com.google.common.primitives.Bytes.asList; +import static org.testng.Assert.assertEquals; + +import java.io.File; + +import javax.ws.rs.HttpMethod; + +import org.jclouds.chef.ChefApiMetadata; +import org.jclouds.chef.config.ChefParserModule; +import org.jclouds.http.HttpRequest; +import org.jclouds.json.config.GsonModule; +import org.jclouds.rest.annotations.ApiVersion; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; + +@Test(groups = { "unit" }) +public class BindHexEncodedMD5sToJsonPayloadTest { + + Injector injector = Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + bind(String.class).annotatedWith(ApiVersion.class).toInstance(ChefApiMetadata.DEFAULT_API_VERSION); + } + }, new ChefParserModule(), new GsonModule()); + + BindChecksumsToJsonPayload binder = injector.getInstance(BindChecksumsToJsonPayload.class); + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testMustBeIterable() { + HttpRequest request = HttpRequest.builder().method(HttpMethod.POST).endpoint("http://localhost").build(); + binder.bindToRequest(request, new File("foo")); + } + + public void testCorrect() { + HttpRequest request = HttpRequest.builder().method(HttpMethod.POST).endpoint("http://localhost").build(); + binder.bindToRequest(request, + ImmutableSet.of(asList(base16().lowerCase().decode("abddef")), asList(base16().lowerCase().decode("1234")))); + assertEquals(request.getPayload().getRawContent(), "{\"checksums\":{\"abddef\":null,\"1234\":null}}"); + } + + @Test(expectedExceptions = { NullPointerException.class, IllegalStateException.class }) + public void testNullIsBad() { + HttpRequest request = HttpRequest.builder().method(HttpMethod.POST).endpoint("http://localhost").build(); + binder.bindToRequest(request, null); + } + +}
