Listed below is a method I am trying to test using Junit and Mockito
Java Code
public String getAuthenticationService() {
Authentication endpoint;
String token = "";
try {
URL wsdlURL = new URL(authenticationURL);
SoapService service = new SoapService(wsdlURL,
new QName("SomeQName",
"SoapService"));
endpoint = service.getAuthenticationPort();
token = endpoint.authenticate(username, password);
} catch (Exception e) {
throw new GenericException(
"OpenText AuthenticationService not working Error is "
+ e.toString());
}
return token;
}
Junit method
public void testGetAuthenticationService()
throws AuthenticationException_Exception {
AuthenticationService mockService = Mockito
.mock(AuthenticationService.class);
Authentication mockEndpoint = Mockito.mock(Authentication.class);
Mockito.when(mockService.getAuthenticationPort()).thenReturn(
mockEndpoint);
Mockito.when(mockEndpoint.authenticate(username, password)).thenReturn(
token);
}
When I run the Junit test case the endpoint.authenticate tries to connect to the actaul soap service, and the method stubbing is not working, what am I doing wrong here
Your mockService seems to be a good replacement for your SoapService, but you aren't giving yourself an opportunity to refer to it in your code. Your test calls the code, which calls the SoapService constructor, so you get a real service. Consider this refactor:
public String getAuthenticationService() {
try {
URL wsdlURL = new URL(authenticationURL);
SoapService service = new SoapService(wsdlURL,
new QName("SomeQName", "SoapService"));
return getAuthenticationService(service);
} catch (Exception e) {
throw new GenericException(
"OpenText AuthenticationService not working Error is "
+ e.toString());
}
}
/** package-private for testing - call this from your test instead */
String getAuthenticationService(AuthenticationService service) {
try {
Authentication endpoint = service.getAuthenticationPort();
String token = endpoint.authenticate(username, password);
return token;
} catch (Exception e) {
throw new GenericException(
"OpenText AuthenticationService not working Error is "
+ e.toString());
}
}
Now you can pass your mockService into getAuthenticationService(service) and your code will use your mock rather than the SoapService it creates inline.
As as alternative, you can also give yourself a seam by wrapping the SoapService constructor:
/** overridden in tests */
protected AuthenticationService createSoapService(String url, QName qname) {
return new SoapService(url, qname);
}
public String getAuthenticationService() {
try {
URL wsdlURL = new URL(authenticationURL);
SoapService service = createSoapService(wsdlURL,
new QName("SomeQName", "SoapService"));
Authentication endpoint = service.getAuthenticationPort();
String token = endpoint.authenticate(username, password);
return token;
} catch (Exception e) {
throw new GenericException(
"OpenText AuthenticationService not working Error is "
+ e.toString());
}
}
// in your test:
SystemUnderTest yourSystem = new YourSystem() {
#Override protected AuthenticationService createAuthenticationService(
String url, QName qname) {
return mockService;
}
}
Related
I'm new to the quarkus framework where I'm writing rabbitmq-client library based on quarkur framework. I'm using io.quarkiverse.rabbitmqclient.RabbitMQClient.
I need to write JUnit for basic send and consume operations, please help me with how can I write junit and mock RabbitMQClient. I'm using the below code to send and consume message.
#ApplicationScoped
public class RabbitMQProducerAdapterImpl extends RabbitMQCongiguration implements RabbitMQProducerAdapter {
#Override
public void sendMessage(String exchange, String routingKey, String messagePayload) throws IOException {
setUpConnectionAndChannel();
channel.basicPublish(exchange, routingKey, null, messagePayload.getBytes(StandardCharsets.UTF_8));
Log.info("message sent succefully: " + messagePayload);
}
}
Here is the RabbitMQCongiguration
#ApplicationScoped
public class RabbitMQCongiguration {
#Inject
private RabbitMQClient rabbitClient;
protected Channel channel;
protected void setUpConnectionAndChannel() {
try {
// create a connection
Connection connection = rabbitClient.connect();
// create a channel
channel = connection.createChannel();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
protected void setupQueueInDirectExchange(String exchangeName, String routingKey, String queueName,
boolean createExchangeQueues) throws IOException {
setUpConnectionAndChannel();
if (createExchangeQueues) {
this.channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT, true, false, false, null);
// declaring a queue for this channel. If queue does not exist,
// it will be created on the server. this line not needed if queue already
// present
this.channel.queueDeclare(queueName, true, false, false, null);
}
// Bind Routing Key to Exchange
this.channel.queueBind(queueName, exchangeName, routingKey);
}
}
Below is the class for consumer
#ApplicationScoped
public class RabbitMQConsumerAdapterImpl extends RabbitMQCongiguration implements RabbitMQConsumerAdapter, Runnable {
private String queueName;
private MessageProcessor messageProcessor;
#Override
public void consumeMessage(String exchange, String queueName, String routingKey,
MessageProcessor messageProcessor) throws IOException {
Log.info("starting consumer...");
try {
this.queueName = queueName;
this.messageProcessor = messageProcessor;
Log.info("setting up rabbitMQPrefetchCountConfig");
setupQueueInDirectExchange(exchange, routingKey, queueName, false);
Thread consumerThread = new Thread(this);
consumerThread.start();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
#Override
public void run() {
try {
// start consuming messages. Auto acknowledge messages.
Log.info("Start consuming messages from thread...");
channel.basicConsume(this.queueName, false, (Consumer) new DefaultConsumer(channel) {
#Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String msgPayload = null;
if (body == null || body.length == 0) {
Log.warn("Invalid Message Body - Consumer Tag : " + consumerTag + ", Message DeliveryTag : "
+ envelope.getDeliveryTag());
channel.basicReject(envelope.getDeliveryTag(), false);
} else {
msgPayload = new String(body);
try {
JsonParser.parseString(msgPayload);
} catch (JsonSyntaxException ex) {
Log.error(msgPayload + " is not a valid json, Reason - ", ex);
channel.basicReject(envelope.getDeliveryTag(), false);
Log.warn("Rejected the current payload.");
return;
}
messageProcessor.processMessage(msgPayload);
channel.basicAck(envelope.getDeliveryTag(), false);
}
// just print the received message.
Log.info("Received: " + new String(body, StandardCharsets.UTF_8));
}
});
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
#ApplicationScoped
public class MessageProcessorImpl implements MessageProcessor{
#Override
public void processMessage(String messagePayload) {
Log.info("message consumed: " + messagePayload);
}
}
I need to make mutiple rest api calls for fetching instance, volume and vnic details. Can i reuse the same signer object created for signing the other calls?
Signer object method
public RequestSigner getSigner(Properties properties, String pemFilePath, String apiKey) {
InputStream privateKeyStream;
PrivateKey privateKey = null;
try {
privateKeyStream = Files.newInputStream(Paths.get(pemFilePath));
privateKey = PEM.readPrivateKey(privateKeyStream);
} catch (InvalidKeySpecException e) {
// throw new RuntimeException("Invalid format for private key");
properties.setProperty(OracleCloudConstants.CUSTOM_DC_ERROR,
FormatUtil.getString("am.webclient.oraclecloud.customdc.invalidformat"));
AMLog.debug("OracleCloudDataCollector::CheckAuthentication()::Invalid format for private key::"
+ e.getMessage());
e.printStackTrace();
} catch (IOException e) {
properties.setProperty(OracleCloudConstants.CUSTOM_DC_ERROR,
FormatUtil.getString("am.webclient.oraclecloud.customdc.failedload"));
AMLog.debug(
"OracleCloudDataCollector::CheckAuthentication()::Failed to load private key::" + e.getMessage()); //No I18N
e.printStackTrace();
// throw new RuntimeException("Failed to load private key");
}
RequestSigner signer = null;
if (privateKey != null) {
signer = new RequestSigner(apiKey, privateKey);
}
return signer;
}
One signer object may be used to sign multiple requests. In fact, the SDK implementation does this too.
It is not clear what version of the SDK you are using. In version 1.5.7 (the most recent at the time of writing), com.oracle.bmc.http.signing.RequestSigner (https://github.com/oracle/oci-java-sdk/blob/master/bmc-common/src/main/java/com/oracle/bmc/http/signing/RequestSigner.java#L16) is an interface which cannot be new’ed as per the snippet above.
I am trying to retrieve the data from my account by connecting to the Fitbit API. I have my app returning the Access Token I need to make the HTTP Request that returns the JSON but anything that I try, it returns an error. I have two Activities - MainActivity.java and TestActivity.java
In MainActivity.java I am simply opening a Chrome Custom Tab to direct the user to the Fitbit Authentication(Login) page. Once the user enters their details they are redirected back to the TestActivity.java as per the Fitbit API documentation. I am then printing the Acess Token which proves to me that it is connecting to the API.
What I need to do it make an HTTP request to returns the sleep data in JSON format. I know how to do it in Java but I am unsure how to do it in Android using the AsyncTask way. Any help is appreciated!
public class TestActivity extends AppCompatActivity {
String string;
String token;
#Override
protected void onNewIntent(Intent intent) {
string = intent.getDataString();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
onNewIntent(getIntent());
//Toast.makeText(TestActivity.this, string , Toast.LENGTH_LONG).show();
Log.e("TAG", string);
Log.e("TAG", string.substring(string.indexOf("&access_token")+14));
token = string.substring(string.indexOf("&access_token")+14);
Context context = getApplicationContext();
Toast toast = Toast.makeText(context,"Access Token: "+ token,Toast.LENGTH_LONG );
Log.i("TAG", "Access Token: "+ token);
new JSONTask().execute("https://api.fitbit.com/1.2/user/-/sleep/date/2018-01-30.json");
}
public class JSONTask extends AsyncTask<String,String,String>
{
#Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try
{
URL url = new URL(params[0]);
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + token);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while((line = reader.readLine()) !=null)
{
buffer.append(line);
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s)
{
super.onPostExecute(s);
Log.i("TAG", s);
}
}
I ended up having a breakthrough with this question. I figured out that I was extracting the Access Token incorrectly. So, instead of doing the following:
token = string.substring(string.indexOf("&access_token")+14);
I instead had to use this:
token = string.substring(string.indexOf("&access_token")+36,308);
The App was then able to make the necessary HTTP request to the Fitbit API which returned the JSON data that I needed.
One order of codes should be changed for preventing FC.
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + token);
This is my custom middleware class for exception. I want to handle global exceptions.
public class CustomExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public CustomExceptionMiddleware(RequestDelegate next, ILogger<CustomExceptionMiddleware> logger)
{
_logger = logger;
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
try
{
await _next(httpContext);
}catch (Exception e)
{
await HandleExceptionAsync(httpContext, e);
}
}
private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var code = HttpStatusCode.InternalServerError;
if(exception is KeyNotFoundException)
{
code = HttpStatusCode.NotFound;
_logger.LogInformation("Exception happend. Exception type: " + exception.GetType().ToString(), new object[0]);
}
else if (exception is UnauthorizedAccessException)
{
code = HttpStatusCode.Unauthorized;
_logger.LogInformation("Exception happend. Exception type: " + exception.GetType().ToString(), new object[0]);
}
else
{
code = HttpStatusCode.BadRequest;
_logger.LogInformation("Exception happend. Bad request ", new object[0]);
}
var result = JsonConvert.SerializeObject(new { error = exception.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int) code;
//context.ExceptionHandled = true;
return context.Response.WriteAsync(result);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CustomExceptionMiddlewareExtensions
{
public static IApplicationBuilder UseCustomExceptionMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CustomExceptionMiddleware>();
}
}
I add in my Startup.cs
app.UseCustomExceptionMiddleware();
I don't get logging information that I'm trying to log, and it doesn't throw any exception. What am I missing? Should I throw an exception in a controller class?
I have a jersey server. When I attempt to handle a POST from AngularJS (1.2.16), it is generating an error (below). When I use a java jersey client to post the message, the jersey server handles it fine.
SEVERE: null
java.lang.IllegalAccessException: Class com.sun.jersey.server.wadl.generators.WadlGeneratorJAXBGrammarGenerator$8 can not access a member of class javax.ws.rs.core.Response with modifiers "protected"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:101)
at java.lang.Class.newInstance(Class.java:427)
this is the jersey post server:
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/post")
public Response verifyAccount( Owner owner ,
#Context HttpServletRequest req)
{
LOGGER.debug("verify account " +owner.toString() );
HashMap<String, Object> results = new HashMap<String, Object>();
boolean verified = AccountManagement.verifyAccount(owner.getEmail(),
owner.getPwd());
if (verified) {
results.put("status", "OK");
} else {
results.put("status", "Fail");
}
return Response.status(200).entity(results)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
.build();
}
This is the jersey java client:
public class JsonClient {
public static void main(String[] args) {
try {
Client client = Client.create();
WebResource webResource = client
.resource("http://myserver.com:8080/restws/accountcheck/post");
String input = "{\"email\":\"fubar#gmail.com\",\"pwd\":\"hello\"}";
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class, input);
int code = response.getStatus();
if (code != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output);
} catch (Exception e) {
System.out.println("exception caught.");
e.printStackTrace();
}
}
}
This is the AngularJS code to post:
$scope.ownerLoginAction = function() {
var dataObject = {
"email": $scope.myId,
"pwd": $scope.mypassword
};
var request = $http({
method: "post",
url: hostName+'/restws/accountcheck/post',
params: {
action:"verify"
},
data: dataObject
});
request.then (function(response) {
console.log(response.data);
},function(errResponse) {
console.error('Error');
} )
}
Anybody know why I cannot seem to post either with JSON from AngularJS? Is the server not set up right? Or the angularJS client is not right?
When i put a TCPMON in between, I noticed that the angularJS attempt sent an OPTION. Is that a clue that I dont understand?