smartrics/RestFixture — pull request #47 by AdamRoberts (2012-11-15 22:44:13+00:00)
Title: Download binary response & Ability to test a workflow that loops on a response

This should have been two separate pull requests, but I am new to GIT and I made a mistake that merged by separate changesets.

### Download Binary Response

This change requires the getRawBody() addition to the RestClient that was sent in a pull request, so this won't compile without those changes.

There is a new class **FileBodyTypeAdapter** that can be associated with any "Content Type", it will take the raw data of the response body and save it to the file specified. It will mark the response as a failure if the response was empty.

There is also a new method for all BodyTypeAdapter's to determine if they need the Raw Response or the Text response, and a small change in the RestFixture where it decides which response to process using the new method.

This example wiki markup will save the response from the downloadLink into the root of the FitNesse directory in a file called "TestSave.zip"
```
| smartrics.rest.fitnesse.fixture.RestFixtureConfig |
| restfixture.content.handlers.map | application/binary=FILE |

| smartrics.rest.fitnesse.fixture.RestFixture | http://${rest.server.hostname}:${rest.server.port} |
| GET | %downloadLink% | 200 | Content-Type : application/binary | TestSave.zip |
```

### Ability to test a workflow that loops on a response

This change is to allow us to test a workflow where the user starts a background process and then calls a status REST call repeatedly to check on the processing. Once the processing reaches 100% complete then there is a new link returned in the status JSON object and the user can continue.

This required several new classes:
1. **LoopUntilRestFixture** which extends RestFixture and adds a new row type of "LOOP"
2. **RowShiftWrapper** which is used by the LoopUntilRestFixture to hide the first 5 cells in the row and then pass the shifted row back the the existing RestFixture code for execution.
3. **LoopResultsCellFormatter** which aggregates the results of each loop execution so that the cells that are executed on each loop action won't get multiple results

To get these new classes to have similar output the the existing class I did have to refactor some code (especially Tools) to add additional method signatures.

Wiki Documentation (copied from javadoc)
```
| setMilliSecondsDelayPerLoop | long value for how long to sleep after each loop action, -1 disables sleeping, defaults to -1 |
| setMaxNumberOfLoops | integer value for when to kill the test if the until hasn't returned true, default value of 10 |
| setContinueIfLoopFails | boolean value, should the test continue if a loop action fails, defaults to false |

| LOOP | Until Status Code | Until Headers | Until Condition? | HTTP METHOD {GET, PUT, POST, ...} | uri | ?ret | ?headers | ?body |

Until Condition: the fixture will run the "HTTP METHOD" until this
returns true or a failure condition occurs. Failure conditions can be:
hit the max number of loops, failure of the "HTTP METHOD", or an
uncaught exception

If a loop until condition is blank then it will be ignored, if all loop
conditions are blank then it will loop until max number of loops is
reached (or failure of loop action).
```

Example Wiki markup:
```
| smartrics.rest.fitnesse.fixture.LoopUntilRestFixture | http://${rest.server.hostname}:${rest.server.port} |
| setMaxNumberOfLoops | 60 |
| setMilliSecondsDelayPerLoop | 500 |
| setContinueIfLoopFails | true |
| LOOP | 200 | Content-Type : application/json | jsonbody.canceled == false && jsonbody.percentComplete == 1.0 | GET | %statusLink% | 200 | Content-Type : application/json | jsonbody.canceled == false |
```

From the example, the REST call represented by:
`| GET | %statusLink% | 200 | Content-Type : application/json | jsonbody.canceled == false |`
will be called every 500 milliseconds until the response matches:
`| 200 | Content-Type : application/json | jsonbody.canceled == false && jsonbody.percentComplete == 1.0 |`
or it has been called 60 times (failure)