diff --git a/CHANGELOG.md b/CHANGELOG.md index c7b62acbc..a00c41d2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Development] +### Changed +- Updated `VerifyClient` to use the JSON endpoints instead of XML. +- Updated endpoints which are used by `VerifyClient` from public to package scope in order to encourage usage through `VerifyClient`. +- Deprecated XML version of the following endpoints: + - `VerifyEndpoint` + - `CheckEndpoint` + - `SearchEndpoint` + +- Deprecated the following XML results: + - `VerifyResult` should use `VerifyResponse` + - `CheckResult` should use `CheckResponse` + - `SearchResult` should use `SearchVerifyResponse` + +- Deprecated the following XML methods: + - `VerifyCheckMethod` + +### Added +- Added `VerifyStatus` enumeration to use for statuses coming back from the verify endpoint. +- Added `VerifyResponse`, `CheckResponse`, and `SearchVerifyResponse` for JSON responses to match other JSON using endpoints. +- Added `VerifyMethod`, `CheckMethod`, and `SearchMethod` for better segregation between endpoint and method classes. ### Fixed - Updated `ConversationNcco`'s `musicOnHoldUrl` to serialize into an array for use in the Voice API. diff --git a/src/main/java/com/nexmo/client/verify/CheckEndpoint.java b/src/main/java/com/nexmo/client/verify/CheckEndpoint.java new file mode 100644 index 000000000..9c3d48254 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/CheckEndpoint.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011-2017 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.nexmo.client.HttpWrapper; +import com.nexmo.client.NexmoClientException; + +import java.io.IOException; + +class CheckEndpoint { + private CheckMethod checkMethod; + + CheckEndpoint(HttpWrapper httpWrapper) { + this.checkMethod = new CheckMethod(httpWrapper); + } + + CheckResult check(final String requestId, + final String code, + final String ipAddress) throws IOException, NexmoClientException { + return check(new CheckRequest(requestId, code, ipAddress)); + } + + CheckResult check(final String requestId, final String code) throws IOException, NexmoClientException { + return check(new CheckRequest(requestId, code)); + } + + private CheckResult check(CheckRequest request) throws IOException, NexmoClientException { + // TODO: Remove translation when releasing 4.0 + return translateFromCheckResponse(this.checkMethod.execute(request)); + } + + private CheckResult translateFromCheckResponse(CheckResponse response) { + return new CheckResult( + // TODO: In 4.0 this will be permitted to be null. + response.getStatus() != null ? response.getStatus().getVerifyStatus() : Integer.MAX_VALUE, + response.getRequestId(), + response.getEventId(), + response.getPrice() != null ? response.getPrice().floatValue() : 0, + response.getCurrency(), + response.getErrorText(), + response.getStatus() != null && response.getStatus().isTemporaryError()); + } +} diff --git a/src/main/java/com/nexmo/client/verify/CheckMethod.java b/src/main/java/com/nexmo/client/verify/CheckMethod.java new file mode 100644 index 000000000..005e92e14 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/CheckMethod.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.nexmo.client.HttpWrapper; +import com.nexmo.client.NexmoClientException; +import com.nexmo.client.auth.SignatureAuthMethod; +import com.nexmo.client.auth.TokenAuthMethod; +import com.nexmo.client.voice.endpoints.AbstractMethod; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.impl.client.BasicResponseHandler; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +public class CheckMethod extends AbstractMethod { + private static final Class[] ALLOWED_AUTH_METHODS = new Class[]{SignatureAuthMethod.class, TokenAuthMethod.class}; + + private static final String DEFAULT_URI = "https://api.nexmo.com/verify/check/json"; + + private String uri = DEFAULT_URI; + + CheckMethod(HttpWrapper httpWrapper) { + super(httpWrapper); + } + + @Override + protected Class[] getAcceptableAuthMethods() { + return ALLOWED_AUTH_METHODS; + } + + @Override + public RequestBuilder makeRequest(CheckRequest request) throws NexmoClientException, UnsupportedEncodingException { + if (request.getRequestId() == null || request.getCode() == null) + throw new IllegalArgumentException("request ID and code parameters are mandatory."); + + RequestBuilder result = RequestBuilder.post(this.uri).addParameter("request_id", request.getRequestId()) + + .addParameter("code", request.getCode()); + if (request.getIpAddress() != null) result.addParameter("ip_address", request.getIpAddress()); + + return result; + } + + @Override + public CheckResponse parseResponse(HttpResponse response) throws IOException { + return CheckResponse.fromJson(new BasicResponseHandler().handleResponse(response)); + } +} diff --git a/src/main/java/com/nexmo/client/verify/CheckResponse.java b/src/main/java/com/nexmo/client/verify/CheckResponse.java new file mode 100644 index 000000000..a19c34c55 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/CheckResponse.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nexmo.client.NexmoResponseParseException; +import com.nexmo.client.NexmoUnexpectedException; + +import java.io.IOException; +import java.math.BigDecimal; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CheckResponse { + private String requestId; + private String eventId; + private VerifyStatus status; + private BigDecimal price; + private String currency; + private String errorText; + + @JsonCreator + public CheckResponse(@JsonProperty(value = "status", required = true) VerifyStatus status) { + this.status = status; + } + + @JsonProperty("request_id") + public String getRequestId() { + return this.requestId; + } + + @JsonProperty("event_id") + public String getEventId() { + return this.eventId; + } + + public VerifyStatus getStatus() { + return this.status; + } + + public BigDecimal getPrice() { + return this.price; + } + + public String getCurrency() { + return this.currency; + } + + @JsonProperty("error_text") + public String getErrorText() { + return this.errorText; + } + + public static CheckResponse fromJson(String json) { + try { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(json, CheckResponse.class); + } catch (JsonMappingException jme) { + throw new NexmoResponseParseException("Failed to produce CheckResponse from json.", jme); + } catch (IOException jpe) { + throw new NexmoUnexpectedException("Failed to produce CheckResponse from json.", jpe); + } + } +} diff --git a/src/main/java/com/nexmo/client/verify/CheckResult.java b/src/main/java/com/nexmo/client/verify/CheckResult.java index edfc14257..ee627c34a 100644 --- a/src/main/java/com/nexmo/client/verify/CheckResult.java +++ b/src/main/java/com/nexmo/client/verify/CheckResult.java @@ -21,29 +21,42 @@ */ package com.nexmo.client.verify; - /** - * Verification check result. - * - * @author Daniele Ricci + * @deprecated Relies on XML Endpoint, use {@link CheckResponse} */ +@Deprecated public class CheckResult extends BaseResult { - private final String eventId; - private final float price; - private final String currency; - - public CheckResult(final int status, - final String eventId, - final float price, - final String currency, - final String errorText, - final boolean temporaryError) { + private String requestId; + private String eventId; + private float price; + private String currency; + + public CheckResult(int status, + String eventId, + float price, + String currency, + String errorText, + boolean temporaryError) { super(status, errorText, temporaryError); this.eventId = eventId; this.price = price; this.currency = currency; } + public CheckResult(int status, + String requestId, + String eventId, + float price, + String currency, + String errorText, + boolean temporaryError) { + super(status, errorText, temporaryError); + this.requestId = requestId; + this.eventId = eventId; + this.price = price; + this.currency = currency; + } + public String getEventId() { return this.eventId; } @@ -56,4 +69,8 @@ public String getCurrency() { return this.currency; } + public String getRequestId() { + return this.requestId; + } + } diff --git a/src/main/java/com/nexmo/client/verify/SearchEndpoint.java b/src/main/java/com/nexmo/client/verify/SearchEndpoint.java new file mode 100644 index 000000000..6e9cc5423 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/SearchEndpoint.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.nexmo.client.HttpWrapper; +import com.nexmo.client.NexmoClientException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class SearchEndpoint { + private SearchMethod searchMethod; + + SearchEndpoint(HttpWrapper httpWrapper) { + this.searchMethod = new SearchMethod(httpWrapper); + } + + SearchResult[] search(String... requestIds) throws IOException, NexmoClientException { + return translateFromSearchVerifyResponse(this.searchMethod.execute(new SearchRequest(requestIds))); + } + + private SearchResult[] translateFromSearchVerifyResponse(SearchVerifyResponse response) { + // TODO: Remove in 4.0 + List resultList = new ArrayList<>(); + + if (response.getStatus() != VerifyStatus.OK) { + resultList.add(new SearchResult(response.getStatus().getVerifyStatus(), + response.getErrorText(), + response.getStatus().isTemporaryError())); + } else { + for (VerifyDetails details : response.getVerificationRequests()) { + resultList.add(new SearchResult(response.getStatus().getVerifyStatus(), + details.getRequestId(), + details.getAccountId(), + translateFromVerifyDetailsStatus(details.getStatus()), + details.getNumber(), + details.getPrice() != null ? details.getPrice().floatValue() : 0, + details.getCurrency(), + details.getSenderId(), + details.getDateSubmitted(), + details.getDateFinalized(), + details.getFirstEventDate(), + details.getLastEventDate(), + translateFromVerifyCheck(details.getChecks()), + response.getErrorText(), + false)); + } + } + + return resultList.toArray(new SearchResult[0]); + } + + private SearchResult.VerificationStatus translateFromVerifyDetailsStatus(VerifyDetails.Status status) { + // TODO: Remove in 4.0 + // This operates in the same way the XML endpoint does without logging the error. + try { + return status != null ? SearchResult.VerificationStatus.valueOf(status.name()) : null; + } catch (IllegalArgumentException e) { + return null; + } + } + + private List translateFromVerifyCheck(List checks) { + // TODO: Remove in 4.0 + List resultChecks = new ArrayList<>(); + + for (VerifyCheck check : checks) { + resultChecks.add(new SearchResult.VerifyCheck(check.getDate(), + check.getCode(), + SearchResult.VerifyCheck.Status.valueOf(check.getStatus().name()), + check.getIpAddress())); + } + + return resultChecks; + } +} diff --git a/src/main/java/com/nexmo/client/verify/SearchMethod.java b/src/main/java/com/nexmo/client/verify/SearchMethod.java new file mode 100644 index 000000000..16bcb2f65 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/SearchMethod.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.nexmo.client.HttpWrapper; +import com.nexmo.client.NexmoClientException; +import com.nexmo.client.auth.SignatureAuthMethod; +import com.nexmo.client.auth.TokenAuthMethod; +import com.nexmo.client.voice.endpoints.AbstractMethod; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.impl.client.BasicResponseHandler; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +public class SearchMethod extends AbstractMethod { + private static final Class[] ALLOWED_AUTH_METHODS = new Class[]{SignatureAuthMethod.class, TokenAuthMethod.class}; + + private static final String DEFAULT_URI = "https://api.nexmo.com/verify/search/json"; + + private String uri = DEFAULT_URI; + + SearchMethod(HttpWrapper httpWrapper) { + super(httpWrapper); + } + + @Override + protected Class[] getAcceptableAuthMethods() { + return ALLOWED_AUTH_METHODS; + } + + @Override + public RequestBuilder makeRequest(SearchRequest request) throws NexmoClientException, UnsupportedEncodingException { + RequestBuilder result = RequestBuilder.post(this.uri); + if (request.getRequestIds().length == 1) { + result.addParameter("request_id", request.getRequestIds()[0]); + } else { + for (String requestId : request.getRequestIds()) + result.addParameter("request_ids", requestId); + } + return result; + } + + @Override + public SearchVerifyResponse parseResponse(HttpResponse response) throws IOException { + return SearchVerifyResponse.fromJson(new BasicResponseHandler().handleResponse(response)); + } +} \ No newline at end of file diff --git a/src/main/java/com/nexmo/client/verify/SearchResult.java b/src/main/java/com/nexmo/client/verify/SearchResult.java index 12a28cd9a..831002e7c 100644 --- a/src/main/java/com/nexmo/client/verify/SearchResult.java +++ b/src/main/java/com/nexmo/client/verify/SearchResult.java @@ -26,23 +26,22 @@ import java.util.List; /** - * Verification search result. - * - * @author Daniele Ricci + * @deprecated Relies on XML Endpoint, use {@link SearchVerifyResponse} */ +@Deprecated public class SearchResult extends BaseResult { - private final String requestId; - private final String accountId; - private final VerificationStatus verificationStatus; - private final String number; - private final float price; - private final String currency; - private final String senderId; - private final Date dateSubmitted; - private final Date dateFinalized; - private final Date firstEventDate; - private final Date lastEventDate; - private final List checks; + private String requestId; + private String accountId; + private VerificationStatus verificationStatus; + private String number; + private float price; + private String currency; + private String senderId; + private Date dateSubmitted; + private Date dateFinalized; + private Date firstEventDate; + private Date lastEventDate; + private List checks; /** Used to define a verify check attempt. */ public static class VerifyCheck implements java.io.Serializable { @@ -150,6 +149,10 @@ public SearchResult(final int status, this.checks = checks; } + SearchResult(int status, String errorText, boolean temporaryError) { + super(status, errorText, temporaryError); + } + public String getRequestId() { return this.requestId; } diff --git a/src/main/java/com/nexmo/client/verify/SearchVerifyResponse.java b/src/main/java/com/nexmo/client/verify/SearchVerifyResponse.java new file mode 100644 index 000000000..b53d4bd69 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/SearchVerifyResponse.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.nexmo.client.NexmoResponseParseException; +import com.nexmo.client.NexmoUnexpectedException; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class SearchVerifyResponse { + private VerifyStatus status; + private List verificationRequests = new ArrayList<>(); + private String errorText; + + @JsonCreator + SearchVerifyResponse() { + this.status = VerifyStatus.OK; + } + + SearchVerifyResponse(List verificationRequests) { + this.status = VerifyStatus.OK; + this.verificationRequests = verificationRequests; + } + + SearchVerifyResponse(VerifyStatus status, String errorText) { + this.status = status; + this.errorText = errorText; + } + + public VerifyStatus getStatus() { + return this.status; + } + + @JsonProperty("verification_requests") + public List getVerificationRequests() { + return this.verificationRequests; + } + + @JsonProperty("error_text") + public String getErrorText() { + return this.errorText; + } + + public static SearchVerifyResponse fromJson(String json) { + try { + ObjectMapper mapper = new ObjectMapper(); + mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + SimpleModule module = new SimpleModule(); + module.addDeserializer(SearchVerifyResponse.class, new SearchVerifyResponseDeserializer()); + mapper.registerModule(module); + + return mapper.readValue(json, SearchVerifyResponse.class); + } catch (JsonMappingException jme) { + throw new NexmoResponseParseException("Failed to produce SearchVerifyResponse from json.", jme); + } catch (IOException jpe) { + throw new NexmoUnexpectedException("Failed to produce SearchVerifyResponse from json.", jpe); + } + } +} diff --git a/src/main/java/com/nexmo/client/verify/SearchVerifyResponseDeserializer.java b/src/main/java/com/nexmo/client/verify/SearchVerifyResponseDeserializer.java new file mode 100644 index 000000000..f75de6799 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/SearchVerifyResponseDeserializer.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Collections; + +public class SearchVerifyResponseDeserializer extends JsonDeserializer { + @Override + public SearchVerifyResponse deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + JsonNode node = p.getCodec().readTree(p); + // TODO: Restructure objects to handle this better. + // Deserialization is a little complicated here. There are a few things to consider: + // (1) A search request with a single result comes back with that single result as json. + // (2) A search request with multiple results comes back with those results as an array in the + // verification_requests property. + // (3) A search request which comes back in error has different Status values than search requests + // that come back without error. (See VerifyStatus vs VerifyDetails.Status) + + // If the results has a verification_requests node then we can successfully map our object as normal. + if (node.has("verification_requests")) { + // Have to create a second object mapper to handle this as we want to bypass custom deserialization. + ObjectMapper mapper = new ObjectMapper(); + mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + return mapper.readValue(node.toString(), SearchVerifyResponse.class); + } + + // If the result has error_text, we can assume that the only fields that matter are status and the error. + if (node.has("error_text")) { + return new SearchVerifyResponse(VerifyStatus.fromInt(node.get("status").asInt()), + node.get("error_text").asText()); + } + // Otherwise we need to map the single result and then put it on the list as is. + VerifyDetails details = p.getCodec().treeToValue(node, VerifyDetails.class); + return new SearchVerifyResponse(Collections.singletonList(details)); + } +} diff --git a/src/main/java/com/nexmo/client/verify/VerifyCheck.java b/src/main/java/com/nexmo/client/verify/VerifyCheck.java new file mode 100644 index 000000000..09bd45201 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/VerifyCheck.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; + +public class VerifyCheck { + private final Date date; + private final String code; + private final Status status; + private final String ipAddress; + + public VerifyCheck(@JsonProperty("date_received") Date date, + @JsonProperty("code") String code, + @JsonProperty("status") Status status, + @JsonProperty("ip_address") String ipAddress) { + this.date = date; + this.code = code; + this.status = status; + this.ipAddress = ipAddress; + } + + public enum Status { + VALID, INVALID, + } + + public Date getDate() { + return this.date; + } + + public String getCode() { + return this.code; + } + + public Status getStatus() { + return this.status; + } + + public String getIpAddress() { + return this.ipAddress; + } +} diff --git a/src/main/java/com/nexmo/client/verify/VerifyClient.java b/src/main/java/com/nexmo/client/verify/VerifyClient.java index f92f475b7..9f41f495c 100644 --- a/src/main/java/com/nexmo/client/verify/VerifyClient.java +++ b/src/main/java/com/nexmo/client/verify/VerifyClient.java @@ -21,15 +21,11 @@ */ package com.nexmo.client.verify; - import com.nexmo.client.AbstractClient; import com.nexmo.client.HttpWrapper; import com.nexmo.client.NexmoClient; import com.nexmo.client.NexmoClientException; -import com.nexmo.client.verify.endpoints.CheckEndpoint; import com.nexmo.client.verify.endpoints.ControlEndpoint; -import com.nexmo.client.verify.endpoints.SearchEndpoint; -import com.nexmo.client.verify.endpoints.VerifyEndpoint; import java.io.IOException; import java.util.Locale; @@ -76,10 +72,8 @@ public VerifyClient(HttpWrapper httpWrapper) { * @throws IOException if a network error occurred contacting the Nexmo Verify API. * @throws NexmoClientException if there was a problem with the Nexmo request or response objects. */ - public VerifyResult verify(final String number, - final String brand) throws IOException, - NexmoClientException { - return verify.verify(number, brand); + public VerifyResult verify(final String number, final String brand) throws IOException, NexmoClientException { + return this.verify.verify(number, brand); } /** @@ -97,9 +91,8 @@ public VerifyResult verify(final String number, */ public VerifyResult verify(final String number, final String brand, - final String from) throws IOException, - NexmoClientException { - return verify.verify(number, brand, from); + final String from) throws IOException, NexmoClientException { + return this.verify.verify(number, brand, from); } /** @@ -123,9 +116,8 @@ public VerifyResult verify(final String number, final String brand, final String from, final int length, - final Locale locale) throws IOException, - NexmoClientException { - return verify.verify(number, brand, from, length, locale); + final Locale locale) throws IOException, NexmoClientException { + return this.verify.verify(number, brand, from, length, locale); } /** @@ -152,16 +144,15 @@ public VerifyResult verify(final String number, final String from, final int length, final Locale locale, - final VerifyRequest.LineType type) throws IOException, - NexmoClientException { - return verify.verify(number, brand, from, length, locale, type); + final VerifyRequest.LineType type) throws IOException, NexmoClientException { + return this.verify.verify(number, brand, from, length, locale, type); } /** * Send a verification request to a phone number. */ public VerifyResult verify(VerifyRequest request) throws IOException, NexmoClientException { - return verify.verify(request); + return this.verify.verify(request); } /** @@ -173,9 +164,8 @@ public VerifyResult verify(VerifyRequest request) throws IOException, NexmoClien * @throws IOException if a network error occurred contacting the Nexmo Verify API. * @throws NexmoClientException if there was a problem with the Nexmo request or response objects. */ - public CheckResult check(final String requestId, - final String code) throws IOException, NexmoClientException { - return check.check(requestId, code, null); + public CheckResult check(final String requestId, final String code) throws IOException, NexmoClientException { + return this.check.check(requestId, code); } /** @@ -191,7 +181,7 @@ public CheckResult check(final String requestId, public CheckResult check(final String requestId, final String code, final String ipAddress) throws IOException, NexmoClientException { - return check.check(requestId, code, ipAddress); + return this.check.check(requestId, code, ipAddress); } /** @@ -204,7 +194,7 @@ public CheckResult check(final String requestId, * @throws NexmoClientException if there was a problem with the Nexmo request or response objects. */ public SearchResult search(String requestId) throws IOException, NexmoClientException { - return search.search(requestId); + return this.search.search(requestId)[0]; } /** @@ -216,28 +206,30 @@ public SearchResult search(String requestId) throws IOException, NexmoClientExce * @throws NexmoClientException if there was a problem with the Nexmo request or response objects. */ public SearchResult[] search(String... requestIds) throws IOException, NexmoClientException { - return search.search(requestIds); + return this.search.search(requestIds); } /** * Advance a current verification request to the next stage in the process. * * @param requestId The requestId of the ongoing verification request. - * @throws IOException If an IO error occurred while making the request. + * @return A {@link ControlResponse} representing the response from the API. + * @throws IOException If an IO error occurred while making the request. * @throws NexmoClientException If the request failed for some reason. */ - public void advanceVerification(String requestId) throws IOException, NexmoClientException { - control.execute(new ControlRequest(requestId, VerifyControlCommand.TRIGGER_NEXT_EVENT)); + public ControlResponse advanceVerification(String requestId) throws IOException, NexmoClientException { + return this.control.execute(new ControlRequest(requestId, VerifyControlCommand.TRIGGER_NEXT_EVENT)); } /** * Cancel a current verification request. * * @param requestId The requestId of the ongoing verification request. - * @throws IOException If an IO error occurred while making the request. + * @return A {@link ControlResponse} representing the response from the API. + * @throws IOException If an IO error occurred while making the request. * @throws NexmoClientException If the request failed for some reason. */ - public void cancelVerification(String requestId) throws IOException, NexmoClientException { - control.execute(new ControlRequest(requestId, VerifyControlCommand.CANCEL)); + public ControlResponse cancelVerification(String requestId) throws IOException, NexmoClientException { + return this.control.execute(new ControlRequest(requestId, VerifyControlCommand.CANCEL)); } } diff --git a/src/main/java/com/nexmo/client/verify/VerifyDetails.java b/src/main/java/com/nexmo/client/verify/VerifyDetails.java new file mode 100644 index 000000000..e08760881 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/VerifyDetails.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; + +import java.math.BigDecimal; +import java.util.*; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class VerifyDetails { + + private String requestId; + private String accountId; + private String number; + private String senderId; + private Date dateSubmitted; + private Date dateFinalized; + private Date firstEventDate; + private Date lastEventDate; + private Status status; + private BigDecimal price; + private String currency; + private List checks = new ArrayList<>(); + + @JsonProperty("request_id") + public String getRequestId() { + return this.requestId; + } + + @JsonProperty("account_id") + public String getAccountId() { + return this.accountId; + } + + public String getNumber() { + return this.number; + } + + @JsonProperty("sender_id") + public String getSenderId() { + return this.senderId; + } + + @JsonProperty("date_submitted") + public Date getDateSubmitted() { + return this.dateSubmitted; + } + + @JsonProperty("date_finalized") + public Date getDateFinalized() { + return this.dateFinalized; + } + + @JsonProperty("first_event_date") + public Date getFirstEventDate() { + return this.firstEventDate; + } + + @JsonProperty("last_event_date") + public Date getLastEventDate() { + return this.lastEventDate; + } + + public Status getStatus() { + return this.status; + } + + public BigDecimal getPrice() { + return this.price; + } + + public String getCurrency() { + return this.currency; + } + + public List getChecks() { + return this.checks; + } + + public enum Status { + IN_PROGRESS("IN PROGRESS"), + SUCCESS("SUCCESS"), + FAILED("FAILED"), + EXPIRED("EXPIRED"), + CANCELLED("CANCELLED"), + INVALID("101"); + + private String status; + + private static Map stringStatusValues = new HashMap<>(); + + static { + for (Status status : Status.values()) { + stringStatusValues.put(status.status, status); + } + } + + /** + * Look up the {@link Status} based on the string value. + * + * @param status the status value to lookup. + * @return VerifyStatus based on the int value given. + */ + public static Status fromString(String status) { + return stringStatusValues.get(status); + } + + Status(String status) { + this.status = status; + } + + @JsonValue + public String getStatus() { + return this.status; + } + } +} diff --git a/src/main/java/com/nexmo/client/verify/VerifyEndpoint.java b/src/main/java/com/nexmo/client/verify/VerifyEndpoint.java new file mode 100644 index 000000000..cda1caf35 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/VerifyEndpoint.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.nexmo.client.HttpWrapper; +import com.nexmo.client.NexmoClientException; + +import java.io.IOException; +import java.util.Locale; + +class VerifyEndpoint { + private VerifyMethod verifyMethod; + + VerifyEndpoint(HttpWrapper httpWrapper) { + this.verifyMethod = new VerifyMethod(httpWrapper); + } + + VerifyResult verify(String number, + String brand, + String from, + int length, + Locale locale, + VerifyRequest.LineType type) throws IOException, NexmoClientException { + return verify(new VerifyRequest(number, brand, from, length, locale, type)); + } + + VerifyResult verify(String number, + String brand, + String from, + int length, + Locale locale) throws IOException, NexmoClientException { + return verify(new VerifyRequest(number, brand, from, length, locale)); + } + + VerifyResult verify(String number, String brand, String from) throws IOException, NexmoClientException { + return verify(new VerifyRequest(number, brand, from)); + } + + VerifyResult verify(String number, String brand) throws IOException, NexmoClientException { + return verify(new VerifyRequest(number, brand)); + } + + VerifyResult verify(VerifyRequest request) throws IOException, NexmoClientException { + // TODO: Remove translation when releasing 4.0 + return translateFromVerifyResponse(this.verifyMethod.execute(request)); + } + + private VerifyResult translateFromVerifyResponse(VerifyResponse response) { + return new VerifyResult(response.getStatus().getVerifyStatus(), + response.getRequestId(), + response.getErrorText(), + response.getStatus().isTemporaryError()); + } +} diff --git a/src/main/java/com/nexmo/client/verify/VerifyMethod.java b/src/main/java/com/nexmo/client/verify/VerifyMethod.java new file mode 100644 index 000000000..6dec4b238 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/VerifyMethod.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011-2017 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.nexmo.client.HttpWrapper; +import com.nexmo.client.NexmoClientException; +import com.nexmo.client.auth.SignatureAuthMethod; +import com.nexmo.client.auth.TokenAuthMethod; +import com.nexmo.client.voice.endpoints.AbstractMethod; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.message.BasicNameValuePair; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +class VerifyMethod extends AbstractMethod { + private static final Class[] ALLOWED_AUTH_METHODS = new Class[]{SignatureAuthMethod.class, TokenAuthMethod.class}; + + private static final String DEFAULT_URI = "https://api.nexmo.com/verify/json"; + + private String uri = DEFAULT_URI; + + VerifyMethod(HttpWrapper httpWrapper) { + super(httpWrapper); + } + + @Override + protected Class[] getAcceptableAuthMethods() { + return ALLOWED_AUTH_METHODS; + } + + @Override + public RequestBuilder makeRequest(VerifyRequest request) throws NexmoClientException, UnsupportedEncodingException { + RequestBuilder result = RequestBuilder.post(this.uri) + .addParameter("number", request.getNumber()) + .addParameter("brand", request.getBrand()); + + if (request.getFrom() != null) { + result.addParameter("sender_id", request.getFrom()); + } + + if (request.getLength() > 0) { + result.addParameter("code_length", Integer.toString(request.getLength())); + } + + if (request.getLocale() != null) { + result.addParameter(new BasicNameValuePair("lg", + (request.getLocale().getLanguage() + "-" + request.getLocale().getCountry()).toLowerCase())); + } + + if (request.getType() != null) { + result.addParameter("require_type", request.getType().toString()); + } + + if (request.getCountry() != null) { + result.addParameter("country", request.getCountry()); + } + + if (request.getPinExpiry() != null) { + result.addParameter("pin_expiry", request.getPinExpiry().toString()); + } + + if (request.getNextEventWait() != null) { + result.addParameter("next_event_wait", request.getNextEventWait().toString()); + } + + return result; + } + + @Override + public VerifyResponse parseResponse(HttpResponse response) throws IOException { + return VerifyResponse.fromJson(new BasicResponseHandler().handleResponse(response)); + } +} diff --git a/src/main/java/com/nexmo/client/verify/VerifyResponse.java b/src/main/java/com/nexmo/client/verify/VerifyResponse.java new file mode 100644 index 000000000..9a8f70608 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/VerifyResponse.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nexmo.client.NexmoResponseParseException; +import com.nexmo.client.NexmoUnexpectedException; + +import java.io.IOException; + +public class VerifyResponse { + private String requestId; + private VerifyStatus status; + private String errorText; + + @JsonCreator + public VerifyResponse(@JsonProperty(value = "status", required = true) VerifyStatus status) { + this.status = status; + } + + public static VerifyResponse fromJson(String json) { + try { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(json, VerifyResponse.class); + } catch (JsonMappingException jme) { + throw new NexmoResponseParseException("Failed to produce VerifyResponse from json.", jme); + } catch (IOException jpe) { + throw new NexmoUnexpectedException("Failed to produce VerifyResponse from json.", jpe); + } + } + + @JsonProperty("request_id") + public String getRequestId() { + return this.requestId; + } + + public VerifyStatus getStatus() { + return this.status; + } + + @JsonProperty("error_text") + public String getErrorText() { + return this.errorText; + } +} diff --git a/src/main/java/com/nexmo/client/verify/VerifyResult.java b/src/main/java/com/nexmo/client/verify/VerifyResult.java index f01e47477..e4c65edf4 100644 --- a/src/main/java/com/nexmo/client/verify/VerifyResult.java +++ b/src/main/java/com/nexmo/client/verify/VerifyResult.java @@ -23,17 +23,16 @@ /** - * Verification request result. - * - * @author Daniele Ricci + * @deprecated Relies on XML Endpoint, use {@link VerifyResponse} */ +@Deprecated public class VerifyResult extends BaseResult { private final String requestId; public VerifyResult(final int status, - final String requestId, - final String errorText, - final boolean temporaryError) { + final String requestId, + final String errorText, + final boolean temporaryError) { super(status, errorText, temporaryError); this.requestId = requestId; } diff --git a/src/main/java/com/nexmo/client/verify/VerifyStatus.java b/src/main/java/com/nexmo/client/verify/VerifyStatus.java new file mode 100644 index 000000000..43e4952d5 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/VerifyStatus.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import java.util.HashMap; +import java.util.Map; + +@JsonDeserialize(using = VerifyStatusDeserializer.class) +public enum VerifyStatus { + OK(0), + THROTTLED(1), + MISSING_PARAMS(2), + INVALID_PARAMS(3), + INVALID_CREDENTIALS(4), + INTERNAL_ERROR(5), + INVALID_REQUEST(6), + NUMBER_BARRED(7), + PARTNER_ACCOUNT_BARRED(8), + PARTNER_QUOTA_EXCEEDED(9), + ALREADY_REQUESTED(10), + UNSUPPORTED_NETWORK(15), + INVALID_CODE(16), + WRONG_CODE_THROTTLED(17), + TOO_MANY_DESTINATIONS(18), + NO_RESPONSE(101), + COMMS_FAILURE(-1); + + private int verifyStatus; + + private static Map integerStatusValues = new HashMap<>(); + + static { + for (VerifyStatus verifyStatus : VerifyStatus.values()) { + integerStatusValues.put(verifyStatus.verifyStatus, verifyStatus); + } + } + + /** + * Look up the {@link VerifyStatus} based on the int value. + * + * @param verifyStatus the int value of the verify status. + * @return VerifyStatus based on the int value given. + */ + public static VerifyStatus fromInt(int verifyStatus) { + return integerStatusValues.get(verifyStatus); + } + + VerifyStatus(int verifyStatus) { + this.verifyStatus = verifyStatus; + } + + public int getVerifyStatus() { + return this.verifyStatus; + } + + public boolean isTemporaryError() { + return this == THROTTLED || this == INTERNAL_ERROR; + } +} diff --git a/src/main/java/com/nexmo/client/verify/VerifyStatusDeserializer.java b/src/main/java/com/nexmo/client/verify/VerifyStatusDeserializer.java new file mode 100644 index 000000000..e0f45a888 --- /dev/null +++ b/src/main/java/com/nexmo/client/verify/VerifyStatusDeserializer.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; + +public class VerifyStatusDeserializer extends JsonDeserializer { + @Override + public VerifyStatus deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + // Perform the conversion using parseInt so that potential number format exceptions can be converted into a default + // VerifyStatus.INTERNAL_ERROR + // Jackson's getValueAsInt defaults results to 0 and throws no exceptions. + try { + return VerifyStatus.fromInt(Integer.parseInt(p.getText())); + } catch (NumberFormatException nfe) { + return VerifyStatus.INTERNAL_ERROR; + } + } +} diff --git a/src/main/java/com/nexmo/client/verify/endpoints/CheckEndpoint.java b/src/main/java/com/nexmo/client/verify/endpoints/CheckEndpoint.java index 990ffa4d7..e087c8d8f 100644 --- a/src/main/java/com/nexmo/client/verify/endpoints/CheckEndpoint.java +++ b/src/main/java/com/nexmo/client/verify/endpoints/CheckEndpoint.java @@ -28,6 +28,10 @@ import java.io.IOException; +/** + * @deprecated Relies on XML Endpoint. Use {@link com.nexmo.client.verify.VerifyClient#check}. + */ +@Deprecated public class CheckEndpoint { private VerifyCheckMethod checkMethod; @@ -40,8 +44,7 @@ public CheckEndpoint(HttpWrapper httpWrapper) { this.checkMethod = new VerifyCheckMethod(httpWrapper); } - public CheckResult check(final String requestId, - final String code) throws IOException, NexmoClientException { + public CheckResult check(final String requestId, final String code) throws IOException, NexmoClientException { return this.checkMethod.execute(new CheckRequest(requestId, code)); } diff --git a/src/main/java/com/nexmo/client/verify/endpoints/SearchEndpoint.java b/src/main/java/com/nexmo/client/verify/endpoints/SearchEndpoint.java index bdb798b31..5dd7e81f2 100644 --- a/src/main/java/com/nexmo/client/verify/endpoints/SearchEndpoint.java +++ b/src/main/java/com/nexmo/client/verify/endpoints/SearchEndpoint.java @@ -50,7 +50,10 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; - +/** + * @deprecated Relies on XML Endpoint, use {@link com.nexmo.client.verify.VerifyClient#search} instead. + */ +@Deprecated public class SearchEndpoint extends AbstractMethod { private static final Log log = LogFactory.getLog(SearchEndpoint.class); diff --git a/src/main/java/com/nexmo/client/verify/endpoints/VerifyCheckMethod.java b/src/main/java/com/nexmo/client/verify/endpoints/VerifyCheckMethod.java index 834752adf..7d76c8322 100644 --- a/src/main/java/com/nexmo/client/verify/endpoints/VerifyCheckMethod.java +++ b/src/main/java/com/nexmo/client/verify/endpoints/VerifyCheckMethod.java @@ -45,6 +45,10 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; +/** + * @deprecated Relies on XML Endpoint, use {@link com.nexmo.client.verify.CheckMethod} + */ +@Deprecated public class VerifyCheckMethod extends AbstractMethod { private static final Log log = LogFactory.getLog(VerifyCheckMethod.class); private static final Class[] ALLOWED_AUTH_METHODS = new Class[]{SignatureAuthMethod.class, TokenAuthMethod.class}; @@ -68,12 +72,10 @@ public RequestBuilder makeRequest(CheckRequest request) throws NexmoClientExcept if (request.getRequestId() == null || request.getCode() == null) throw new IllegalArgumentException("request ID and code parameters are mandatory."); - RequestBuilder result = RequestBuilder.post(this.uri) - .addParameter("request_id", request.getRequestId()) + RequestBuilder result = RequestBuilder.post(this.uri).addParameter("request_id", request.getRequestId()) .addParameter("code", request.getCode()); - if (request.getIpAddress() != null) - result.addParameter("ip_address", request.getIpAddress()); + if (request.getIpAddress() != null) result.addParameter("ip_address", request.getIpAddress()); return result; } @@ -100,8 +102,7 @@ private CheckResult parseCheckResponse(String response) throws NexmoResponsePars NodeList fields = root.getChildNodes(); for (int i = 0; i < fields.getLength(); i++) { Node node = fields.item(i); - if (node.getNodeType() != Node.ELEMENT_NODE) - continue; + if (node.getNodeType() != Node.ELEMENT_NODE) continue; String name = node.getNodeName(); if ("event_id".equals(name)) { @@ -109,8 +110,7 @@ private CheckResult parseCheckResponse(String response) throws NexmoResponsePars } else if ("status".equals(name)) { String str = XmlUtil.stringValue(node); try { - if (str != null) - status = Integer.parseInt(str); + if (str != null) status = Integer.parseInt(str); } catch (NumberFormatException e) { log.error("xml parser .. invalid value in node [ " + str + " ] "); status = BaseResult.STATUS_INTERNAL_ERROR; @@ -118,8 +118,7 @@ private CheckResult parseCheckResponse(String response) throws NexmoResponsePars } else if ("price".equals(name)) { String str = XmlUtil.stringValue(node); try { - if (str != null) - price = Float.parseFloat(str); + if (str != null) price = Float.parseFloat(str); } catch (NumberFormatException e) { log.error("xml parser .. invalid value in node [ " + str + " ] "); } @@ -130,8 +129,7 @@ private CheckResult parseCheckResponse(String response) throws NexmoResponsePars } } - if (status == -1) - throw new NexmoResponseParseException("Xml Parser - did not find a node"); + if (status == -1) throw new NexmoResponseParseException("Xml Parser - did not find a node"); // Is this a temporary error ? boolean temporaryError = (status == BaseResult.STATUS_THROTTLED || status == BaseResult.STATUS_INTERNAL_ERROR); diff --git a/src/main/java/com/nexmo/client/verify/endpoints/VerifyEndpoint.java b/src/main/java/com/nexmo/client/verify/endpoints/VerifyEndpoint.java index 12ce66363..6e0daa40a 100644 --- a/src/main/java/com/nexmo/client/verify/endpoints/VerifyEndpoint.java +++ b/src/main/java/com/nexmo/client/verify/endpoints/VerifyEndpoint.java @@ -41,6 +41,10 @@ import java.io.UnsupportedEncodingException; import java.util.Locale; +/** + * @deprecated Relies on XML Endpoint, use {@link com.nexmo.client.verify.VerifyClient#verify} instead. + */ +@Deprecated public class VerifyEndpoint extends AbstractMethod { private static final Class[] ALLOWED_AUTH_METHODS = new Class[]{SignatureAuthMethod.class, TokenAuthMethod.class}; @@ -51,7 +55,7 @@ public class VerifyEndpoint extends AbstractMethod private String uri = DEFAULT_URI; /** - * Create a new VerifyEndpoint. + * Create a new VerifyMethod. *

* This client is used for calling the verify API's verify endpoint. */ @@ -107,16 +111,13 @@ public VerifyResult parseResponse(HttpResponse response) throws IOException { return parseVerifyResponse(new BasicResponseHandler().handleResponse(response)); } - public VerifyResult verify(final String number, - final String brand) throws IOException, - NexmoClientException { + public VerifyResult verify(final String number, final String brand) throws IOException, NexmoClientException { return execute(new VerifyRequest(number, brand)); } public VerifyResult verify(final String number, final String brand, - final String from) throws IOException, - NexmoClientException { + final String from) throws IOException, NexmoClientException { return execute(new VerifyRequest(number, brand, from)); } @@ -124,8 +125,7 @@ public VerifyResult verify(final String number, final String brand, final String from, final int length, - final Locale locale) throws IOException, - NexmoClientException { + final Locale locale) throws IOException, NexmoClientException { return execute(new VerifyRequest(number, brand, from, length, locale)); } @@ -134,8 +134,7 @@ public VerifyResult verify(final String number, final String from, final int length, final Locale locale, - final VerifyRequest.LineType type) throws IOException, - NexmoClientException { + final VerifyRequest.LineType type) throws IOException, NexmoClientException { return execute(new VerifyRequest(number, brand, from, length, locale, type)); } diff --git a/src/test/java/com/nexmo/client/verify/CheckMethodTest.java b/src/test/java/com/nexmo/client/verify/CheckMethodTest.java new file mode 100644 index 000000000..306a45965 --- /dev/null +++ b/src/test/java/com/nexmo/client/verify/CheckMethodTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import org.apache.http.NameValuePair; +import org.apache.http.client.methods.RequestBuilder; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +public class CheckMethodTest extends MethodTest { + @Before + public void setUp() { + method = new CheckMethod(null); + } + + @Test + public void testConstructVerifyParamsWithoutIp() throws Exception { + CheckRequest checkRequest = new CheckRequest("request-id", "code"); + RequestBuilder request = method.makeRequest(checkRequest); + List params = request.getParameters(); + + assertContainsParam(params, "request_id", "request-id"); + assertContainsParam(params, "code", "code"); + assertParamMissing(params, "ip_address"); + } + + @Test + public void testConstructVerifyParamsWithIp() throws Exception { + CheckRequest checkRequest = new CheckRequest("request-id", "code", "ip-address"); + RequestBuilder request = method.makeRequest(checkRequest); + List params = request.getParameters(); + + assertContainsParam(params, "request_id", "request-id"); + assertContainsParam(params, "code", "code"); + assertContainsParam(params, "ip_address", "ip-address"); + } +} diff --git a/src/test/java/com/nexmo/client/verify/ClientTest.java b/src/test/java/com/nexmo/client/verify/ClientTest.java new file mode 100644 index 000000000..af131db56 --- /dev/null +++ b/src/test/java/com/nexmo/client/verify/ClientTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.nexmo.client.AbstractClient; +import com.nexmo.client.HttpWrapper; +import com.nexmo.client.auth.TokenAuthMethod; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.junit.Before; + +import java.io.ByteArrayInputStream; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public abstract class ClientTest { + protected HttpWrapper wrapper; + protected T client; + + @Before + public void setupWrapper() { + wrapper = new HttpWrapper(new TokenAuthMethod("not-an-api-key", "secret")); + } + + protected HttpClient stubHttpClient(int statusCode, String content) throws Exception { + HttpClient result = mock(HttpClient.class); + + HttpResponse response = mock(HttpResponse.class); + StatusLine sl = mock(StatusLine.class); + HttpEntity entity = mock(HttpEntity.class); + + when(result.execute(any(HttpUriRequest.class))).thenReturn(response); + when(entity.getContent()).thenReturn(new ByteArrayInputStream(content.getBytes("UTF-8"))); + when(sl.getStatusCode()).thenReturn(statusCode); + when(response.getStatusLine()).thenReturn(sl); + when(response.getEntity()).thenReturn(entity); + + return result; + } +} diff --git a/src/test/java/com/nexmo/client/verify/MethodTest.java b/src/test/java/com/nexmo/client/verify/MethodTest.java new file mode 100644 index 000000000..b765774f8 --- /dev/null +++ b/src/test/java/com/nexmo/client/verify/MethodTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import org.apache.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public abstract class MethodTest { + protected T method; + + protected void assertContainsParam(List params, String key, String value) { + NameValuePair item = new BasicNameValuePair(key, value); + assertTrue("" + params + " should contain " + item, params.contains(item)); + } + + protected void assertParamMissing(List params, String key) { + Set keys = new HashSet<>(); + for (NameValuePair pair : params) { + keys.add(pair.getName()); + } + assertFalse("" + params + " should not contain " + key, keys.contains(key)); + } + + +} diff --git a/src/test/java/com/nexmo/client/verify/VerifyClientCheckEndpointTest.java b/src/test/java/com/nexmo/client/verify/VerifyClientCheckEndpointTest.java new file mode 100644 index 000000000..154c9bebf --- /dev/null +++ b/src/test/java/com/nexmo/client/verify/VerifyClientCheckEndpointTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.nexmo.client.NexmoResponseParseException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.math.BigDecimal; + +public class VerifyClientCheckEndpointTest extends ClientTest { + + @Before + public void setUp() { + client = new VerifyClient(wrapper); + } + + @Test + public void testCheckWithValidResponseAndIp() throws Exception { + String json = "{\n" + " \"request_id\": \"a-request-id\",\n" + " \"status\": \"0\",\n" + " \"event_id\": \"an-event-id\",\n" + " \"price\": \"0.10000000\",\n" + " \"currency\": \"EUR\"\n" + "}\n"; + // For proper coverage we will check both with and without IP. However, the logic remains the same. + // Note: We have to stub the client each time because it won't allow for sequential requests. + CheckResult[] results = new CheckResult[2]; + wrapper.setHttpClient(stubHttpClient(200, json)); + results[0] = client.check("a-request-id", "1234", "127.0.0.1"); + + wrapper.setHttpClient(stubHttpClient(200, json)); + results[1] = client.check("a-request-id", "1234"); + + for (CheckResult result : results) { + Assert.assertEquals("a-request-id", result.getRequestId()); + Assert.assertEquals(0, result.getStatus()); + Assert.assertEquals("an-event-id", result.getEventId()); + Assert.assertEquals(new BigDecimal("0.10000000").floatValue(), result.getPrice(), 0.0f); + Assert.assertEquals("EUR", result.getCurrency()); + Assert.assertNull(result.getErrorText()); + } + } + + @Test + public void testCheckWithoutRequestId() throws Exception { + String json = "{\n" + " \"status\": \"0\",\n" + " \"event_id\": \"an-event-id\",\n" + " \"price\": \"0.10000000\",\n" + " \"currency\": \"EUR\"\n" + "}\n"; + wrapper.setHttpClient(stubHttpClient(200, json)); + CheckResult result = client.check("a-request-id", "1234", "127.0.0.1"); + + Assert.assertNull(result.getRequestId()); + } + + @Test(expected = NexmoResponseParseException.class) + public void testCheckWithoutStatusThrowsException() throws Exception { + String json = "{\n" + " \"request_id\": \"a-request-id\",\n" + " \"event_id\": \"an-event-id\",\n" + " \"price\": \"0.10000000\",\n" + " \"currency\": \"EUR\"\n" + "}\n"; + wrapper.setHttpClient(stubHttpClient(200, json)); + client.check("a-request-id", "1234", "127.0.0.1"); + } + + @Test + public void testCheckWithNonNumericStatus() throws Exception { + String json = "{\n" + " \"request_id\": \"a-request-id\",\n" + " \"status\": \"test\",\n" + " \"event_id\": \"an-event-id\",\n" + " \"price\": \"0.10000000\",\n" + " \"currency\": \"EUR\"\n" + "}\n"; + wrapper.setHttpClient(stubHttpClient(200, json)); + CheckResult result = client.check("a-request-id", "1234"); + Assert.assertEquals(VerifyStatus.INTERNAL_ERROR.getVerifyStatus(), result.getStatus()); + } + + @Test + public void testCheckWithoutEventId() throws Exception { + String json = "{\n" + " \"request_id\": \"a-request-id\",\n" + " \"status\": \"0\",\n" + " \"price\": \"0.10000000\",\n" + " \"currency\": \"EUR\"\n" + "}\n"; + wrapper.setHttpClient(stubHttpClient(200, json)); + CheckResult result = client.check("a-request-id", "1234", "127.0.0.1"); + + Assert.assertNull(result.getEventId()); + } + + @Test + public void testCheckWithoutPrice() throws Exception { + String json = "{\n" + " \"request_id\": \"a-request-id\",\n" + " \"status\": \"0\",\n" + " \"event_id\": \"an-event-id\",\n" + " \"currency\": \"EUR\"\n" + "}\n"; + wrapper.setHttpClient(stubHttpClient(200, json)); + CheckResult result = client.check("a-request-id", "1234", "127.0.0.1"); + + Assert.assertEquals(0, result.getPrice(), 0.0f); + } + + @Test(expected = NexmoResponseParseException.class) + public void testCheckWithNonNumericPrice() throws Exception { + String json = "{\n" + " \"request_id\": \"a-request-id\",\n" + " \"status\": \"0\",\n" + " \"event_id\": \"an-event-id\",\n" + " \"price\": \"test\",\n" + " \"currency\": \"EUR\"\n" + "}\n"; + wrapper.setHttpClient(stubHttpClient(200, json)); + client.check("a-request-id", "1234"); + } + + @Test + public void testCheckWithoutCurrency() throws Exception { + String json = "{\n" + " \"request_id\": \"a-request-id\",\n" + " \"status\": \"0\",\n" + " \"event_id\": \"an-event-id\",\n" + " \"price\": \"0.10000000\"\n" + "}\n"; + wrapper.setHttpClient(stubHttpClient(200, json)); + CheckResult result = client.check("a-request-id", "1234", "127.0.0.1"); + + Assert.assertNull(result.getCurrency()); + } + + @Test + public void testCheckWithError() throws Exception { + String json = "{\n" + " \"status\": \"2\",\n" + " \"error_text\": \"There was an error.\"\n" + "}"; + wrapper.setHttpClient(stubHttpClient(200, json)); + CheckResult result = client.check("a-request-id", "1234", "127.0.0.1"); + + Assert.assertEquals(2, result.getStatus()); + Assert.assertEquals("There was an error.", result.getErrorText()); + } + + @Test + public void testWithInvalidNumericStatus() throws Exception { + String json = "{\n" + " \"status\": \"5958\"\n" + "}"; + wrapper.setHttpClient(stubHttpClient(200, json)); + CheckResult result = client.check("a-request-id", "1234", "127.0.0.1"); + + Assert.assertEquals(Integer.MAX_VALUE, result.getStatus()); + } +} diff --git a/src/test/java/com/nexmo/client/verify/VerifyClientSearchEndpointTest.java b/src/test/java/com/nexmo/client/verify/VerifyClientSearchEndpointTest.java new file mode 100644 index 000000000..153733e47 --- /dev/null +++ b/src/test/java/com/nexmo/client/verify/VerifyClientSearchEndpointTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import com.nexmo.client.NexmoResponseParseException; +import org.junit.Before; +import org.junit.Test; + +import java.text.SimpleDateFormat; + +import static org.junit.Assert.assertEquals; + +public class VerifyClientSearchEndpointTest extends ClientTest { + @Before + public void setUp() { + client = new VerifyClient(wrapper); + } + + @Test + public void testSearchSuccess() throws Exception { + //language=JSON + String json = "{\n" + " \"request_id\": \"not-a-search-request-id\",\n" + " \"account_id\": \"not-an-account-id\",\n" + " \"number\": \"447700900999\",\n" + " \"sender_id\": \"447700900991\",\n" + " \"date_submitted\": \"2014-03-04 10:11:12\",\n" + " \"date_finalized\": \"2015-02-03 07:08:09\",\n" + " \"checks\": [\n" + " {\n" + " \"date_received\": \"2012-01-02 03:04:05\",\n" + " \"code\": \"code\",\n" + " \"status\": \"VALID\",\n" + " \"ip_address\": \"\"\n" + " },\n" + " {\n" + " \"date_received\": \"2012-01-02 03:04:05\",\n" + " \"code\": \"code\",\n" + " \"status\": \"VALID\",\n" + " \"ip_address\": \"\"\n" + " }\n" + " ],\n" + " \"first_event_date\": \"2012-01-02 03:04:05\",\n" + " \"last_event_date\": \"2012-01-02 03:04:06\",\n" + " \"price\": \"0.03000000\",\n" + " \"currency\": \"EUR\",\n" + " \"status\": \"SUCCESS\"\n" + "}"; + wrapper.setHttpClient(this.stubHttpClient(200, json)); + + SearchResult c = client.search("not-a-search-request-id"); + assertEquals(SearchResult.STATUS_OK, c.getStatus()); + assertEquals("not-a-search-request-id", c.getRequestId()); + assertEquals(SearchResult.VerificationStatus.SUCCESS, c.getVerificationStatus()); + assertEquals("447700900999", c.getNumber()); + assertEquals("447700900991", c.getSenderId()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-03-04 10:11:12"), c.getDateSubmitted()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2015-02-03 07:08:09"), c.getDateFinalized()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2012-01-02 03:04:05"), c.getFirstEventDate()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2012-01-02 03:04:06"), c.getLastEventDate()); + } + + @Test + public void testSearchError() throws Exception { + //language=JSON + String json = "{\n" + " \"request_id\": \"\",\n" + " \"status\": \"101\",\n" + " \"error_text\": \"No response found.\"\n" + "}"; + wrapper.setHttpClient(this.stubHttpClient(200, json)); + + SearchResult c = client.search("AAAAA"); + assertEquals(SearchResult.STATUS_NO_RESPONSE, c.getStatus()); + } + + @Test + public void testSearchFailed() throws Exception { + //language=JSON + String json = "{\n" + " \"request_id\": \"a-random-request-id\",\n" + " \"account_id\": \"account-id\",\n" + " \"number\": \"not-a-number\",\n" + " \"sender_id\": \"verify\",\n" + " \"date_submitted\": \"2016-10-19 11:18:56\",\n" + " \"date_finalized\": \"2016-10-19 11:20:00\",\n" + " \"checks\": [\n" + " {\n" + " \"date_received\": \"2016-10-19 11:19:54\",\n" + " \"code\": \"1234\",\n" + " \"status\": \"INVALID\",\n" + " \"ip_address\": \"\"\n" + " },\n" + " {\n" + " \"date_received\": \"2016-10-19 11:19:58\",\n" + " \"code\": \"1234\",\n" + " \"status\": \"INVALID\",\n" + " \"ip_address\": \"\"\n" + " },\n" + " {\n" + " \"date_received\": \"2016-10-19 11:20:00\",\n" + " \"code\": \"1234\",\n" + " \"status\": \"INVALID\",\n" + " \"ip_address\": \"\"\n" + " }\n" + " ],\n" + " \"first_event_date\": \"2016-10-19 11:18:56\",\n" + " \"last_event_date\": \"2016-10-19 11:18:56\",\n" + " \"price\": \"0.03000000\",\n" + " \"currency\": \"EUR\",\n" + " \"status\": \"FAILED\"\n" + "}"; + wrapper.setHttpClient(this.stubHttpClient(200, json)); + + SearchResult c = client.search("a-random-request-id"); + assertEquals(SearchResult.STATUS_OK, c.getStatus()); + assertEquals("a-random-request-id", c.getRequestId()); + assertEquals(SearchResult.VerificationStatus.FAILED, c.getVerificationStatus()); + } + + @Test + public void testSearchExpired() throws Exception { + String json = "{\n" + " \"request_id\": \"a-random-request-id\",\n" + " \"account_id\": \"account-id\",\n" + " \"number\": \"not-a-number\",\n" + " \"sender_id\": \"verify\",\n" + " \"date_submitted\": \"2016-10-19 11:25:19\",\n" + " \"date_finalized\": \"2016-10-19 11:35:27\",\n" + " \"checks\": [],\n" + " \"first_event_date\": \"2016-10-19 11:25:19\",\n" + " \"last_event_date\": \"2016-10-19 11:30:26\",\n" + " \"price\": \"0\",\n" + " \"currency\": \"EUR\",\n" + " \"status\": \"EXPIRED\"\n" + "}\n"; + wrapper.setHttpClient(this.stubHttpClient(200, json)); + + SearchResult c = client.search("a-random-request-id"); + assertEquals(SearchResult.STATUS_OK, c.getStatus()); + assertEquals("a-random-request-id", c.getRequestId()); + assertEquals(SearchResult.VerificationStatus.EXPIRED, c.getVerificationStatus()); + } + + @Test + public void testSearchInProgress() throws Exception { + String json = "{\n" + " \"request_id\": \"a-random-request-id\",\n" + " \"account_id\": \"account-id\",\n" + " \"number\": \"not-a-number\",\n" + " \"sender_id\": \"verify\",\n" + " \"date_submitted\": \"2016-10-19 11:25:19\",\n" + " \"date_finalized\": \"\",\n" + " \"checks\": [],\n" + " \"first_event_date\": \"2016-10-19 11:25:19\",\n" + " \"last_event_date\": \"2016-10-19 11:30:26\",\n" + " \"price\": \"0.10000000\",\n" + " \"currency\": \"EUR\",\n" + " \"status\": \"IN PROGRESS\"\n" + "}\n"; + wrapper.setHttpClient(this.stubHttpClient(200, json)); + + SearchResult c = client.search("a-random-request-id"); + assertEquals(SearchResult.STATUS_OK, c.getStatus()); + assertEquals("a-random-request-id", c.getRequestId()); + assertEquals(SearchResult.VerificationStatus.IN_PROGRESS, c.getVerificationStatus()); + } + + @Test + public void testSearchWithWrongParams() throws Exception { + String json = "{\n" + " \"request_id\": \"\",\n" + " \"status\": 6,\n" + " \"error_text\": \"The Nexmo platform was unable to process this message for the following reason: Wrong parameters.\"\n" + "}"; + wrapper.setHttpClient(this.stubHttpClient(200, json)); + + SearchResult c = client.search("a-random-request-id"); + assertEquals(SearchResult.STATUS_INVALID_REQUEST, c.getStatus()); + } + + @Test + public void testSearchWithMultipleResults() throws Exception { + String json = "{\n" + " \"verification_requests\": [\n" + " { \n" + " \"request_id\": \"a-random-request-id\",\n" + " \"account_id\": \"abcde\",\n" + " \"number\": \"447700900999\",\n" + " \"sender_id\": \"verify\",\n" + " \"date_submitted\": \"2016-10-21 15:41:02\",\n" + " \"date_finalized\": \"\",\n" + " \"checks\": [],\n" + " \"first_event_date\": \"2016-10-21 15:41:02\",\n" + " \"last_event_date\": \"2016-10-21 15:43:07\",\n" + " \"price\": \"0.10000000\",\n" + " \"currency\": \"EUR\",\n" + " \"status\": \"IN PROGRESS\"\n" + " },\n" + " { \n" + " \"request_id\": \"another-random-request-id\",\n" + " \"account_id\": \"fghij\",\n" + " \"number\": \"447700900991\",\n" + " \"sender_id\": \"verify2\",\n" + " \"date_submitted\": \"2016-10-21 15:41:58\",\n" + " \"date_finalized\": \"\",\n" + " \"checks\": [],\n" + " \"first_event_date\": \"2016-10-21 15:41:58\",\n" + " \"last_event_date\": \"2016-10-21 15:41:58\",\n" + " \"price\": \"0.10000000\",\n" + " \"currency\": \"EUR\",\n" + " \"status\": \"EXPIRED\"\n" + " }\n" + " ]\n" + "}"; + wrapper.setHttpClient(this.stubHttpClient(200, json)); + + SearchResult[] c = client.search("a-random-request-id", "another-random-request-id"); + SearchResult firstResult = c[0]; + SearchResult secondResult = c[1]; + + assertEquals("a-random-request-id", firstResult.getRequestId()); + assertEquals("abcde", firstResult.getAccountId()); + assertEquals("447700900999", firstResult.getNumber()); + assertEquals("verify", firstResult.getSenderId()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-10-21 15:41:02"), + firstResult.getDateSubmitted()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-10-21 15:41:02"), + firstResult.getFirstEventDate()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-10-21 15:43:07"), + firstResult.getLastEventDate()); + assertEquals(SearchResult.VerificationStatus.IN_PROGRESS, firstResult.getVerificationStatus()); + + assertEquals("another-random-request-id", secondResult.getRequestId()); + assertEquals("fghij", secondResult.getAccountId()); + assertEquals("447700900991", secondResult.getNumber()); + assertEquals("verify2", secondResult.getSenderId()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-10-21 15:41:58"), + secondResult.getDateSubmitted()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-10-21 15:41:58"), + secondResult.getFirstEventDate()); + assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-10-21 15:41:58"), + secondResult.getLastEventDate()); + assertEquals(SearchResult.VerificationStatus.EXPIRED, secondResult.getVerificationStatus()); + } + + @Test(expected = NexmoResponseParseException.class) + public void testSearchInvalidDates() throws Exception { + String json = " { \n" + " \"request_id\": \"a-random-request-id\",\n" + " \"account_id\": \"account-id\",\n" + " \"number\": \"not-a-number\",\n" + " \"sender_id\": \"verify\",\n" + " \"date_submitted\": \"aaa\",\n" + " \"date_finalized\": \"ddd\",\n" + " \"checks\": [],\n" + " \"first_event_date\": \"bbb\",\n" + " \"last_event_date\": \"ccc\",\n" + " \"price\": \"0.10000000\",\n" + " \"currency\": \"EUR\",\n" + " \"status\": \"SUCCESS\"\n" + " }"; + + wrapper.setHttpClient(this.stubHttpClient(200, json)); + client.search("a-random-request-id"); + } +} diff --git a/src/test/java/com/nexmo/client/verify/VerifyClientTest.java b/src/test/java/com/nexmo/client/verify/VerifyClientTest.java deleted file mode 100644 index 185d9e494..000000000 --- a/src/test/java/com/nexmo/client/verify/VerifyClientTest.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2011-2017 Nexmo Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.nexmo.client.verify; - - -import com.nexmo.client.HttpWrapper; -import com.nexmo.client.NexmoResponseParseException; -import com.nexmo.client.auth.TokenAuthMethod; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpUriRequest; -import org.junit.Before; -import org.junit.Test; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Locale; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - - -public class VerifyClientTest { - private HttpWrapper wrapper; - private VerifyClient client; - - @Before - public void setUp() throws Exception { - wrapper = new HttpWrapper(new TokenAuthMethod("not-an-api-key", "secret")); - client = new VerifyClient(wrapper); - } - - private HttpClient stubHttpClient(int statusCode, String content) throws Exception { - HttpClient result = mock(HttpClient.class); - - HttpResponse response = mock(HttpResponse.class); - StatusLine sl = mock(StatusLine.class); - HttpEntity entity = mock(HttpEntity.class); - - when(result.execute(any(HttpUriRequest.class))).thenReturn(response); - when(entity.getContent()).thenReturn(new ByteArrayInputStream(content.getBytes("UTF-8"))); - when(sl.getStatusCode()).thenReturn(statusCode); - when(response.getStatusLine()).thenReturn(sl); - when(response.getEntity()).thenReturn(entity); - - return result; - } - - @Test - public void testVerify() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - " \n" + - " not-really-a-request-id\n" + - " 0\n" + - " error\n" + - " ")); - VerifyResult r = client.verify( - "447700900999", - "TestBrand", - "15555215554", 6, Locale.US); - assertEquals(VerifyResult.STATUS_OK, r.getStatus()); - } - - @Test - public void testVerifyWithRequestObject() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - " \n" + - " not-really-a-request-id\n" + - " 0\n" + - " error\n" + - " ")); - VerifyResult r = client.verify(new VerifyRequest( - "447700900999", - "TestBrand", - "15555215554", 6, Locale.US)); - assertEquals(VerifyResult.STATUS_OK, r.getStatus()); - } - - @Test - public void testVerifyHttpError() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(500, "\n" + - " \n" + - " not-really-a-request-id\n" + - " 0\n" + - " error\n" + - " ")); - try { - client.verify( - "447700900999", - "TestBrand", - "15555215554", 6, Locale.US); - fail("An IOException should be thrown if an HTTP 500 response is received."); - } catch (IOException ioe) { - // This is expected - } - } - - @Test - public void testCheck() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - " \n" + - " verify-check-id\n" + - " 0\n" + - " 100.00\n" + - " EUR\n" + - " error\n" + - " ")); - - CheckResult c = client.check("verify-check-id", "1234", "my-ip-address"); - assertEquals(CheckResult.STATUS_OK, c.getStatus()); - } - - @Test - public void testCheckMissingParams() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - " \n" + - " verify-check-id\n" + - " 0\n" + - " 100.00\n" + - " EUR\n" + - " error\n" + - " ")); - - try { - client.check(null, null); - fail("Calling check with null destination should throw IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // This is expected - } - } - - @Test - public void testCheckError() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - " \n" + - " 6\n" + - " Something has gone terribly wrong!\n" + - " ")); - - CheckResult c = client.check("verify-check-id", "1234", "my-ip-address"); - assertEquals(CheckResult.STATUS_INVALID_REQUEST, c.getStatus()); - } - - @Test - public void testCheckInvalidResponse() throws Exception { - wrapper.setHttpClient(this.stubHttpClient( - 200, - "\n" + - "")); - - try { - client.check("verify-check-id", "1234", "my-ip-address"); - fail("Parsing an invalid response should raise NexmoResponseParseException"); - } catch (NexmoResponseParseException parseException) { - // This is expected - } - } - - @Test - public void testSearchSuccess() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - " \n" + - " not-a-search-request-id\n" + - " not-an-account-id\n" + - " 447700900999\n" + - " 447700900991\n" + - " 2014-03-04 10:11:12\n" + - " 2015-02-03 07:08:09\n" + - " 2012-01-02 03:04:05\n" + - " 2012-01-02 03:04:06\n" + - " \n" + - " \n" + - " 2012-01-02 03:04:05\n" + - " VALID\n" + - " code\n" + - " \n" + - " \n" + - " 2012-01-02 03:04:06\n" + - " VALID\n" + - " code\n" + - " \n" + - " \n" + - " price\n" + - " currency\n" + - " error\n" + - " SUCCESS\n" + - " ")); - - - SearchResult c = client.search("not-a-search-request-id"); - assertEquals(SearchResult.STATUS_OK, c.getStatus()); - assertEquals("not-a-search-request-id", c.getRequestId()); - assertEquals(SearchResult.VerificationStatus.SUCCESS, c.getVerificationStatus()); - assertEquals("447700900999", c.getNumber()); - assertEquals("447700900991", c.getSenderId()); - assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-03-04 10:11:12"), - c.getDateSubmitted()); - assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2015-02-03 07:08:09"), - c.getDateFinalized()); - assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2012-01-02 03:04:05"), - c.getFirstEventDate()); - assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2012-01-02 03:04:06"), - c.getLastEventDate()); - } - - @Test - public void testSearchError() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - "\n" + - " \n" + - " 101\n" + - " No response found\n" + - "")); - - SearchResult c = client.search("AAAAA"); - assertEquals(SearchResult.STATUS_NO_RESPONSE, c.getStatus()); - } - - @Test - public void testSearchFailed() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - "\n" + - " a-random-request-id\n" + - " account-id\n" + - " not-a-number\n" + - " verify\n" + - " 2016-10-19 11:18:56\n" + - " 2016-10-19 11:20:00\n" + - " \n" + - " \n" + - " 2016-10-19 11:20:00\n" + - " 1234\n" + - " INVALID\n" + - " \n" + - " \n" + - " \n" + - " 2016-10-19 11:19:54\n" + - " 1234\n" + - " INVALID\n" + - " \n" + - " \n" + - " \n" + - " 2016-10-19 11:19:58\n" + - " 1234\n" + - " INVALID\n" + - " \n" + - " \n" + - " \n" + - " 2016-10-19 11:18:56\n" + - " 2016-10-19 11:18:56\n" + - " 0\n" + - " EUR\n" + - " FAILED\n" + - "")); - - SearchResult c = client.search("a-random-request-id"); - assertEquals(SearchResult.STATUS_OK, c.getStatus()); - assertEquals("a-random-request-id", c.getRequestId()); - assertEquals(SearchResult.VerificationStatus.FAILED, c.getVerificationStatus()); - } - - @Test - public void testSearchExpired() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - "\n" + - " a-random-request-id\n" + - " account-id\n" + - " not-a-number\n" + - " verify\n" + - " 2016-10-19 11:25:19\n" + - " 2016-10-19 11:35:27\n" + - " \n" + - " 2016-10-19 11:25:19\n" + - " 2016-10-19 11:30:26\n" + - " 0\n" + - " EUR\n" + - " EXPIRED\n" + - "")); - - SearchResult c = client.search("a-random-request-id"); - assertEquals(SearchResult.STATUS_OK, c.getStatus()); - assertEquals("a-random-request-id", c.getRequestId()); - assertEquals(SearchResult.VerificationStatus.EXPIRED, c.getVerificationStatus()); - } - - @Test - public void testSearchInProgress() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - "\n" + - " a-random-request-id\n" + - " account-id\n" + - " not-a-number\n" + - " verify\n" + - " 2016-10-19 11:25:19\n" + - " \n" + - " \n" + - " 2016-10-19 11:25:19\n" + - " 2016-10-19 11:30:26\n" + - " 0.10000000\n" + - " EUR\n" + - " IN PROGRESS\n" + - "")); - SearchResult c = client.search("a-random-request-id"); - assertEquals(SearchResult.STATUS_OK, c.getStatus()); - assertEquals("a-random-request-id", c.getRequestId()); - assertEquals(SearchResult.VerificationStatus.IN_PROGRESS, c.getVerificationStatus()); - } - - @Test - public void testSearchWithWrongParams() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - "\n" + - " \n" + - " 6\n" + - " The Nexmo platform was unable to process this message for the following reason: Wrong parameters\n" + - "")); - SearchResult c = client.search("a-random-request-id"); - assertEquals(SearchResult.STATUS_INVALID_REQUEST, c.getStatus()); - } - - @Test - public void testSearchWithMultipleResults() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - "\n" + - " \n" + - " a-random-request-id\n" + - " abcde\n" + - " 447700900999\n" + - " verify\n" + - " 2016-10-21 15:41:02\n" + - " \n" + - " \n" + - " 2016-10-21 15:41:02\n" + - " 2016-10-21 15:43:07\n" + - " 0.10000000\n" + - " EUR\n" + - " IN PROGRESS\n" + - " \n" + - " \n" + - " another-random-request-id\n" + - " abcde\n" + - " 447700900991\n" + - " verify\n" + - " 2016-10-21 15:41:58\n" + - " \n" + - " \n" + - " 2016-10-21 15:41:58\n" + - " 2016-10-21 15:41:58\n" + - " 0.10000000\n" + - " EUR\n" + - " IN PROGRESS\n" + - " \n" + - "")); - SearchResult[] c = client.search("a-random-request-id", "another-random-request-id"); - assertEquals(SearchResult.STATUS_OK, c[0].getStatus()); - } - - @Test - public void testSearchDodgyDates() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - "\n" + - " a-random-request-id\n" + - " account-id\n" + - " not-a-number\n" + - " verify\n" + - " aaa\n" + - " ddd\n" + - " \n" + - " bbb\n" + - " ccc\n" + - " 0.10000000\n" + - " EUR\n" + - " SUCCESS\n" + - "")); - SearchResult c = client.search("a-random-request-id"); - assertEquals(SearchResult.STATUS_OK, c.getStatus()); - assertEquals("a-random-request-id", c.getRequestId()); - assertEquals(SearchResult.VerificationStatus.SUCCESS, c.getVerificationStatus()); - } - - @Test - public void testSearchHttpError() throws Exception { - wrapper.setHttpClient(this.stubHttpClient(200, "\n" + - "")); - try { - client.search("a-random-request-id"); - fail("Invalid content should raise NexmoResponseParseException"); - } catch (NexmoResponseParseException e) { - // This is expected - } - } - - @Test - public void testLineType() { - VerifyRequest.LineType all = VerifyRequest.LineType.ALL; - assertEquals("ALL", all.toString()); - } -} diff --git a/src/test/java/com/nexmo/client/verify/VerifyClientVerifyControlEndpointTest.java b/src/test/java/com/nexmo/client/verify/VerifyClientVerifyControlEndpointTest.java new file mode 100644 index 000000000..caeceb2cd --- /dev/null +++ b/src/test/java/com/nexmo/client/verify/VerifyClientVerifyControlEndpointTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class VerifyClientVerifyControlEndpointTest extends ClientTest { + + @Before + public void setUp() { + client = new VerifyClient(wrapper); + } + + @Test + public void testAdvanceVerification() throws Exception { + String json = "{\n" + " \"status\":\"0\",\n" + " \"command\":\"trigger_next_event\"\n" + "}"; + wrapper.setHttpClient(this.stubHttpClient(200, json)); + + ControlResponse response = client.advanceVerification("a-request-id"); + Assert.assertEquals("0", response.getStatus()); + Assert.assertEquals(VerifyControlCommand.TRIGGER_NEXT_EVENT, response.getCommand()); + } + + @Test + public void testCancelVerification() throws Exception { + String json = "{\n" + " \"status\":\"0\",\n" + " \"command\":\"cancel\"\n" + "}"; + wrapper.setHttpClient(this.stubHttpClient(200, json)); + + ControlResponse response = client.cancelVerification("a-request-id"); + Assert.assertEquals("0", response.getStatus()); + Assert.assertEquals(VerifyControlCommand.CANCEL, response.getCommand()); + } +} diff --git a/src/test/java/com/nexmo/client/verify/VerifyClientVerifyEndpointTest.java b/src/test/java/com/nexmo/client/verify/VerifyClientVerifyEndpointTest.java new file mode 100644 index 000000000..8cdd139f9 --- /dev/null +++ b/src/test/java/com/nexmo/client/verify/VerifyClientVerifyEndpointTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.Locale; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class VerifyClientVerifyEndpointTest extends ClientTest { + + @Before + public void setUp() { + client = new VerifyClient(wrapper); + } + + @Test + public void testVerifyWithNumberBrandFromLengthLocaleLineType() throws Exception { + wrapper.setHttpClient(this.stubHttpClient(200, + "{\n" + " \"request_id\": \"not-really-a-request-id\",\n" + " \"status\": 0,\n" + " \"error_text\": \"error\"\n" + "}")); + VerifyResult r = client.verify("447700900999", "TestBrand", "15555215554", 6, Locale.US, VerifyRequest.LineType.MOBILE); + assertEquals(VerifyResult.STATUS_OK, r.getStatus()); + } + + @Test + public void testVerifyWithNumberBrandFromLengthLocale() throws Exception { + wrapper.setHttpClient(this.stubHttpClient(200, + "{\n" + " \"request_id\": \"not-really-a-request-id\",\n" + " \"status\": 0,\n" + " \"error_text\": \"error\"\n" + "}")); + VerifyResult r = client.verify("447700900999", "TestBrand", "15555215554", 6, Locale.US); + assertEquals(VerifyResult.STATUS_OK, r.getStatus()); + } + + @Test + public void testVerifyWithNumberBrandFrom() throws Exception { + wrapper.setHttpClient(this.stubHttpClient(200, + "{\n" + " \"request_id\": \"not-really-a-request-id\",\n" + " \"status\": 0,\n" + " \"error_text\": \"error\"\n" + "}")); + VerifyResult r = client.verify("447700900999", "TestBrand", "15555215554"); + assertEquals(VerifyResult.STATUS_OK, r.getStatus()); + } + + @Test + public void testVerifyWithNumberBrand() throws Exception { + wrapper.setHttpClient(this.stubHttpClient(200, + "{\n" + " \"request_id\": \"not-really-a-request-id\",\n" + " \"status\": 0,\n" + " \"error_text\": \"error\"\n" + "}")); + VerifyResult r = client.verify("447700900999", "TestBrand"); + assertEquals(VerifyResult.STATUS_OK, r.getStatus()); + } + + @Test + public void testVerifyWithRequestObject() throws Exception { + wrapper.setHttpClient(this.stubHttpClient(200, + "{\n" + " \"request_id\": \"not-really-a-request-id\",\n" + " \"status\": 0,\n" + " \"error_text\": \"error\"\n" + "}")); + VerifyResult r = client.verify(new VerifyRequest("447700900999", "TestBrand", "15555215554", 6, Locale.US)); + assertEquals(VerifyResult.STATUS_OK, r.getStatus()); + } + + @Test + public void testVerifyHttpError() throws Exception { + wrapper.setHttpClient(this.stubHttpClient(500, + "{\n" + " \"request_id\": \"not-really-a-request-id\",\n" + " \"status\": 0,\n" + " \"error_text\": \"error\"\n" + "}")); + try { + client.verify("447700900999", "TestBrand", "15555215554", 6, Locale.US); + fail("An IOException should be thrown if an HTTP 500 response is received."); + } catch (IOException ioe) { + // This is expected + } + } + + @Test + public void testVerifyWithNonNumericStatus() throws Exception { + wrapper.setHttpClient(this.stubHttpClient(200, + "{\n" + " \"request_id\": \"not-really-a-request-id\",\n" + " \"status\": \"test\",\n" + " \"error_text\": \"error\"\n" + "}")); + VerifyResult r = client.verify(new VerifyRequest("447700900999", "TestBrand", "15555215554", 6, Locale.US)); + assertEquals(VerifyResult.STATUS_INTERNAL_ERROR, r.getStatus()); + } +} diff --git a/src/test/java/com/nexmo/client/verify/VerifyDetailsTest.java b/src/test/java/com/nexmo/client/verify/VerifyDetailsTest.java new file mode 100644 index 000000000..46394397f --- /dev/null +++ b/src/test/java/com/nexmo/client/verify/VerifyDetailsTest.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011-2018 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import org.junit.Assert; +import org.junit.Test; + +public class VerifyDetailsTest { + @Test + public void testVerifyDetailsStatusFromString() { + Assert.assertEquals(VerifyDetails.Status.INVALID, VerifyDetails.Status.fromString("101")); + + } +} diff --git a/src/test/java/com/nexmo/client/verify/VerifyMethodTest.java b/src/test/java/com/nexmo/client/verify/VerifyMethodTest.java new file mode 100644 index 000000000..2da04d420 --- /dev/null +++ b/src/test/java/com/nexmo/client/verify/VerifyMethodTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011-2017 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.verify; + +import org.apache.http.NameValuePair; +import org.apache.http.client.methods.RequestBuilder; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; +import java.util.Locale; + +public class VerifyMethodTest extends MethodTest { + + @Before + public void setUp() { + method = new VerifyMethod(null); + } + + @Test + public void testConstructVerifyParams() throws Exception { + VerifyRequest verifyRequest = new VerifyRequest("4477990090090", + "Brand.com", + "Your friend", + 4, + new Locale("en", "GB"), + VerifyRequest.LineType.MOBILE); + + RequestBuilder request = method.makeRequest(verifyRequest); + List params = request.getParameters(); + + assertContainsParam(params, "number", "4477990090090"); + assertContainsParam(params, "brand", "Brand.com"); + assertContainsParam(params, "sender_id", "Your friend"); + assertContainsParam(params, "code_length", "4"); + assertContainsParam(params, "lg", "en-gb"); + assertContainsParam(params, "require_type", "MOBILE"); + } + + @Test + public void testConstructVerifyParamsMissingValues() throws Exception { + VerifyRequest verifyRequest = new VerifyRequest("4477990090090", "Brand.com", null, 0, null, null); + + RequestBuilder request = method.makeRequest(verifyRequest); + List params = request.getParameters(); + assertContainsParam(params, "number", "4477990090090"); + assertContainsParam(params, "brand", "Brand.com"); + assertParamMissing(params, "code_length"); + assertParamMissing(params, "lg"); + assertParamMissing(params, "sender_id"); + assertParamMissing(params, "require_type"); + assertParamMissing(params, "country"); + assertParamMissing(params, "pin_expiry"); + assertParamMissing(params, "next_event_wait"); + } + + @Test + public void testConstructVerifyParamsWithOptionalValues() throws Exception { + VerifyRequest verifyRequest = new VerifyRequest("4477990090090", "Brand.com"); + verifyRequest.setFrom("VERIFICATION"); + verifyRequest.setLength(6); + verifyRequest.setLocale(new Locale("en", "gb")); + verifyRequest.setType(VerifyRequest.LineType.LANDLINE); + verifyRequest.setCountry("ZZ"); + verifyRequest.setPinExpiry(60); + verifyRequest.setNextEventWait(90); + + RequestBuilder request = method.makeRequest(verifyRequest); + List params = request.getParameters(); + assertContainsParam(params, "number", "4477990090090"); + assertContainsParam(params, "brand", "Brand.com"); + + assertContainsParam(params, "code_length", "6"); + assertContainsParam(params, "sender_id", "VERIFICATION"); + assertContainsParam(params, "lg", "en-gb"); + assertContainsParam(params, "require_type", "LANDLINE"); + assertContainsParam(params, "country", "ZZ"); + assertContainsParam(params, "pin_expiry", "60"); + assertContainsParam(params, "next_event_wait", "90"); + + } +} diff --git a/src/test/java/com/nexmo/client/verify/endpoints/SearchEndpointTest.java b/src/test/java/com/nexmo/client/verify/endpoints/SearchEndpointTest.java index d03e7c667..c9e81f7ac 100644 --- a/src/test/java/com/nexmo/client/verify/endpoints/SearchEndpointTest.java +++ b/src/test/java/com/nexmo/client/verify/endpoints/SearchEndpointTest.java @@ -23,17 +23,22 @@ import com.nexmo.client.NexmoResponseParseException; +import com.nexmo.client.TestUtils; +import com.nexmo.client.verify.SearchRequest; import com.nexmo.client.verify.SearchResult; +import org.apache.http.client.methods.RequestBuilder; import org.junit.Before; import org.junit.Test; import javax.xml.parsers.ParserConfigurationException; import java.util.GregorianCalendar; +import java.util.List; +import java.util.Map; import static com.nexmo.client.TestUtils.test429; import static junit.framework.Assert.fail; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.*; public class SearchEndpointTest { @@ -283,6 +288,31 @@ public void testParseCheckXmlNodeUnrecognizedElement() throws Exception { assertEquals(new GregorianCalendar(2016, 9, 19, 11, 20, 0).getTime(), rs[0].getChecks().get(0).getDate()); } + @Test + public void testMakeRequestWithOneId() throws Exception { + RequestBuilder builder = client.makeRequest(new SearchRequest("1")); + assertEquals("POST", builder.getMethod()); + Map> params = TestUtils.makeFullParameterMap(builder.getParameters()); + assertThat(params.size(), equalTo(1)); + List ids = params.get("request_id"); + assertNotNull(ids); + assertEquals(1, ids.size()); + assertEquals("1", ids.get(0)); + } + + @Test + public void testMakeRequestWithMultipleIds() throws Exception { + RequestBuilder builder = client.makeRequest(new SearchRequest("1", "2")); + assertEquals("POST", builder.getMethod()); + Map> params = TestUtils.makeFullParameterMap(builder.getParameters()); + assertThat(params.size(), equalTo(1)); + List ids = params.get("request_ids"); + assertNotNull(ids); + assertEquals(2, ids.size()); + assertEquals("1", ids.get(0)); + assertEquals("2", ids.get(1)); + } + @Test public void testRequestThrottleResponse() throws Exception { test429(new SearchEndpoint(null));