Junit HTTP request test with Apache SS Workbook? - spring

My restful service accepts a file argument, the contents of which is an Apache SS (XSSF) Workbook. The method iterates through the cells of the Workbook and takes various actions, based on the values of the cells.
I've conceived a Junit test where I instantiate and populate an Apache SS Workbook, add it to a 'file'object and then pass the 'file' object to the method under test. The primary problem that I'm having is how to instantiate the 'file' object using the Workbook object.
Following is a sample of the method under test (omitting details unrelated to the Workbook), followed by a pseudo-code example of what I'm trying to do:
/* Method under test */
public Object workbookProcessing(HttpServletRequest request) {
List<Part> workbookParts = request.getParts().collect(Collectors.toList());
for (Part workbookPart : workbookParts) {
InputStream workbookContent = workbookPart.getInputStream();
Workbook workbook = WorkbookFactory.create(workbookContent);
// ...
}
/* Junit test pseudo-code */
public void testWorkbookProcessing() {
RestfulService rs = new RestfulService();
Workbook wb = WorkbookFactory.create(true) // Create XSSF workbook
CreationHelper createHelper = wb.getCreationHelper();
Sheet sheet = wb.createSheet("Sheet 1");
Row row = sheet.createRow(0);
row.createCell(0).setCellValue(createHelper.createRichTextString("Row 1 Cell 1"));
row.createCell(1).setCellValue(12345678);
// ...
HttpServletRequest request = new HttpServletRequest(); // Create HttpServletRequest
// Create InputStream, using above Workbook <- Help!
// Create Part object from InputStream <- Help!
request.addPart(inputStream); // Add Part object to request
ResponseEntity re = rs.workbookProcessing(request);
assertEquals(200, re.getStatusCodeValue());
}
Alternatively, if there is a way to Mock the workbook and it's cell values, I'm happy to do that as well.

After quite a bit of research, trial and error and combining techniques, here is how I was able to write a working Junit test to submit a multi-part HTTP request which contained an Apache SS workbook object.
// Working Junit test code:
#Test
public void testWorkbookProcessing() {
RestfulService rs = new RestfulService();
Workbook wb = WorkbookFactory.create(true) // Create XSSF workbook
CreationHelper createHelper = wb.getCreationHelper();
Sheet sheet = wb.createSheet("Sheet 1");
Row row = sheet.createRow(0); // First row of sheet
row.createCell(0).setCellValue(createHelper.createRichTextString("Row 1 Cell 1"));
row.createCell(1).setCellValue(12345678);
// ...
// This is the code to create the multi-part content
ByteArrayOutputStream baos = New ByteArrayOutputStream();
wb.write(baos); // Write workbook to output stream
byte[] bytes = baos.toByteArray(); // Convert output stream to byte array
MockPart part = new MockPart("file", "test_filename.xlsx", bytes); // Add byte array to mocked Part object
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
request.setMethod(RequestMethod.POST.name());
request.addHeader("Content-Type", "multipart/form-data");
request.addParameter("id", "12345678"); // optional
request.addPart(part); // Add Part to request
ResponseEntity re = rs.workbookProcessing(request);
assertEquals(202, re.getStatusCodeValue());
}
Refinements/comments/suggestions appreciated.

Related

Junit Mock responses are not returned in case of loop

I have some problem with Junit testcases , below is the case :
I have below method loop inside the void method :
List<Message> msgList = service1.getList();
for (Message message : msgList) {
StorageObject object = cloudStorage.readObject(anotherObject);
InputStream inputStream = object .getObjectContent();
String text = IOUtils.toString(inputStream);
// text to object mapping
// third party service call
}
in my unit testcase, i have done below mocking :
service1.getList() to return the list of 2 message objects
mock storageobject and provided it some mock values as below
StorageObject stObject = new StorageObject();
stObject.setObjectContent(new StorageObjectInputStream(new ByteArrayInputStream( "Hi, This is a dummy and it would be json format".getBytes()), null));
Mockito.when(cloudStorage.readObject(Mockito.any())).thenReturn(stObject );
When i execute the testcase, for first iteration it works perfectly and method execution returns the correct result but for second iteration inputStream doesn't have the valid values so text it returned as null, why so? Any help would be appreciated.
Your InputStream is being emptied after the first read.
You need to recreate it for each iteration.
You can configure mockito to return a newly created InputSteam mock object for each consequent call.
Mockito.when(cloudStorage.readObject(Mockito.any())).thenAnswer(new Answer() {
Object answer(InvocationOnMock invocation) {
StorageObject stObject = new StorageObject();
stObject.setObjectContent(new StorageObjectInputStream(new ByteArrayInputStream("Hi, This is a dummy and it would be json format".getBytes()), null));
return stObject;
}
});

How to satisfy multiple byte ranges when using PushStreamContent in WebAPI?

I need to use PushStreamContent because of the source of my data (effectively have to concatenate blobs), but I also have to support requests for multiple byte ranges (arbitrary ranges not aligned to the stored blobs). What is not clear to me is if I can use PushStreamContent to generate a multipart/byteranges response, if each range needs to be separated in the response, and if so, how to do it, and how it relates to the chunked transfer encoding which PushStreamContent invokes.
You can do it using MultipartContent like this:
public class MyRangeController : ApiController
{
[HttpGet]
public HttpResponseMessage Get()
{
// Create a multi-part content object for the response; note that per RFC spec, subtype must be "byteranges"
// Note that the content type of the over-all response will be "multipart/byteranges"
// We choose to use a GUID string for the separator; it could be anything suitable.
var multipartContent = new MultipartContent("byteranges", Guid.NewGuid().ToString("D"));
// Create the response object and set its content
var response = new HttpResponseMessage(HttpStatusCode.PartialContent) { Content = multipartContent };
foreach (var rangeItemHeaderValue in Request.Headers.Range.Ranges)
{
// Create PushStreamContent object for our current byte range...
var pushStreamContent = new PushStreamContent((stream1, content, arg3) =>
{
// Write to stream1
stream1.Close();
});
// We need to add certain headers to each part of the response
pushStreamContent.Headers.ContentRange = new ContentRangeHeaderValue(rangeItemHeaderValue.From.Value, rangeItemHeaderValue.To.Value, /* total size of the resource */);
pushStreamContent.Headers.ContentType = new MediaTypeHeaderValue(/* Set a content type for each part of the response */);
// Add the part to the multi-part content response
multipartContent.Add(pushStreamContent);
}
return response;
}
}

Unable to insert dynamic object to Elastic Search using NEST

I am creating a dynamic object. I assign the values via IDictionary. Add the collections of the IDictionary to the object. Then I add the dynamic object to Elastic Search using NEST code. It throws me stackoverflow exception."An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll"
Here is what I have tried.
var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(node,defaultIndex: "test-index");
var client = new ElasticClient(settings);
try
{
dynamic x = new ExpandoObject();
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("NewProp", "test1");
dic.Add("NewProp3", "test1");
x = dic;
var index3 = client.Index(x);
}
catch (Exception ex)
{
string j = ex.StackTrace;
}
I need to create an index in ElasticSearch, using a dynamic object, because I will be having an excel work book consisting of over 300 worksheet, and each and every sheet will be named as type, and the contents inside the worksheet will be the _source.
In the above example 'x' the dynamic object created is the name of the worksheet, and the values added into the dictionary are the rows and columns of excel sheet.
Where am I going wrong.
Regards,
Hema
I belive you can skip ExpandoObject and just index Dictionary<string, object>().
var dictionary = new Dictionary<string, object>();
dictionary.Add("NewProp", "test1");
dictionary.Add("NewProp3", "test1");
client.Index(dictionary);

How to convert from Java to Xamarin C#

Can someone help me convert the following from Java to C# (Xamarin)?
I tried a couple of different ways, but I cannot get it to work.
The code is:
HttpPost post = new HttpPost(url);
// Break out all extra HTTP header lines and add it to the HttpPost object
for (String line : contentType.replace("\r", "\n").split("\n")) {
if (line.length() > 0 && line.contains(":")) {
String[] parts = line.split(":", 2);
if (parts.length == 2) {
post.addHeader(parts[0].trim(), parts[1].trim());
}
}
}
// Create a byte array entity for the POST data, the content
// type here is only used for the postEntity object
ByteArrayEntity postEntity = new ByteArrayEntity(challenge);
postEntity.setContentType("application/octet-stream");
post.setEntity(postEntity);
// Create a HttpClient and execute the HttpPost filled out above
HttpClient client = new DefaultHttpClient();
HttpResponse httpResponse = client.execute(post);
// Get the response entity out of the response
HttpEntity entity = httpResponse.getEntity();
If you are stuck with
post.SetEntity(postEntity);
then it converts to:
ByteArrayEntity postEntity = new ByteArrayEntity(challenge);
postEntity.SetContentType("application/octet-stream");
post.Entity = postEntity;
When converting to Java from C# you mostly have to change the property names to start with upperCase and then if you get stuck on certain objects I would look check out the Xamarin API Docs, HttpPost class linked here.

Google SpreadSheet Api, Putting List-Based Feeds Which Starts on Specific Cell

As seen as Google Api, i can easily put my data into a spreadsheet as below :
namespace MySpreadsheetIntegration
{
class Program
{
static void Main(string[] args)
{
SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");
// TODO: Authorize the service object for a specific user (see other sections)
// Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
SpreadsheetQuery query = new SpreadsheetQuery();
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no spreadsheets, act accordingly.
}
// TODO: Choose a spreadsheet more intelligently based on your
// app's needs.
SpreadsheetEntry spreadsheet = (SpreadsheetEntry)feed.Entries[0];
Console.WriteLine(spreadsheet.Title.Text);
// Get the first worksheet of the first spreadsheet.
// TODO: Choose a worksheet more intelligently based on your
// app's needs.
WorksheetFeed wsFeed = spreadsheet.Worksheets;
WorksheetEntry worksheet = (WorksheetEntry)wsFeed.Entries[0];
// Define the URL to request the list feed of the worksheet.
AtomLink listFeedLink = worksheet.Links.FindService(GDataSpreadsheetsNameTable.ListRel, null);
// Fetch the list feed of the worksheet.
ListQuery listQuery = new ListQuery(listFeedLink.HRef.ToString());
ListFeed listFeed = service.Query(listQuery);
// Create a local representation of the new row.
ListEntry row = new ListEntry();
row.Elements.Add(new ListEntry.Custom() { LocalName = "firstname", Value = "Joe" });
row.Elements.Add(new ListEntry.Custom() { LocalName = "lastname", Value = "Smith" });
row.Elements.Add(new ListEntry.Custom() { LocalName = "age", Value = "26" });
row.Elements.Add(new ListEntry.Custom() { LocalName = "height", Value = "176" });
// Send the new row to the API for insertion.
service.Insert(listFeed, row);
}
}
}
If i wrote "firstname" into the A1 and "lastname" into the B1, this is working, but i want to start this function ie. F21.
I mean, my localname firstname is in the cell F21 and i want google api to put my data "JOE" into F22 cell and ...
How can i do that ?
Regards.
CellFeed will do that, but list feed is more like an SQL style database table.
Suggest you use CellFeed or update your data SQL style, in whole rows.
I gave up with list feed when I discovered how little control you have over the position of the data.
Good examples:
CellFeed
https://gdata-java-client.googlecode.com/svn-history/r51/trunk/java/sample/spreadsheet/cell/CellDemo.java
ListFeed
https://gdata-java-client.googlecode.com/svn-history/r51/trunk/java/sample/spreadsheet/list/ListDemo.java

Resources