Skip to content

Commit

Permalink
Merge pull request #200 from admd/original-exception-info
Browse files Browse the repository at this point in the history
Better error handling in Runner and Wheel calls
  • Loading branch information
mateiw authored May 23, 2017
2 parents 3b8bb51 + d19a64a commit 11911bf
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 36 deletions.
23 changes: 11 additions & 12 deletions src/main/java/com/suse/salt/netapi/calls/RunnerCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import com.suse.salt.netapi.AuthModule;
import com.suse.salt.netapi.client.SaltClient;
import com.suse.salt.netapi.exception.SaltException;
import com.suse.salt.netapi.results.Result;
import com.suse.salt.netapi.results.Return;

import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
Expand Down Expand Up @@ -109,21 +109,20 @@ public RunnerAsyncResult<R> callAsync(final SaltClient client, String username,
* @return the result of the called function
* @throws SaltException if anything goes wrong
*/
public R callSync(final SaltClient client, String username, String password,
public Result<R> callSync(final SaltClient client, String username, String password,
AuthModule authModule) throws SaltException {
Map<String, Object> customArgs = new HashMap<>();
customArgs.putAll(getPayload());
customArgs.put("username", username);
customArgs.put("password", password);
customArgs.put("eauth", authModule.getValue());

Type listType = parameterizedType(null, List.class, getReturnType().getType());
Type xor = parameterizedType(null, Result.class, getReturnType().getType());
Type listType = parameterizedType(null, List.class, xor);
Type wrapperType = parameterizedType(null, Return.class, listType);

@SuppressWarnings("unchecked")
Return<List<R>> wrapper = client.call(
Return<List<Result<R>>> wrapper = client.call(
this, Client.RUNNER, "/run", Optional.of(customArgs),
(TypeToken<Return<List<R>>>) TypeToken.get(wrapperType));
(TypeToken<Return<List<Result<R>>>>) TypeToken.get(wrapperType));
return wrapper.getResult().get(0);
}

Expand All @@ -136,13 +135,13 @@ public R callSync(final SaltClient client, String username, String password,
* @return the result of the called function
* @throws SaltException if anything goes wrong
*/
public R callSync(final SaltClient client) throws SaltException {
Type listType = parameterizedType(null, List.class, getReturnType().getType());
public Result<R> callSync(final SaltClient client) throws SaltException {
Type xor = parameterizedType(null, Result.class, getReturnType().getType());
Type listType = parameterizedType(null, List.class, xor);
Type wrapperType = parameterizedType(null, Return.class, listType);

@SuppressWarnings("unchecked")
Return<List<R>> wrapper = client.call(this, Client.RUNNER, "/",
(TypeToken<Return<List<R>>>) TypeToken.get(wrapperType));
Return<List<Result<R>>> wrapper = client.call(this, Client.RUNNER, "/",
(TypeToken<Return<List<Result<R>>>>) TypeToken.get(wrapperType));
return wrapper.getResult().get(0);
}

Expand Down
26 changes: 14 additions & 12 deletions src/main/java/com/suse/salt/netapi/calls/WheelCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import com.suse.salt.netapi.AuthModule;
import com.suse.salt.netapi.client.SaltClient;
import com.suse.salt.netapi.exception.SaltException;
import com.suse.salt.netapi.results.Result;
import com.suse.salt.netapi.results.Return;

import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
Expand Down Expand Up @@ -106,16 +106,17 @@ public WheelAsyncResult<R> callAsync(final SaltClient client, String username,
* @return the result of the called function
* @throws SaltException if anything goes wrong
*/
public WheelResult<R> callSync(final SaltClient client)
public WheelResult<Result<R>> callSync(final SaltClient client)
throws SaltException {
Type wheelResult = parameterizedType(null, WheelResult.class,
getReturnType().getType());
Type xor = parameterizedType(null, Result.class, getReturnType().getType());
Type wheelResult = parameterizedType(null, WheelResult.class, xor);
Type listType = parameterizedType(null, List.class, wheelResult);
Type wrapperType = parameterizedType(null, Return.class, listType);

@SuppressWarnings("unchecked")
Return<List<WheelResult<R>>> wrapper = client.call(this, Client.WHEEL, "/",
(TypeToken<Return<List<WheelResult<R>>>>) TypeToken.get(wrapperType));
Return<List<WheelResult<Result<R>>>> wrapper = client.call(this, Client.WHEEL, "/",
(TypeToken<Return<List<WheelResult<Result<R>>>>>)
TypeToken.get(wrapperType));
return wrapper.getResult().get(0);
}

Expand All @@ -131,7 +132,7 @@ public WheelResult<R> callSync(final SaltClient client)
* @return the result of the called function
* @throws SaltException if anything goes wrong
*/
public WheelResult<R> callSync(final SaltClient client,
public WheelResult<Result<R>> callSync(final SaltClient client,
String username, String password,
AuthModule authModule) throws SaltException {
Map<String, Object> customArgs = new HashMap<>();
Expand All @@ -140,15 +141,16 @@ public WheelResult<R> callSync(final SaltClient client,
customArgs.put("password", password);
customArgs.put("eauth", authModule.getValue());

Type wheelResult = parameterizedType(null, WheelResult.class,
getReturnType().getType());
Type xor = parameterizedType(null, Result.class, getReturnType().getType());
Type wheelResult = parameterizedType(null, WheelResult.class, xor);
Type listType = parameterizedType(null, List.class, wheelResult);
Type wrapperType = parameterizedType(null, Return.class, listType);

@SuppressWarnings("unchecked")
Return<List<WheelResult<R>>> wrapper = client.call(this, Client.WHEEL, "/run",
Optional.of(customArgs),
(TypeToken<Return<List<WheelResult<R>>>>) TypeToken.get(wrapperType));
Return<List<WheelResult<Result<R>>>> wrapper = client.call(this, Client.WHEEL,
"/run", Optional.of(customArgs),
(TypeToken<Return<List<WheelResult<Result<R>>>>>)
TypeToken.get(wrapperType));
return wrapper.getResult().get(0);
}
}
101 changes: 101 additions & 0 deletions src/test/java/com/suse/salt/netapi/calls/runner/JobsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.suse.salt.netapi.calls.runner;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.any;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Optional;

import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.suse.salt.netapi.calls.modules.SaltUtilTest;
import com.suse.salt.netapi.client.SaltClient;
import com.suse.salt.netapi.exception.SaltException;
import com.suse.salt.netapi.results.Result;
import com.suse.salt.netapi.utils.ClientUtils;

/**
* Tests for the runner Jobs module.
*/
public class JobsTest {

private static final int MOCK_HTTP_PORT = 8888;

static final String JSON_LIST_JOB_RESPONSE = ClientUtils.streamToString(
SaltUtilTest.class.getResourceAsStream("/runner/list_job_response.json"));
static final String JSON_LIST_JOB_UNPARSABLE_DATE_RESPONSE = ClientUtils.streamToString(
SaltUtilTest.class.
getResourceAsStream("/runner/list_job_unparseable_date_response.json"));
static final String JSON_SALT_EXCEPTION_RESPONSE = ClientUtils.streamToString(
SaltUtilTest.class.getResourceAsStream("/runner/salt_exception_response.json"));

@Rule
public WireMockRule wireMockRule = new WireMockRule(MOCK_HTTP_PORT);

private SaltClient client;

@Before
public void init() {
URI uri = URI.create("http://localhost:" + Integer.toString(MOCK_HTTP_PORT));
client = new SaltClient(uri);
}

@Test
public void testListJob() throws SaltException {
stubFor(any(urlMatching("/"))
.willReturn(aResponse()
.withStatus(HttpURLConnection.HTTP_OK)
.withHeader("Content-Type", "application/json")
.withBody(JSON_LIST_JOB_RESPONSE)));

Result<Jobs.Info> result = Jobs.listJob("111").callSync(client);

assertTrue(result.result().isPresent());
assertEquals(Optional.empty(), result.error());

}

@Test
public void testListJobInvalidResponse() throws SaltException {
stubFor(any(urlMatching("/"))
.willReturn(aResponse()
.withStatus(HttpURLConnection.HTTP_OK)
.withHeader("Content-Type", "application/json")
.withBody(JSON_LIST_JOB_UNPARSABLE_DATE_RESPONSE)));

Result<Jobs.Info> result = Jobs.listJob("111").callSync(client);

assertEquals(Optional.empty(), result.result());
assertTrue(result.error().isPresent());
assertThat(result.error().get().toString(),
CoreMatchers.containsString("java.text.ParseException:"));
}

@Test
public void testResponseWithException() throws SaltException {
stubFor(any(urlMatching("/"))
.willReturn(aResponse()
.withStatus(HttpURLConnection.HTTP_OK)
.withHeader("Content-Type", "application/json")
.withBody(JSON_SALT_EXCEPTION_RESPONSE)));

Result<Jobs.Info> result = Jobs.listJob("111").callSync(client);

assertEquals(Optional.empty(), result.result());
assertTrue(result.error().isPresent());
assertThat(result.error().get().toString(),
CoreMatchers.containsString("unexpected keyword argument"
+ " 'kwargs'"));

}
}
22 changes: 15 additions & 7 deletions src/test/java/com/suse/salt/netapi/calls/wheel/KeyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import com.suse.salt.netapi.calls.modules.SaltUtilTest;
import com.suse.salt.netapi.client.SaltClient;
import com.suse.salt.netapi.exception.SaltException;
import com.suse.salt.netapi.results.Result;
import com.suse.salt.netapi.utils.ClientUtils;

import com.github.tomakehurst.wiremock.junit.WireMockRule;

import org.junit.Before;
Expand Down Expand Up @@ -59,9 +59,13 @@ public void testGen() throws SaltException {
.withHeader("Content-Type", "application/json")
.withBody(JSON_KEY_GEN_RESPONSE)));

WheelResult<Key.Pair> keyPair = Key.gen("minion1").callSync(client);
assertTrue(keyPair.getData().getResult().getPub().isPresent());
assertTrue(keyPair.getData().getResult().getPriv().isPresent());
WheelResult<Result<Key.Pair>> keyPair = Key.gen("minion1").callSync(client);

Result<Key.Pair> resultData = keyPair.getData().getResult();
Key.Pair data = resultData.result().get();

assertTrue(data.getPub().isPresent());
assertTrue(data.getPriv().isPresent());

verify(1, postRequestedFor(urlEqualTo("/"))
.withHeader("Accept", equalTo("application/json"))
Expand All @@ -78,10 +82,14 @@ public void testGenAccept() throws SaltException {
.withHeader("Content-Type", "application/json")
.withBody(JSON_KEY_GEN_ACCEPT_RESPONSE)));

WheelResult<Key.Pair> keyPair = Key.genAccept(
WheelResult<Result<Key.Pair>> keyPair = Key.genAccept(
"minion1", Optional.empty()).callSync(client);
assertTrue(keyPair.getData().getResult().getPub().isPresent());
assertTrue(keyPair.getData().getResult().getPriv().isPresent());

Result<Key.Pair> resultData = keyPair.getData().getResult();
Key.Pair data = resultData.result().get();

assertTrue(data.getPub().isPresent());
assertTrue(data.getPriv().isPresent());

verify(1, postRequestedFor(urlEqualTo("/"))
.withHeader("Accept", equalTo("application/json"))
Expand Down
14 changes: 9 additions & 5 deletions src/test/java/com/suse/salt/netapi/examples/Wheel.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.suse.salt.netapi.calls.wheel.Key;
import com.suse.salt.netapi.client.SaltClient;
import com.suse.salt.netapi.exception.SaltException;
import com.suse.salt.netapi.results.Result;

import java.net.URI;
import java.util.Optional;
Expand All @@ -23,19 +24,22 @@ public static void main(String[] args) throws SaltException {
SaltClient client = new SaltClient(URI.create(SALT_API_URL));

// List accepted and pending minion keys
WheelResult<Key.Names> keyResults = Key.listAll().callSync(
WheelResult<Result<Key.Names>> keyResults = Key.listAll().callSync(
client, USER, PASSWORD, AuthModule.AUTO);
Key.Names keys = keyResults.getData().getResult();
Result<Key.Names> resultKeys = keyResults.getData().getResult();
Key.Names keys = resultKeys.result().get();

System.out.println("\n--> Accepted minion keys:\n");
keys.getMinions().forEach(System.out::println);
System.out.println("\n--> Pending minion keys:\n");
keys.getUnacceptedMinions().forEach(System.out::println);

// Generate a new key pair and accept the public key
WheelResult<Key.Pair> genResults = Key.genAccept("new.minion.id", Optional.empty())
.callSync(client, USER, PASSWORD, AuthModule.AUTO);
Key.Pair keyPair = genResults.getData().getResult();
WheelResult<Result<Key.Pair>> genResults = Key.genAccept("new.minion.id",
Optional.empty()).callSync(client,
USER, PASSWORD, AuthModule.AUTO);
Result<Key.Pair> resultKeyPair = genResults.getData().getResult();
Key.Pair keyPair = resultKeyPair.result().get();

System.out.println("\n--> New key pair:");
System.out.println("\nPUB:\n\n" + keyPair.getPub());
Expand Down
12 changes: 12 additions & 0 deletions src/test/resources/runner/list_job_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"return": [{
"Function": "unknown-function",
"jid": "111",
"Target": "unknown-target",
"Target-type": "",
"User": "root",
"Result": {},
"StartTime": "2017, May 07 17:55:55.169861",
"Arguments": []
}]
}
12 changes: 12 additions & 0 deletions src/test/resources/runner/list_job_unparseable_date_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"return": [{
"Function": "unknown-function",
"jid": "111",
"Target": "unknown-target",
"Target-type": "",
"User": "root",
"Result": {},
"StartTime": "2017",
"Arguments": []
}]
}
3 changes: 3 additions & 0 deletions src/test/resources/runner/salt_exception_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"return": ["Exception occurred in runner jobs.list_job: Traceback (most recent call last):\n File \"/usr/lib/python2.7/dist-packages/salt/client/mixins.py\", line 395, in _low\n data['return'] = self.functions[fun](*args, **kwargs)\nTypeError: list_job() got an unexpected keyword argument 'kwargs'\n"]
}

0 comments on commit 11911bf

Please sign in to comment.