diff --git a/modules/functional-test/src/main/java/com/intuit/wasabi/tests/service/IntegrationExperiment.java b/modules/functional-test/src/main/java/com/intuit/wasabi/tests/service/IntegrationExperiment.java index 57c79b15c..936b0cb27 100644 --- a/modules/functional-test/src/main/java/com/intuit/wasabi/tests/service/IntegrationExperiment.java +++ b/modules/functional-test/src/main/java/com/intuit/wasabi/tests/service/IntegrationExperiment.java @@ -37,20 +37,26 @@ import java.lang.reflect.Field; import java.text.ParseException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; import static com.intuit.wasabi.tests.library.util.ModelAssert.assertEqualModelItems; import static org.slf4j.LoggerFactory.getLogger; /** * Tests the experiment functionality. - * + *

* Known Issues: * - The python test checked for the number of experiments, but since this could be run on production environments - * it does not feel right to check those numbers, as they might change by other accessors. - * + * it does not feel right to check those numbers, as they might change by other accessors. + *

* These transitions are tested: - * + *

* (row transitions to column) *

  * DR = DRAFT, R = RUNNING, P = PAUSED, DEL = DELETED, T = TERMINATED, I = INVALID
@@ -65,16 +71,15 @@
  * T  | b | b | b | b | b | b |
  * I  | x | x | x | x | x | x |
  * 
- * + *

* Table legend: *

- * */ public class IntegrationExperiment extends TestBase { @@ -177,15 +182,15 @@ public Object[][] invalidIdProvider() { // FIXME: jwtodd // new Object[]{"0", "Invalid identifier", HttpStatus.SC_INTERNAL_SERVER_ERROR}, new Object[]{"0", "com.intuit.wasabi.experimentobjects.exceptions.InvalidIdentifierException: Invalid experiment identifier \"0\"", HttpStatus.SC_INTERNAL_SERVER_ERROR}, - new Object[]{"../applications", "The server was unable to process the request", HttpStatus.SC_INTERNAL_SERVER_ERROR}, + new Object[]{"../applications", "The server was unable to process the request", HttpStatus.SC_NOT_FOUND}, }; } /** * Checks invalid experiment IDs for their error message and HTTP Status codes. * - * @param id the ID - * @param status the error message/status + * @param id the ID + * @param status the error message/status * @param httpStatus the HTTP status code */ @Test(dependsOnGroups = {"ping"}, dataProvider = "invalidIdProvider") @@ -260,10 +265,10 @@ public Object[][] badExperimentsPOST() { new Object[]{ExperimentFactory.createExperiment().setState(Constants.EXPERIMENT_STATE_DRAFT), "Unrecognized property \"state\"", HttpStatus.SC_BAD_REQUEST}, // FIXME: jwtodd // new Object[] { ExperimentFactory.createCompleteExperiment().setStartTime((String) null), "Repository error", HttpStatus.SC_INTERNAL_SERVER_ERROR }, - new Object[]{ExperimentFactory.createCompleteExperiment().setStartTime((String) null), "Could not create experiment \"NewExperiment[id=20533222-2a3f-459d-b6b6-5e05ad1104e3,label=SW50ZWdyVGVzdA_Experiment_146123290282853,applicationName=SW50ZWdyVGVzdA_1461232889078App_PRIMARY,startTime=,endTime=Thu Jun 02 10:01:42 UTC 2016,samplingPercent=1.0,description=A sample Experiment description.,rule=(salary < 10000) && (state = 'VA'),isPersonalizationEnabled=false,modelName=,modelVersion=,isRapidExperiment=false,userCap=0,creatorID="+userName+"]\"", HttpStatus.SC_INTERNAL_SERVER_ERROR}, + new Object[]{ExperimentFactory.createCompleteExperiment().setStartTime((String) null), "Could not create experiment \"NewExperiment[id=20533222-2a3f-459d-b6b6-5e05ad1104e3,label=SW50ZWdyVGVzdA_Experiment_146123290282853,applicationName=SW50ZWdyVGVzdA_1461232889078App_PRIMARY,startTime=,endTime=Thu Jun 02 10:01:42 UTC 2016,samplingPercent=1.0,description=A sample Experiment description.,rule=(salary < 10000) && (state = 'VA'),isPersonalizationEnabled=false,modelName=,modelVersion=,isRapidExperiment=false,userCap=0,creatorID=" + userName + "]\"", HttpStatus.SC_INTERNAL_SERVER_ERROR}, // FIXME: jwtodd // new Object[] { ExperimentFactory.createCompleteExperiment().setEndTime((String) null), "Repository error", HttpStatus.SC_INTERNAL_SERVER_ERROR }, - new Object[]{ExperimentFactory.createCompleteExperiment().setEndTime((String) null), "Could not create experiment \"NewExperiment[id=97daea3b-1523-43e7-8d7c-d7eba2c18ff5,label=SW50ZWdyVGVzdA_Experiment_146123290282954,applicationName=SW50ZWdyVGVzdA_1461232889078App_PRIMARY,startTime=Thu Apr 21 10:01:42 UTC 2016,endTime=,samplingPercent=1.0,description=A sample Experiment description.,rule=(salary < 10000) && (state = 'VA'),isPersonalizationEnabled=false,modelName=,modelVersion=,isRapidExperiment=false,userCap=0,creatorID="+userName+"]\"", HttpStatus.SC_INTERNAL_SERVER_ERROR}, + new Object[]{ExperimentFactory.createCompleteExperiment().setEndTime((String) null), "Could not create experiment \"NewExperiment[id=97daea3b-1523-43e7-8d7c-d7eba2c18ff5,label=SW50ZWdyVGVzdA_Experiment_146123290282954,applicationName=SW50ZWdyVGVzdA_1461232889078App_PRIMARY,startTime=Thu Apr 21 10:01:42 UTC 2016,endTime=,samplingPercent=1.0,description=A sample Experiment description.,rule=(salary < 10000) && (state = 'VA'),isPersonalizationEnabled=false,modelName=,modelVersion=,isRapidExperiment=false,userCap=0,creatorID=" + userName + "]\"", HttpStatus.SC_INTERNAL_SERVER_ERROR}, // FIXME: jwtodd // new Object[] { null, "The server was unable to process the request", HttpStatus.SC_INTERNAL_SERVER_ERROR }, new Object[]{null, "null", HttpStatus.SC_INTERNAL_SERVER_ERROR}, @@ -274,8 +279,8 @@ public Object[][] badExperimentsPOST() { /** * Tries to POST invalid experiments. * - * @param experiment the experiment - * @param expectedError the expected error + * @param experiment the experiment + * @param expectedError the expected error * @param expectedStatusCode the expected HTTP status code */ @Test(dependsOnMethods = {"t_createAndValidateExperiment"}, dataProvider = "badExperimentsPOST") @@ -308,15 +313,15 @@ public Object[][] badExperimentsDELETE() { // FIXME: jwtodd // new Object[] { new Experiment(experiment.setId("foobar")), "Invalid identifier", HttpStatus.SC_INTERNAL_SERVER_ERROR }, new Object[]{new Experiment(experiment.setId("foobar")), "com.intuit.wasabi.experimentobjects.exceptions.InvalidIdentifierException: Invalid experiment identifier \"foobar\"", HttpStatus.SC_INTERNAL_SERVER_ERROR}, - new Object[] { new Experiment(experiment.setId("")), "The server was unable to process the request", HttpStatus.SC_INTERNAL_SERVER_ERROR }, + new Object[]{new Experiment(experiment.setId("")), "The server was unable to process the request", HttpStatus.SC_INTERNAL_SERVER_ERROR}, }; } /** * Tries to DELETE invalid experiments. * - * @param experiment the experiment - * @param expectedError the expected error + * @param experiment the experiment + * @param expectedError the expected error * @param expectedStatusCode the expected HTTP status code */ @Test(dependsOnGroups = {"ping"}, dataProvider = "badExperimentsDELETE") @@ -339,7 +344,7 @@ public void t_failDeleteExperiments(Experiment experiment, String expectedError, public Object[][] badExperimentsPUT() { Experiment experiment = ExperimentFactory.createExperiment().setId(initialExperiment.id); String samplingPercAsString = experiment.toJSONString(); - samplingPercAsString = samplingPercAsString.replace(""+experiment.samplingPercent, "\"foo\""); + samplingPercAsString = samplingPercAsString.replace("" + experiment.samplingPercent, "\"foo\""); return new Object[][]{ // FIXME: jwtodd // new Object[] { new Experiment(experiment).setStartTime("foo").toJSONString(), "Invalid input", HttpStatus.SC_BAD_REQUEST }, @@ -371,8 +376,8 @@ public Object[][] badExperimentsPUT() { /** * Tries to PUT invalid experiments. * - * @param experiment the experiment - * @param expectedError the expected error + * @param experiment the experiment + * @param expectedError the expected error * @param expectedStatusCode the expected HTTP status code */ @SuppressWarnings("unchecked") @@ -401,46 +406,46 @@ public void t_failPutExperiments(String experiment, String expectedError, int ex @DataProvider public Object[][] state() { return new Object[][]{ - new Object[] { "OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // DR -> I - new Object[] { Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_OK}, // DR -> DR - new Object[] { Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_OK}, // DR -> P - new Object[] { "OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // P -> I - new Object[] { Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_OK}, // P -> P + new Object[]{"OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // DR -> I + new Object[]{Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_OK}, // DR -> DR + new Object[]{Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_OK}, // DR -> P + new Object[]{"OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // P -> I + new Object[]{Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_OK}, // P -> P // FIXME: jwtodd // new Object[] { Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_UNPROCESSABLE_ENTITY}, // P -> DR new Object[]{Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_BAD_REQUEST}, // P -> DR - new Object[] { Constants.EXPERIMENT_STATE_RUNNING, HttpStatus.SC_OK}, // P -> R - new Object[] { "OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // R -> I - new Object[] { Constants.EXPERIMENT_STATE_RUNNING, HttpStatus.SC_OK}, // R -> R + new Object[]{Constants.EXPERIMENT_STATE_RUNNING, HttpStatus.SC_OK}, // P -> R + new Object[]{"OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // R -> I + new Object[]{Constants.EXPERIMENT_STATE_RUNNING, HttpStatus.SC_OK}, // R -> R // FIXME: jwtodd // new Object[] { Constants.EXPERIMENT_STATE_DELETED, HttpStatus.SC_UNPROCESSABLE_ENTITY}, // R -> DEL new Object[]{Constants.EXPERIMENT_STATE_DELETED, HttpStatus.SC_BAD_REQUEST}, // R -> DEL // FIXME: jwtodd // new Object[] { Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_UNPROCESSABLE_ENTITY}, // R -> DR new Object[]{Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_BAD_REQUEST}, // R -> DR - new Object[] { Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_OK}, // R -> P + new Object[]{Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_OK}, // R -> P // FIXME: jwtodd // new Object[] { Constants.EXPERIMENT_STATE_DELETED, HttpStatus.SC_UNPROCESSABLE_ENTITY}, // P -> DEL new Object[]{Constants.EXPERIMENT_STATE_DELETED, HttpStatus.SC_BAD_REQUEST}, // P -> DEL - new Object[] { Constants.EXPERIMENT_STATE_TERMINATED, HttpStatus.SC_OK}, // P -> T - new Object[] { "OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // T -> I + new Object[]{Constants.EXPERIMENT_STATE_TERMINATED, HttpStatus.SC_OK}, // P -> T + new Object[]{"OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // T -> I // FIXME: jwtodd // new Object[] { Constants.EXPERIMENT_STATE_RUNNING, HttpStatus.SC_UNPROCESSABLE_ENTITY}, // T -> R new Object[]{Constants.EXPERIMENT_STATE_RUNNING, HttpStatus.SC_BAD_REQUEST}, // T -> R - new Object[] { Constants.EXPERIMENT_STATE_TERMINATED, HttpStatus.SC_OK}, // T -> T + new Object[]{Constants.EXPERIMENT_STATE_TERMINATED, HttpStatus.SC_OK}, // T -> T // FIXME: jwtodd // new Object[] { Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_UNPROCESSABLE_ENTITY}, // T -> P new Object[]{Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_BAD_REQUEST}, // T -> P // FIXME: jwtodd // new Object[] { Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_UNPROCESSABLE_ENTITY}, // T -> DR new Object[]{Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_BAD_REQUEST}, // T -> DR - new Object[] { Constants.EXPERIMENT_STATE_DELETED, HttpStatus.SC_NO_CONTENT}, // T -> DEL - new Object[] { "OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // DEL -> I - new Object[] { Constants.EXPERIMENT_STATE_DELETED, HttpStatus.SC_NOT_FOUND}, // DEL -> DEL - new Object[] { Constants.EXPERIMENT_STATE_RUNNING, HttpStatus.SC_NOT_FOUND}, // DEL -> R - new Object[] { Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_NOT_FOUND}, // DEL -> P - new Object[] { Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_NOT_FOUND}, // DEL -> DR - new Object[] { Constants.EXPERIMENT_STATE_TERMINATED, HttpStatus.SC_NOT_FOUND}, // DEL -> T + new Object[]{Constants.EXPERIMENT_STATE_DELETED, HttpStatus.SC_NO_CONTENT}, // T -> DEL + new Object[]{"OBVIOUSLY_INVALID_EXPERIMENT_STATE", HttpStatus.SC_BAD_REQUEST}, // DEL -> I + new Object[]{Constants.EXPERIMENT_STATE_DELETED, HttpStatus.SC_NOT_FOUND}, // DEL -> DEL + new Object[]{Constants.EXPERIMENT_STATE_RUNNING, HttpStatus.SC_NOT_FOUND}, // DEL -> R + new Object[]{Constants.EXPERIMENT_STATE_PAUSED, HttpStatus.SC_NOT_FOUND}, // DEL -> P + new Object[]{Constants.EXPERIMENT_STATE_DRAFT, HttpStatus.SC_NOT_FOUND}, // DEL -> DR + new Object[]{Constants.EXPERIMENT_STATE_TERMINATED, HttpStatus.SC_NOT_FOUND}, // DEL -> T }; } @@ -456,7 +461,7 @@ public void t_createBucket() { /** * Tests different experiment state transitions. * - * @param state the state to change to + * @param state the state to change to * @param statusCode the expected http status code */ @Test(dependsOnMethods = {"t_createBucket"}, dataProvider = "state") @@ -471,10 +476,10 @@ public void t_basicStateTransitions(String state, int statusCode) { /** * Tests different experiment state transitions with other constraints like too few buckets. - * + *

* The transitions tested are: * DR -> R -> T - * + *

* Each with 0 buckets, buckets with fewer than 100% allocation and the correct amount of buckets with allocations. */ @Test(dependsOnMethods = {"t_failPutExperiments", "t_failPostExperiments", "t_failDeleteExperiments"}) @@ -561,12 +566,12 @@ public void t_remainingTransitionTests() { @DataProvider public Object[][] dates() { String identicalTime = TestUtils.relativeTimeString(5); - return new Object[][] { - new Object[] { "present", TestUtils.relativeTimeString(-1), TestUtils.relativeTimeString(1) }, - new Object[] { "future", TestUtils.relativeTimeString(2), TestUtils.relativeTimeString(4) }, - new Object[] { "same", identicalTime, identicalTime }, - new Object[] { "past", TestUtils.relativeTimeString(-4), TestUtils.relativeTimeString(-2) }, - new Object[] { "endBeforeStart", TestUtils.relativeTimeString(3), TestUtils.relativeTimeString(1) }, + return new Object[][]{ + new Object[]{"present", TestUtils.relativeTimeString(-1), TestUtils.relativeTimeString(1)}, + new Object[]{"future", TestUtils.relativeTimeString(2), TestUtils.relativeTimeString(4)}, + new Object[]{"same", identicalTime, identicalTime}, + new Object[]{"past", TestUtils.relativeTimeString(-4), TestUtils.relativeTimeString(-2)}, + new Object[]{"endBeforeStart", TestUtils.relativeTimeString(3), TestUtils.relativeTimeString(1)}, }; } @@ -574,9 +579,8 @@ public Object[][] dates() { * Checks if the date change behaviour is correct for several cases. * * @param identifier the identifier of the test - * @param start the start time - * @param end the end time - * + * @param start the start time + * @param end the end time * @throws ParseException when parse date time failed */ @Test(dependsOnMethods = {"t_remainingTransitionTests"}, dataProvider = "dates")