Skip to content

Instantly share code, notes, and snippets.

@parker
Last active December 24, 2015 10:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save parker/2e61249a1b002fbf2b31 to your computer and use it in GitHub Desktop.
Save parker/2e61249a1b002fbf2b31 to your computer and use it in GitHub Desktop.
package com.indeed.demo;
import com.indeed.proctor.common.*;
import com.indeed.proctor.common.model.Payload;
import com.indeed.proctor.common.model.TestBucket;
import com.indeed.proctor.consumer.*;
import javax.annotation.Nullable;
/*
* GENERATED source; do not edit directly
* (but you can extend me. you'll want to override {@link #toString()}, using {@link #buildTestGroupString()} or {@link #appendTestGroups(StringBuilder)} instead)
*/
public class ExampleGroups extends AbstractGroups {
public static final ExampleGroups EMPTY = new ExampleGroups(ProctorResult.EMPTY);
public ExampleGroups(final ProctorResult proctorResult) {
super(proctorResult);
}
public static Bucket<Test>[] getBuckets(final Test test) {
switch (test) {
case BGCOLORTST:
return Bgcolortst.values();
}
return null;
}
public enum Test {
BGCOLORTST("bgcolortst");
; // fix compilation if no tests
private final String name;
private Test(final String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public enum Bgcolortst implements Bucket<Test> {
INACTIVE(-1, "inactive"),
ALTCOLOR1(0, "altcolor1"),
ALTCOLOR2(1, "altcolor2"),
ALTCOLOR3(2, "altcolor3"),
ALTCOLOR4(3, "altcolor4");
private final int value;
private final String name;
private final String fullName;
private Bgcolortst(final int value, final String name) {
this.value = value;
this.name = name;
this.fullName = getTest().getName() + "-" + name;
}
@Override
public Test getTest() {
return Test.BGCOLORTST;
}
@Override
public int getValue() {
return value;
}
@Override
public String getName() {
return name;
}
@Override
public String getFullName() {
return fullName;
}
}
public Bgcolortst getBgcolortst() {
for (final Bgcolortst bucket : Bgcolortst.values()) {
final String testName = Test.BGCOLORTST.getName();
if (isBucketActive(testName, bucket.getValue())) {
return bucket;
}
}
return null;
}
/**
* perhaps defaultValue should be specified in and supplied from src/proctor/proctor-specification.json
*/
public int getBgcolortstValue(final int defaultValue) {
return getValue(Test.BGCOLORTST.getName(), defaultValue);
}
public @Nullable String getBgcolortstPayload() {
return getPayload(Test.BGCOLORTST.getName()).getStringValue();
}
public @Nullable String getBgcolortstPayloadForBucket(final Bgcolortst targetBucket) {
final @Nullable TestBucket bucket = getTestBucketForBucket(Test.BGCOLORTST.getName(), targetBucket);
if (bucket == null) {
return null;
}
final Payload payload = bucket.getPayload();
if (payload == null) {
return null;
}
return payload.getStringValue();
}
public boolean isBgcolortstInactive() {
final String testName = Test.BGCOLORTST.getName();
final int bucketValue = Bgcolortst.INACTIVE.getValue();
return isBucketActive(testName, bucketValue);
}
public boolean isBgcolortstAltcolor1() {
final String testName = Test.BGCOLORTST.getName();
final int bucketValue = Bgcolortst.ALTCOLOR1.getValue();
return isBucketActive(testName, bucketValue);
}
public boolean isBgcolortstAltcolor2() {
final String testName = Test.BGCOLORTST.getName();
final int bucketValue = Bgcolortst.ALTCOLOR2.getValue();
return isBucketActive(testName, bucketValue);
}
public boolean isBgcolortstAltcolor3() {
final String testName = Test.BGCOLORTST.getName();
final int bucketValue = Bgcolortst.ALTCOLOR3.getValue();
return isBucketActive(testName, bucketValue);
}
public boolean isBgcolortstAltcolor4() {
final String testName = Test.BGCOLORTST.getName();
final int bucketValue = Bgcolortst.ALTCOLOR4.getValue();
return isBucketActive(testName, bucketValue);
}
}
{
"tests" : {
"bgcolortst": {
"buckets": {
"inactive":-1,
"altcolor1":0,
"altcolor2":1,
"altcolor3":2,
"altcolor4":3
},
"fallbackValue": -1,
"payload": {
"type": "stringValue",
"validator": "${fn:startsWith(value, '#') && fn:length(value) == 7}"
}
}
},
"providedContext": {
"country": "String",
"loggedIn": "boolean",
"ua": "com.indeed.example.UserAgent"
}
}
package com.indeed.example.proctor;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ExampleGroupsInterceptor extends HandlerInterceptorAdapter {
private final ExampleGroupsManager manager;
public GroupsInterceptor(final ExampleGroupsManager manager) {
this.manager = manager;
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 1. create the set of test-identifiers and their values for a given request
final String trackingCookie = getTrackingCookie(request);
final Identifiers identifiers = Identifiers.of(TestType.USER, trackingCookie);
// 2. application-specific context variables
final com.indeed.example.UserAgent useragent = UserAgent.parse(request);
final String country = getCountry(request);
final boolean loggedIn = isLoggedIn(request);
// 3. can groups be forced via url-parameters / cookie values. eg. Internal-Users can force groups
final boolean allowForceGroups = isAllowForceGroups(request);
ProctorResult result = ProctorResult.EMPTY;
try {
// 4. determine buckets from groups-manager
result = manager.determineBuckets(request,
response,
identifiers,
allowForceGroups,
country,
loggedIn,
useragent);
} catch (Exception ignored) {
// 5. handle exceptions from javax.el expressions / rules
result = ProctorResult.EMPTY;
}
// 5. construct groups from the result
final ExampleGroups groups = new ExampleGroups(result);
// 6. set groups as request attribute for use in other parts of your web application
request.setAttribute("__groups__", groups);
return true;
}
public String getTrackingCookie(HttpServletRequest request) {
// application specific logic to identify tracking cookie
}
public boolean isLoggedIn(HttpServletRequest request) {
// application specific logic to identify logged-in users
}
public String getCountry(HttpServletRequest request) {
// application specific logic to identify country
}
private boolean isAllowForceGroups(HttpServletRequest request) {
// application specific logic to permit the overriding of groups
}
}
package com.indeed.demo;
import com.indeed.proctor.common.*;
import com.indeed.proctor.common.model.*;
import com.indeed.proctor.consumer.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Supplier;
/*
* GENERATED source; do not edit directly
*/
public class ExampleGroupsManager extends AbstractGroupsManager {
private static final Map<String, String> PROVIDED_CONTEXT;
static {
final Map<String, String> providedContext = new LinkedHashMap<String, String>();
providedContext.put("country", "String");
providedContext.put("loggedIn", "boolean");
providedContext.put("ua", "com.indeed.example.UserAgent");
PROVIDED_CONTEXT = Collections.unmodifiableMap(providedContext);
}
public ExampleGroupsManager(final Supplier<Proctor> proctorSource) {
super(proctorSource);
}
/**
* This should be used for non-webapp applications that are working
* with test groups as those applications will not have a request and response,
* such as boxcar services.
* @deprecated Use the one that takes a Map<TestType, String> instead
*/
public ProctorResult determineBuckets(final TestType testType, final String identifier,
final String country,
final boolean loggedIn,
final com.indeed.example.UserAgent ua) {
final Map<String, Object> context = new HashMap<String, Object>();
context.put("country", country);
context.put("loggedIn", loggedIn);
context.put("ua", ua);
return super.determineBuckets(testType, identifier, context);
}
/**
* This should be used for non-webapp applications that are working
* with test groups as those applications will not have a request and response,
* such as boxcar services.
*/
public ProctorResult determineBuckets(final Identifiers identifiers,
final String country,
final boolean loggedIn,
final com.indeed.example.UserAgent ua) {
final Map<String, Object> context = new HashMap<String, Object>();
context.put("country", country);
context.put("loggedIn", loggedIn);
context.put("ua", ua);
return super.determineBuckets(identifiers, context);
}
/**
* This should be used for non-webapp applications that are working
* with test groups as those applications will not have a request and response,
* such as boxcar services.
*/
public ProctorResult determineBuckets(final Identifiers identifiers,
final Map<String, Integer> forcedGroups,
final String country,
final boolean loggedIn,
final com.indeed.example.UserAgent ua) {
final Map<String, Object> context = new HashMap<String, Object>();
context.put("country", country);
context.put("loggedIn", loggedIn);
context.put("ua", ua);
return super.determineBuckets(identifiers, context, forcedGroups);
}
/*
* @deprecated Use the one that takes a Map<TestType, String> instead
*/
public ProctorResult determineBuckets(final HttpServletRequest request, final HttpServletResponse response,
final TestType testType, final String identifier, final boolean allowForcedGroups,
final String country,
final boolean loggedIn,
final com.indeed.example.UserAgent ua) {
final Identifiers identifiers = new Identifiers(testType, identifier);
return determineBuckets(request, response, identifiers, allowForcedGroups
, country
, loggedIn
, ua
);
}
public ProctorResult determineBuckets(final HttpServletRequest request, final HttpServletResponse response,
final Identifiers identifiers, final boolean allowForcedGroups,
final String country,
final boolean loggedIn,
final com.indeed.example.UserAgent ua) {
final Map<String, Object> context = new HashMap<String, Object>();
context.put("country", country);
context.put("loggedIn", loggedIn);
context.put("ua", ua);
return super.determineBuckets(request, response, identifiers, context, allowForcedGroups);
}
private static final Map<String, TestBucket> DEFAULT_BUCKET_VALUES = constructDefaultBucketValuesMap();
private static Map<String, TestBucket> constructDefaultBucketValuesMap() {
final Map<String, TestBucket> defaultBucketValues = new HashMap<String, TestBucket>();
defaultBucketValues.put("bgcolortst", new TestBucket("fallback", -1, "fallback value; something is broken", null));
return Collections.unmodifiableMap(defaultBucketValues);
}
@Override
protected Map<String, TestBucket> getDefaultBucketValues() {
return DEFAULT_BUCKET_VALUES;
}
@Override
public Map<String, String> getProvidedContext() {
return PROVIDED_CONTEXT;
}
}
package com.indeed.example;
public class UserAgent {
public static UserAgent parse(final HttpServletRequest request);
public int getVersion() { ... }
public boolean isMobile() { ... }
public boolean isAndroid() { ... }
public boolean isIPad() { ... }
public boolean isIPhone() { ... }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment