Introduce RuleKeyBuilderFactory so that all RuleKeys can be seeded with common data.

Summary:
Ultimately, we need to be able to include build options from `.buckconfig` in the
computation of a `RuleKey`. (It would also be nice to be able to inject it for
testing purposes.)

Test Plan: Sandcastle builds.
diff --git a/src/com/facebook/buck/cli/CommandRunnerParams.java b/src/com/facebook/buck/cli/CommandRunnerParams.java
index 86f8db2..89639cc 100644
--- a/src/com/facebook/buck/cli/CommandRunnerParams.java
+++ b/src/com/facebook/buck/cli/CommandRunnerParams.java
@@ -18,7 +18,11 @@
 
 import com.facebook.buck.event.BuckEventBus;
 import com.facebook.buck.parser.Parser;
+import com.facebook.buck.rules.BuildRule;
 import com.facebook.buck.rules.KnownBuildRuleTypes;
+import com.facebook.buck.rules.RuleKey;
+import com.facebook.buck.rules.RuleKey.Builder;
+import com.facebook.buck.rules.RuleKeyBuilderFactory;
 import com.facebook.buck.util.Ansi;
 import com.facebook.buck.util.Console;
 import com.facebook.buck.util.ProjectFilesystem;
@@ -45,7 +49,7 @@
   private final Platform platform;
 
   @VisibleForTesting
-  public CommandRunnerParams(
+  CommandRunnerParams(
       Console console,
       ProjectFilesystem projectFilesystem,
       KnownBuildRuleTypes buildRuleTypes,
@@ -62,7 +66,13 @@
             buildRuleTypes,
             console,
             pythonInterpreter,
-            ImmutableSet.<Pattern>of() /* Temp file patterns */),
+            /* tempFilePatterns */ ImmutableSet.<Pattern>of(),
+            new RuleKeyBuilderFactory() {
+              @Override
+              public Builder newInstance(BuildRule buildRule) {
+                return RuleKey.builder(buildRule);
+              }
+            }),
         platform);
   }
 
diff --git a/src/com/facebook/buck/cli/Main.java b/src/com/facebook/buck/cli/Main.java
index 2b8ca56..15f4ab8 100644
--- a/src/com/facebook/buck/cli/Main.java
+++ b/src/com/facebook/buck/cli/Main.java
@@ -26,9 +26,13 @@
 import com.facebook.buck.parser.Parser;
 import com.facebook.buck.rules.ArtifactCache;
 import com.facebook.buck.rules.ArtifactCacheEvent;
+import com.facebook.buck.rules.BuildRule;
 import com.facebook.buck.rules.KnownBuildRuleTypes;
 import com.facebook.buck.rules.LoggingArtifactCacheDecorator;
 import com.facebook.buck.rules.NoopArtifactCache;
+import com.facebook.buck.rules.RuleKey;
+import com.facebook.buck.rules.RuleKey.Builder;
+import com.facebook.buck.rules.RuleKeyBuilderFactory;
 import com.facebook.buck.timing.Clock;
 import com.facebook.buck.timing.DefaultClock;
 import com.facebook.buck.util.Ansi;
@@ -79,6 +83,9 @@
   private static final String DEFAULT_BUCK_CONFIG_FILE_NAME = ".buckconfig";
   private static final String DEFAULT_BUCK_CONFIG_OVERRIDE_FILE_NAME = ".buckconfig.local";
 
+  private static final String BUCK_VERSION_UID_KEY = "buck.version_uid";
+  private static final String BUCK_VERSION_UID = System.getProperty(BUCK_VERSION_UID_KEY, "N/A");
+
   private final PrintStream stdOut;
   private final PrintStream stdErr;
 
@@ -109,7 +116,8 @@
           new KnownBuildRuleTypes(),
           console,
           config.getPythonInterpreter(),
-          config.getTempFilePatterns());
+          config.getTempFilePatterns(),
+          createRuleKeyBuilderFactory(config));
       this.fileEventBus = new EventBus("file-change-events");
       this.filesystemWatcher = new ProjectFilesystemWatcher(
           projectFilesystem,
@@ -296,7 +304,8 @@
           knownBuildRuleTypes,
           console,
           config.getPythonInterpreter(),
-          config.getTempFilePatterns());
+          config.getTempFilePatterns(),
+          createRuleKeyBuilderFactory(config));
     }
 
     Clock clock = new DefaultClock();
@@ -487,6 +496,22 @@
     return BuckConfig.createFromFiles(projectFilesystem, configFiles, platform);
   }
 
+  /**
+   * @param buckConfig This is currently unused, but we plan to use this in the near future so that
+   *     global user configurations can be included when computing keys.
+   */
+  @SuppressWarnings("unused")
+  private static RuleKeyBuilderFactory createRuleKeyBuilderFactory(BuckConfig buckConfig) {
+    return new RuleKeyBuilderFactory() {
+      @Override
+      public Builder newInstance(BuildRule buildRule) {
+        RuleKey.Builder builder = RuleKey.builder(buildRule);
+        builder.set("buckVersionUid", BUCK_VERSION_UID);
+        return builder;
+      }
+    };
+  }
+
   @VisibleForTesting
   int tryRunMainWithExitCode(File projectRoot, String... args) throws IOException {
     // TODO(user): enforce write command exclusion, but allow concurrent read only commands?
diff --git a/src/com/facebook/buck/parser/BuildRuleFactoryParams.java b/src/com/facebook/buck/parser/BuildRuleFactoryParams.java
index 9d9c201..7f7cc4f 100644
--- a/src/com/facebook/buck/parser/BuildRuleFactoryParams.java
+++ b/src/com/facebook/buck/parser/BuildRuleFactoryParams.java
@@ -23,6 +23,7 @@
 import com.facebook.buck.rules.BuildTargetSourcePath;
 import com.facebook.buck.rules.DefaultBuildRuleBuilderParams;
 import com.facebook.buck.rules.FileSourcePath;
+import com.facebook.buck.rules.RuleKeyBuilderFactory;
 import com.facebook.buck.rules.SourcePath;
 import com.facebook.buck.util.BuckConstant;
 import com.facebook.buck.util.HumanReadableException;
@@ -67,12 +68,14 @@
       ProjectFilesystem filesystem,
       BuildFileTree buildFiles,
       BuildTargetParser buildTargetParser,
-      BuildTarget target) {
+      BuildTarget target,
+      RuleKeyBuilderFactory ruleKeyBuilderFactory) {
     this(instance,
         filesystem,
         buildFiles,
         buildTargetParser,
         target,
+        ruleKeyBuilderFactory,
         false /* ignoreFileExistenceChecks */);
   }
 
@@ -83,6 +86,7 @@
       BuildFileTree buildFiles,
       BuildTargetParser buildTargetParser,
       BuildTarget target,
+      RuleKeyBuilderFactory ruleKeyBuilderFactory,
       boolean ignoreFileExistenceChecks) {
     this.instance = instance;
     this.filesystem = filesystem;
@@ -101,7 +105,8 @@
       }
     };
 
-    this.abstractBuildRuleFactoryParams = new DefaultBuildRuleBuilderParams(filesystem);
+    this.abstractBuildRuleFactoryParams = new DefaultBuildRuleBuilderParams(filesystem,
+        ruleKeyBuilderFactory);
   }
 
   /** This is package-private so that only AbstractBuildRuleFactory can access it. */
diff --git a/src/com/facebook/buck/parser/Parser.java b/src/com/facebook/buck/parser/Parser.java
index 8ffd985..0b68832 100644
--- a/src/com/facebook/buck/parser/Parser.java
+++ b/src/com/facebook/buck/parser/Parser.java
@@ -32,6 +32,7 @@
 import com.facebook.buck.rules.BuildRuleType;
 import com.facebook.buck.rules.DependencyGraph;
 import com.facebook.buck.rules.KnownBuildRuleTypes;
+import com.facebook.buck.rules.RuleKeyBuilderFactory;
 import com.facebook.buck.util.BuckConstant;
 import com.facebook.buck.util.Console;
 import com.facebook.buck.util.HumanReadableException;
@@ -107,6 +108,7 @@
   private final ProjectFilesystem projectFilesystem;
   private final KnownBuildRuleTypes buildRuleTypes;
   private final ProjectBuildFileParserFactory buildFileParserFactory;
+  private final RuleKeyBuilderFactory ruleKeyBuilderFactory;
   private final Console console;
 
   /**
@@ -161,7 +163,8 @@
       KnownBuildRuleTypes buildRuleTypes,
       Console console,
       String pythonInterpreter,
-      ImmutableSet<Pattern> tempFilePatterns) {
+      ImmutableSet<Pattern> tempFilePatterns,
+      RuleKeyBuilderFactory ruleKeyBuilderFactory) {
     this(projectFilesystem,
         buildRuleTypes,
         console,
@@ -175,7 +178,8 @@
         new BuildTargetParser(projectFilesystem),
          /* knownBuildTargets */ Maps.<BuildTarget, BuildRuleBuilder<?>>newHashMap(),
         new DefaultProjectBuildFileParserFactory(projectFilesystem, pythonInterpreter),
-        tempFilePatterns);
+        tempFilePatterns,
+        ruleKeyBuilderFactory);
   }
 
   /**
@@ -190,7 +194,8 @@
          BuildTargetParser buildTargetParser,
          Map<BuildTarget, BuildRuleBuilder<?>> knownBuildTargets,
          ProjectBuildFileParserFactory buildFileParserFactory,
-         ImmutableSet<Pattern> tempFilePatterns) {
+         ImmutableSet<Pattern> tempFilePatterns,
+         RuleKeyBuilderFactory ruleKeyBuilderFactory) {
     this.projectFilesystem = Preconditions.checkNotNull(projectFilesystem);
     this.buildRuleTypes = Preconditions.checkNotNull(buildRuleTypes);
     this.console = Preconditions.checkNotNull(console);
@@ -199,6 +204,7 @@
     this.knownBuildTargets = Maps.newHashMap(Preconditions.checkNotNull(knownBuildTargets));
     this.buildTargetParser = Preconditions.checkNotNull(buildTargetParser);
     this.buildFileParserFactory = Preconditions.checkNotNull(buildFileParserFactory);
+    this.ruleKeyBuilderFactory = Preconditions.checkNotNull(ruleKeyBuilderFactory);
     this.parsedBuildFiles = ArrayListMultimap.create();
     this.buildFileDependents = ArrayListMultimap.create();
     this.tempFilePatterns = tempFilePatterns;
@@ -481,7 +487,8 @@
           projectFilesystem,
           buildFileTree,
           buildTargetParser,
-          target));
+          target,
+          ruleKeyBuilderFactory));
       Object existingRule = knownBuildTargets.put(target, buildRuleBuilder);
       if (existingRule != null) {
         throw new RuntimeException("Duplicate definition for " + target.getFullyQualifiedName());
diff --git a/src/com/facebook/buck/rules/AbstractBuildRule.java b/src/com/facebook/buck/rules/AbstractBuildRule.java
index a60a238..88eeb8e 100644
--- a/src/com/facebook/buck/rules/AbstractBuildRule.java
+++ b/src/com/facebook/buck/rules/AbstractBuildRule.java
@@ -34,6 +34,7 @@
   private final BuildTarget buildTarget;
   private final ImmutableSortedSet<BuildRule> deps;
   private final ImmutableSet<BuildTargetPattern> visibilityPatterns;
+  private final RuleKeyBuilderFactory ruleKeyBuilderFactory;
   @Nullable private volatile RuleKey.Builder.RuleKeyPair ruleKeyPair;
 
   protected AbstractBuildRule(BuildRuleParams buildRuleParams) {
@@ -41,6 +42,7 @@
     this.buildTarget = buildRuleParams.getBuildTarget();
     this.deps = buildRuleParams.getDeps();
     this.visibilityPatterns = buildRuleParams.getVisibilityPatterns();
+    this.ruleKeyBuilderFactory = buildRuleParams.getRuleKeyBuilderFactory();
 
     for (BuildRule dep : this.deps) {
       if (!dep.isVisibleTo(buildTarget)) {
@@ -167,7 +169,7 @@
     if (ruleKeyPair == null) {
       synchronized (this) {
         if (ruleKeyPair == null) {
-          RuleKey.Builder builder = RuleKey.builder(this);
+          RuleKey.Builder builder = ruleKeyBuilderFactory.newInstance(this);
           appendToRuleKey(builder);
           ruleKeyPair = builder.build();
         }
diff --git a/src/com/facebook/buck/rules/AbstractBuildRuleBuilder.java b/src/com/facebook/buck/rules/AbstractBuildRuleBuilder.java
index 88fc4d1..81989c9 100644
--- a/src/com/facebook/buck/rules/AbstractBuildRuleBuilder.java
+++ b/src/com/facebook/buck/rules/AbstractBuildRuleBuilder.java
@@ -38,9 +38,11 @@
   protected Set<BuildTargetPattern> visibilityPatterns = Sets.newHashSet();
 
   private final Function<String, String> pathRelativizer;
+  private final RuleKeyBuilderFactory ruleKeyBuilderFactory;
 
   protected AbstractBuildRuleBuilder(AbstractBuildRuleBuilderParams params) {
     this.pathRelativizer = params.getPathRelativizer();
+    this.ruleKeyBuilderFactory = params.getRuleKeyBuilderFactory();
   }
 
   @Override
@@ -113,6 +115,7 @@
     return new BuildRuleParams(getBuildTarget(),
         getDepsAsBuildRules(ruleResolver),
         getVisibilityPatterns(),
-        pathRelativizer);
+        pathRelativizer,
+        ruleKeyBuilderFactory);
   }
 }
diff --git a/src/com/facebook/buck/rules/AbstractBuildRuleBuilderParams.java b/src/com/facebook/buck/rules/AbstractBuildRuleBuilderParams.java
index 29a8b8e..6776a34 100644
--- a/src/com/facebook/buck/rules/AbstractBuildRuleBuilderParams.java
+++ b/src/com/facebook/buck/rules/AbstractBuildRuleBuilderParams.java
@@ -34,4 +34,5 @@
    */
   public Function<String, String> getPathRelativizer();
 
+  public RuleKeyBuilderFactory getRuleKeyBuilderFactory();
 }
diff --git a/src/com/facebook/buck/rules/BUCK b/src/com/facebook/buck/rules/BUCK
index 63f5a10..2e50e08 100644
--- a/src/com/facebook/buck/rules/BUCK
+++ b/src/com/facebook/buck/rules/BUCK
@@ -108,6 +108,7 @@
     'ProjectConfigRule.java',
     'RecordArtifactsInDirectoryStep.java',
     'ResourcesAttributeBuilder.java',
+    'RuleKeyBuilderFactory.java',
     'SourcePaths.java',
     'SrcsAttributeBuilder.java',
     'TestRule.java',
diff --git a/src/com/facebook/buck/rules/BuildRuleParams.java b/src/com/facebook/buck/rules/BuildRuleParams.java
index 4735e89..50e46a8 100644
--- a/src/com/facebook/buck/rules/BuildRuleParams.java
+++ b/src/com/facebook/buck/rules/BuildRuleParams.java
@@ -34,15 +34,18 @@
   private final ImmutableSortedSet<BuildRule> deps;
   private final ImmutableSet<BuildTargetPattern> visibilityPatterns;
   private final Function<String, String> pathRelativizer;
+  private final RuleKeyBuilderFactory ruleKeyBuilderFactory;
 
   public BuildRuleParams(BuildTarget buildTarget,
       ImmutableSortedSet<BuildRule> deps,
       ImmutableSet<BuildTargetPattern> visibilityPatterns,
-      Function<String, String> pathRelativizer) {
+      Function<String, String> pathRelativizer,
+      RuleKeyBuilderFactory ruleKeyBuilderFactory) {
     this.buildTarget = Preconditions.checkNotNull(buildTarget);
     this.deps = Preconditions.checkNotNull(deps);
     this.visibilityPatterns = Preconditions.checkNotNull(visibilityPatterns);
     this.pathRelativizer = Preconditions.checkNotNull(pathRelativizer);
+    this.ruleKeyBuilderFactory = Preconditions.checkNotNull(ruleKeyBuilderFactory);
   }
 
   public BuildTarget getBuildTarget() {
@@ -60,4 +63,8 @@
   public Function<String, String> getPathRelativizer() {
     return pathRelativizer;
   }
+
+  public RuleKeyBuilderFactory getRuleKeyBuilderFactory() {
+    return ruleKeyBuilderFactory;
+  }
 }
diff --git a/src/com/facebook/buck/rules/DefaultBuildRuleBuilderParams.java b/src/com/facebook/buck/rules/DefaultBuildRuleBuilderParams.java
index 61254c1..78df1ba 100644
--- a/src/com/facebook/buck/rules/DefaultBuildRuleBuilderParams.java
+++ b/src/com/facebook/buck/rules/DefaultBuildRuleBuilderParams.java
@@ -23,9 +23,12 @@
 public class DefaultBuildRuleBuilderParams implements AbstractBuildRuleBuilderParams {
 
   private final Function<String, String> pathRelativizer;
+  private final RuleKeyBuilderFactory ruleKeyBuilderFactory;
 
-  public DefaultBuildRuleBuilderParams(ProjectFilesystem projectFilesystem) {
+  public DefaultBuildRuleBuilderParams(ProjectFilesystem projectFilesystem,
+      RuleKeyBuilderFactory ruleKeyBuilderFactory) {
     this.pathRelativizer = Preconditions.checkNotNull(projectFilesystem).getPathRelativizer();
+    this.ruleKeyBuilderFactory = Preconditions.checkNotNull(ruleKeyBuilderFactory);
   }
 
   @Override
@@ -33,4 +36,9 @@
     return pathRelativizer;
   }
 
+  @Override
+  public RuleKeyBuilderFactory getRuleKeyBuilderFactory() {
+    return ruleKeyBuilderFactory;
+  }
+
 }
diff --git a/src/com/facebook/buck/rules/RuleKey.java b/src/com/facebook/buck/rules/RuleKey.java
index 8d15a37..52be447 100644
--- a/src/com/facebook/buck/rules/RuleKey.java
+++ b/src/com/facebook/buck/rules/RuleKey.java
@@ -116,7 +116,7 @@
   /**
    * Builder for a {@link RuleKey} that is a function of all of a {@link BuildRule}'s inputs.
    */
-  public static Builder builder(BuildRule rule) throws IOException {
+  public static Builder builder(BuildRule rule) {
     Builder builder = new Builder(rule)
         .set("name", rule.getFullyQualifiedName())
 
@@ -127,10 +127,6 @@
   }
 
   public static class Builder {
-    private static final String BUCK_VERSION_UID_KEY = "buck.version_uid";
-
-    @VisibleForTesting
-    static final String buckVersionUID = System.getProperty(BUCK_VERSION_UID_KEY, "N/A");
 
     @VisibleForTesting
     static final byte SEPARATOR = '\0';
@@ -147,7 +143,6 @@
       if (logger.isLoggable(Level.INFO)) {
         this.logElms = Lists.newArrayList();
       }
-      setBuckVersionUID();
     }
 
     private Builder feed(byte[] bytes) {
@@ -160,13 +155,6 @@
       return this;
     }
 
-    private void setBuckVersionUID() {
-      if (logElms != null) {
-        logElms.add(String.format("buckVersionUID(%s):", buckVersionUID));
-      }
-      feed(buckVersionUID.getBytes()).separate();
-    }
-
     private Builder setKey(String sectionLabel) {
       if (logElms != null) {
         logElms.add(String.format(":key(%s):", sectionLabel));
diff --git a/src/com/facebook/buck/rules/RuleKeyBuilderFactory.java b/src/com/facebook/buck/rules/RuleKeyBuilderFactory.java
new file mode 100644
index 0000000..a493e5a
--- /dev/null
+++ b/src/com/facebook/buck/rules/RuleKeyBuilderFactory.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013-present Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.facebook.buck.rules;
+
+public interface RuleKeyBuilderFactory {
+
+  public RuleKey.Builder newInstance(BuildRule buildRule);
+}
diff --git a/test/com/facebook/buck/android/AndroidResourceRuleTest.java b/test/com/facebook/buck/android/AndroidResourceRuleTest.java
index 4411041..b351e8f 100644
--- a/test/com/facebook/buck/android/AndroidResourceRuleTest.java
+++ b/test/com/facebook/buck/android/AndroidResourceRuleTest.java
@@ -27,14 +27,13 @@
 import com.facebook.buck.rules.BuildRuleResolver;
 import com.facebook.buck.rules.DependencyGraph;
 import com.facebook.buck.rules.FakeAbstractBuildRuleBuilderParams;
+import com.facebook.buck.rules.FakeBuildRuleParams;
 import com.facebook.buck.testutil.MoreAsserts;
 import com.facebook.buck.testutil.RuleMap;
 import com.facebook.buck.util.DirectoryTraversal;
 import com.facebook.buck.util.DirectoryTraverser;
 import com.facebook.buck.util.Paths;
-import com.google.common.base.Functions;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
 
 import org.junit.Test;
@@ -70,11 +69,9 @@
     // Create an android_library rule with all sorts of input files that it depends on. If any of
     // these files is modified, then this rule should not be cached.
     BuildTarget buildTarget = new BuildTarget("//java/src/com/facebook/base", "res");
-    BuildRuleParams buildRuleParams = new BuildRuleParams(
+    BuildRuleParams buildRuleParams = new FakeBuildRuleParams(
         buildTarget,
-        ImmutableSortedSet.<BuildRule>of() /* deps */,
-        ImmutableSet.of(BuildTargetPattern.MATCH_ALL),
-        /* pathRelativizer */ Functions.<String>identity());
+        ImmutableSortedSet.<BuildRule>of());
     AndroidResourceRule androidResourceRule = new AndroidResourceRule(
         buildRuleParams,
         "java/src/com/facebook/base/res",
diff --git a/test/com/facebook/buck/android/RobolectricTestBuildRuleFactoryTest.java b/test/com/facebook/buck/android/RobolectricTestBuildRuleFactoryTest.java
index 06b0d2f..340fa10 100644
--- a/test/com/facebook/buck/android/RobolectricTestBuildRuleFactoryTest.java
+++ b/test/com/facebook/buck/android/RobolectricTestBuildRuleFactoryTest.java
@@ -30,6 +30,7 @@
 import com.facebook.buck.rules.BuildRuleResolver;
 import com.facebook.buck.rules.BuildRuleType;
 import com.facebook.buck.rules.FakeAbstractBuildRuleBuilderParams;
+import com.facebook.buck.rules.FakeRuleKeyBuilderFactory;
 import com.facebook.buck.util.ProjectFilesystem;
 import com.google.common.base.Functions;
 import com.google.common.collect.ImmutableList;
@@ -71,7 +72,8 @@
         projectFilesystem,
         buildFileTree,
         buildTargetParser,
-        buildTarget);
+        buildTarget,
+        new FakeRuleKeyBuilderFactory());
 
     // Create a builder using the factory.
     RobolectricTestBuildRuleFactory factory = new RobolectricTestBuildRuleFactory();
diff --git a/test/com/facebook/buck/java/DefaultJavaLibraryRuleTest.java b/test/com/facebook/buck/java/DefaultJavaLibraryRuleTest.java
index e1a3003..3ee8ee7 100644
--- a/test/com/facebook/buck/java/DefaultJavaLibraryRuleTest.java
+++ b/test/com/facebook/buck/java/DefaultJavaLibraryRuleTest.java
@@ -45,7 +45,9 @@
 import com.facebook.buck.rules.DefaultBuildRuleBuilderParams;
 import com.facebook.buck.rules.DependencyGraph;
 import com.facebook.buck.rules.FakeAbstractBuildRuleBuilderParams;
+import com.facebook.buck.rules.FakeBuildRuleParams;
 import com.facebook.buck.rules.FakeBuildableContext;
+import com.facebook.buck.rules.FakeRuleKeyBuilderFactory;
 import com.facebook.buck.rules.FileSourcePath;
 import com.facebook.buck.rules.JavaPackageFinder;
 import com.facebook.buck.rules.NoopArtifactCache;
@@ -66,7 +68,6 @@
 import com.facebook.buck.util.ProjectFilesystem;
 import com.facebook.buck.util.Verbosity;
 import com.facebook.buck.util.environment.Platform;
-import com.google.common.base.Functions;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Splitter;
@@ -130,15 +131,9 @@
     // android/java/src/com/facebook/base/data.json
     // android/java/src/com/facebook/common/util/data.json
     BuildTarget buildTarget = new BuildTarget("//android/java", "resources");
-    ImmutableSortedSet<BuildRule> deps = ImmutableSortedSet.of();
-    ImmutableSet<BuildTargetPattern> visibilityPatterns = ImmutableSet.of();
-    DefaultJavaLibraryRule javaRule =new DefaultJavaLibraryRule(
-        new BuildRuleParams(
-            buildTarget,
-            deps,
-            visibilityPatterns,
-            /* pathRelativizer */ Functions.<String>identity()),
-        ImmutableSet.<String>of() /* srcs */,
+    DefaultJavaLibraryRule javaRule = new DefaultJavaLibraryRule(
+        new FakeBuildRuleParams(buildTarget),
+        /* srcs */ ImmutableSet.<String>of(),
         ImmutableSet.of(
             new FileSourcePath("android/java/src/com/facebook/base/data.json"),
             new FileSourcePath("android/java/src/com/facebook/common/util/data.json")
@@ -169,15 +164,9 @@
     // android/java/src/com/facebook/base/data.json
     // android/java/src/com/facebook/common/util/data.json
     BuildTarget buildTarget = new BuildTarget("//android/java/src", "resources");
-    ImmutableSortedSet<BuildRule> deps = ImmutableSortedSet.of();
-    ImmutableSet<BuildTargetPattern> visibilityPatterns = ImmutableSet.of();
     DefaultJavaLibraryRule javaRule = new DefaultJavaLibraryRule(
-        new BuildRuleParams(
-            buildTarget,
-            deps,
-            visibilityPatterns,
-            /* pathRelativizer */ Functions.<String>identity()),
-        ImmutableSet.<String>of() /* srcs */,
+        new FakeBuildRuleParams(buildTarget),
+        /* srcs */ ImmutableSet.<String>of(),
         ImmutableSet.<SourcePath>of(
             new FileSourcePath("android/java/src/com/facebook/base/data.json"),
             new FileSourcePath("android/java/src/com/facebook/common/util/data.json")
@@ -209,15 +198,9 @@
     // android/java/src/com/facebook/base/data.json
     // android/java/src/com/facebook/common/util/data.json
     BuildTarget buildTarget = new BuildTarget("//android/java/src/com/facebook", "resources");
-    ImmutableSortedSet<BuildRule> deps = ImmutableSortedSet.of();
-    ImmutableSet<BuildTargetPattern> visibilityPatterns = ImmutableSet.of();
     DefaultJavaLibraryRule javaRule = new DefaultJavaLibraryRule(
-        new BuildRuleParams(
-            buildTarget,
-            deps,
-            visibilityPatterns,
-            /* pathRelativizer */ Functions.<String>identity()),
-        ImmutableSet.<String>of() /* srcs */,
+        new FakeBuildRuleParams(buildTarget),
+        /* srcs */ ImmutableSet.<String>of(),
         ImmutableSet.of(
             new FileSourcePath("android/java/src/com/facebook/base/data.json"),
             new FileSourcePath("android/java/src/com/facebook/common/util/data.json")
@@ -258,7 +241,7 @@
     ProjectFilesystem projectFilesystem = new ProjectFilesystem(tmp.getRoot());
     DefaultJavaLibraryRule javaLibrary = ruleResolver.buildAndAddToIndex(
         AndroidLibraryRule.newAndroidLibraryRuleBuilder(
-            new DefaultBuildRuleBuilderParams(projectFilesystem))
+            new DefaultBuildRuleBuilderParams(projectFilesystem, new FakeRuleKeyBuilderFactory()))
         .setBuildTarget(buildTarget)
         .addSrc(src));
 
@@ -640,11 +623,7 @@
       ImmutableSet<BuildRule> deps,
       boolean exportDeps) {
     return new DefaultJavaLibraryRule(
-        new BuildRuleParams(buildTarget,
-            /* deps */ ImmutableSortedSet.copyOf(deps),
-            /* visibilityPatterns */ ImmutableSet.<BuildTargetPattern>of(),
-            /* pathRelativizer */ Functions.<String>identity()
-        ),
+        new FakeBuildRuleParams(buildTarget, ImmutableSortedSet.copyOf(deps)),
         srcs,
         /* resources */ ImmutableSet.<SourcePath>of(),
         /* proguardConfig */ Optional.<String>absent(),
@@ -828,7 +807,7 @@
       @Override
       public BuildRule createRule(BuildTarget target) {
         return new PrebuiltJarRule(
-            createBuildRuleParams(target),
+            new FakeBuildRuleParams(target),
             "MyJar",
             Optional.<String>absent(),
             Optional.<String>absent());
@@ -838,7 +817,7 @@
       @Override
       public BuildRule createRule(BuildTarget target) {
         return new JavaBinaryRule(
-            createBuildRuleParams(target),
+            new FakeBuildRuleParams(target),
             "com.facebook.Main",
             null,
             null,
@@ -849,7 +828,7 @@
       @Override
       public BuildRule createRule(BuildTarget target) {
         return new DefaultJavaLibraryRule(
-            createBuildRuleParams(target),
+            new FakeBuildRuleParams(target),
             ImmutableSet.<String>of("MyClass.java"),
             ImmutableSet.<SourcePath>of(),
             Optional.of("MyProguardConfig"),
@@ -864,14 +843,6 @@
       this.targetName = targetName;
     }
 
-    protected BuildRuleParams createBuildRuleParams(BuildTarget target) {
-      return new BuildRuleParams(
-          target,
-          ImmutableSortedSet.<BuildRule>of(),
-          ImmutableSet.of(BuildTargetPattern.MATCH_ALL),
-          /* pathRelativizer */ Functions.<String>identity());
-    }
-
     public BuildTarget createTarget() {
       return BuildTargetFactory.newInstance(targetName);
     }
@@ -944,7 +915,8 @@
               buildTarget,
               /* deps */ ImmutableSortedSet.<BuildRule>of(),
               /* visibilityPatterns */ ImmutableSet.<BuildTargetPattern>of(),
-              projectFilesystem.getPathRelativizer()),
+              projectFilesystem.getPathRelativizer(),
+              new FakeRuleKeyBuilderFactory()),
           ImmutableSet.of(src),
           /* resources */ ImmutableSet.<SourcePath>of(),
           /* proguardConfig */ Optional.<String>absent(),
diff --git a/test/com/facebook/buck/java/PrebuiltJarRuleTest.java b/test/com/facebook/buck/java/PrebuiltJarRuleTest.java
index 0a7fa63..66ed507 100644
--- a/test/com/facebook/buck/java/PrebuiltJarRuleTest.java
+++ b/test/com/facebook/buck/java/PrebuiltJarRuleTest.java
@@ -20,21 +20,17 @@
 import static org.junit.Assert.assertTrue;
 
 import com.facebook.buck.model.BuildTarget;
-import com.facebook.buck.model.BuildTargetPattern;
 import com.facebook.buck.rules.AbiRule;
 import com.facebook.buck.rules.BuildContext;
-import com.facebook.buck.rules.BuildRule;
 import com.facebook.buck.rules.BuildRuleParams;
+import com.facebook.buck.rules.FakeBuildRuleParams;
 import com.facebook.buck.rules.FakeBuildableContext;
 import com.facebook.buck.rules.Sha1HashCode;
 import com.facebook.buck.step.ExecutionContext;
 import com.facebook.buck.step.Step;
 import com.facebook.buck.step.TestExecutionContext;
-import com.google.common.base.Functions;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.hash.HashCode;
 import com.google.common.hash.Hashing;
 import com.google.common.io.ByteStreams;
@@ -56,11 +52,7 @@
 
   @Before
   public void setUp() {
-    BuildRuleParams buildRuleParams = new BuildRuleParams(
-        new BuildTarget("//lib", "junit"),
-        /* deps */ ImmutableSortedSet.<BuildRule>of(),
-        /* visibilityPatterns */ ImmutableSet.of(BuildTargetPattern.MATCH_ALL),
-        /* pathRelativizer */ Functions.<String>identity());
+    BuildRuleParams buildRuleParams = new FakeBuildRuleParams(new BuildTarget("//lib", "junit"));
     junitJarRule = new PrebuiltJarRule(buildRuleParams,
         PATH_TO_JUNIT_JAR,
         Optional.of("lib/junit-4.11-sources.jar"),
diff --git a/test/com/facebook/buck/parser/BUCK b/test/com/facebook/buck/parser/BUCK
index 1cbc2e6..e73b2fd 100644
--- a/test/com/facebook/buck/parser/BUCK
+++ b/test/com/facebook/buck/parser/BUCK
@@ -65,6 +65,7 @@
     '//src/com/facebook/buck/rules:rules',
     '//src/com/facebook/buck/util:io',
     '//src/com/facebook/buck/util:util',
+    '//test/com/facebook/buck/rules:testutil',
     '//test/com/facebook/buck/testutil:testutil',
   ],
   visibility = [
diff --git a/test/com/facebook/buck/parser/BuildRuleFactoryParamsTest.java b/test/com/facebook/buck/parser/BuildRuleFactoryParamsTest.java
index 28e151a..1245df4 100644
--- a/test/com/facebook/buck/parser/BuildRuleFactoryParamsTest.java
+++ b/test/com/facebook/buck/parser/BuildRuleFactoryParamsTest.java
@@ -30,6 +30,7 @@
 import com.facebook.buck.model.BuildTargetFactory;
 import com.facebook.buck.rules.AbstractBuildRuleBuilder;
 import com.facebook.buck.rules.BuildTargetSourcePath;
+import com.facebook.buck.rules.FakeRuleKeyBuilderFactory;
 import com.facebook.buck.rules.FileSourcePath;
 import com.facebook.buck.rules.SourcePath;
 import com.facebook.buck.util.HumanReadableException;
@@ -93,7 +94,8 @@
         filesystem,
         tree,
         parser,
-        buildTarget);
+        buildTarget,
+        new FakeRuleKeyBuilderFactory());
 
     assertEquals("build.xml",
         params.resolveFilePathRelativeToBuildFileDirectory("build.xml"));
@@ -108,7 +110,8 @@
         filesystem,
         tree,
         parser,
-        buildTarget);
+        buildTarget,
+        new FakeRuleKeyBuilderFactory());
     assertEquals("src/com/facebook/A.java",
         params.resolveFilePathRelativeToBuildFileDirectory("A.java"));
   }
@@ -121,7 +124,8 @@
         filesystem,
         tree,
         parser,
-        buildTarget);
+        buildTarget,
+        new FakeRuleKeyBuilderFactory());
     // File exists, but is in a parent directory.
     try {
       params.resolveFilePathRelativeToBuildFileDirectory("../A.java");
@@ -143,7 +147,8 @@
         filesystem,
         tree,
         parser,
-        buildTarget);
+        buildTarget,
+        new FakeRuleKeyBuilderFactory());
     try {
       // File exists, but crosses a buck package boundary.
       params.resolveFilePathRelativeToBuildFileDirectory("demo/B.java");
@@ -165,7 +170,8 @@
         filesystem,
         tree,
         parser,
-        buildTarget);
+        buildTarget,
+        new FakeRuleKeyBuilderFactory());
     // File exists, is in a subdir but does not cross a buck package boundary
     String relativePath = params.resolveFilePathRelativeToBuildFileDirectory("nobuild/C.java");
     assertEquals("src/com/facebook/nobuild/C.java", relativePath);
@@ -180,7 +186,8 @@
         filesystem,
         tree,
         parser,
-        target);
+        target,
+        new FakeRuleKeyBuilderFactory());
     AbstractBuildRuleBuilder<?> builder = createMock(AbstractBuildRuleBuilder.class);
     replay(builder);
 
@@ -200,7 +207,8 @@
         filesystem,
         tree,
         parser,
-        target);
+        target,
+        new FakeRuleKeyBuilderFactory());
     DefaultJavaLibraryRule.Builder builder = createMock(DefaultJavaLibraryRule.Builder.class);
     expect(builder.addDep(
         new BuildTarget(
@@ -225,7 +233,8 @@
         filesystem,
         tree,
         parser,
-        target);
+        target,
+        new FakeRuleKeyBuilderFactory());
     AbstractBuildRuleBuilder<?> builder = createMock(AbstractBuildRuleBuilder.class);
     replay(builder);
 
@@ -251,7 +260,8 @@
         filesystem,
         tree,
         parser,
-        target);
+        target,
+        new FakeRuleKeyBuilderFactory());
     DefaultJavaLibraryRule.Builder builder = createMock(DefaultJavaLibraryRule.Builder.class);
     expect(builder.addDep(
         new BuildTarget(
diff --git a/test/com/facebook/buck/parser/NonCheckingBuildRuleFactoryParams.java b/test/com/facebook/buck/parser/NonCheckingBuildRuleFactoryParams.java
index f383fc8..623af34 100644
--- a/test/com/facebook/buck/parser/NonCheckingBuildRuleFactoryParams.java
+++ b/test/com/facebook/buck/parser/NonCheckingBuildRuleFactoryParams.java
@@ -18,6 +18,7 @@
 
 import com.facebook.buck.model.BuildFileTree;
 import com.facebook.buck.model.BuildTarget;
+import com.facebook.buck.rules.FakeRuleKeyBuilderFactory;
 import com.facebook.buck.util.Paths;
 import com.facebook.buck.util.ProjectFilesystem;
 import com.google.common.collect.ImmutableSet;
@@ -41,7 +42,8 @@
         new NonCheckingBuildFileTree(),
         buildTargetParser,
         target,
-        true /* ignoreFileExistenceChecks */);
+        new FakeRuleKeyBuilderFactory(),
+        /* ignoreFileExistenceChecks */ true);
   }
 
   private static class NonCheckingBuildFileTree extends BuildFileTree {
diff --git a/test/com/facebook/buck/parser/ParserTest.java b/test/com/facebook/buck/parser/ParserTest.java
index ab019a0..a03dc9f 100644
--- a/test/com/facebook/buck/parser/ParserTest.java
+++ b/test/com/facebook/buck/parser/ParserTest.java
@@ -42,6 +42,7 @@
 import com.facebook.buck.rules.BuildRuleType;
 import com.facebook.buck.rules.DependencyGraph;
 import com.facebook.buck.rules.FakeBuildRule;
+import com.facebook.buck.rules.FakeRuleKeyBuilderFactory;
 import com.facebook.buck.rules.KnownBuildRuleTypes;
 import com.facebook.buck.testutil.BuckTestConstant;
 import com.facebook.buck.testutil.TestConsole;
@@ -183,7 +184,8 @@
         buildTargetParser,
         knownBuildTargets,
         buildFileParserFactory,
-        tempFilePatterns);
+        tempFilePatterns,
+        new FakeRuleKeyBuilderFactory());
   }
 
   /**
@@ -207,7 +209,8 @@
         new KnownBuildRuleTypes(),
         new TestConsole(),
         BuckTestConstant.PYTHON_INTERPRETER,
-        tempFilePatterns);
+        tempFilePatterns,
+        new FakeRuleKeyBuilderFactory());
 
     parser.parseRawRulesInternal(ruleObjects);
     RawRulePredicate predicate = alwaysTrue();
diff --git a/test/com/facebook/buck/python/BUCK b/test/com/facebook/buck/python/BUCK
index f1af3bb..45d7bf3 100644
--- a/test/com/facebook/buck/python/BUCK
+++ b/test/com/facebook/buck/python/BUCK
@@ -13,5 +13,6 @@
     '//src/com/facebook/buck/rules:rules',
     '//src/com/facebook/buck/util:io',
     '//test/com/facebook/buck/model:BuildTargetFactory',
+    '//test/com/facebook/buck/rules:testutil',
   ],
 )
diff --git a/test/com/facebook/buck/python/PythonLibraryTest.java b/test/com/facebook/buck/python/PythonLibraryTest.java
index 59977bb..014a58a 100644
--- a/test/com/facebook/buck/python/PythonLibraryTest.java
+++ b/test/com/facebook/buck/python/PythonLibraryTest.java
@@ -20,12 +20,9 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
-import com.facebook.buck.model.BuildTargetFactory;
-import com.facebook.buck.model.BuildTargetPattern;
-import com.facebook.buck.rules.BuildRule;
+import com.facebook.buck.model.BuildTarget;
 import com.facebook.buck.rules.BuildRuleParams;
-import com.google.common.base.Functions;
-import com.google.common.collect.ImmutableSet;
+import com.facebook.buck.rules.FakeBuildRuleParams;
 import com.google.common.collect.ImmutableSortedSet;
 
 import org.junit.Test;
@@ -37,11 +34,8 @@
 
   @Test
   public void testGetters() {
-    BuildRuleParams buildRuleParams = new BuildRuleParams(
-        BuildTargetFactory.newInstance("//scripts/python:foo"),
-        /* deps */ ImmutableSortedSet.<BuildRule>of(),
-        /* visibilityPatterns */ ImmutableSet.<BuildTargetPattern>of(),
-        /* pathRelativizer */ Functions.<String>identity());
+    BuildRuleParams buildRuleParams = new FakeBuildRuleParams(
+        new BuildTarget("//scripts/python", "foo"));
     ImmutableSortedSet<String> srcs = ImmutableSortedSet.of("");
     PythonLibrary pythonLibrary = new PythonLibrary(
         buildRuleParams,
diff --git a/test/com/facebook/buck/rules/AbstractBuildRuleTest.java b/test/com/facebook/buck/rules/AbstractBuildRuleTest.java
index 5d80c19..a27a3f0 100644
--- a/test/com/facebook/buck/rules/AbstractBuildRuleTest.java
+++ b/test/com/facebook/buck/rules/AbstractBuildRuleTest.java
@@ -26,7 +26,6 @@
 import com.facebook.buck.model.SingletonBuildTargetPattern;
 import com.facebook.buck.model.SubdirectoryBuildTargetPattern;
 import com.facebook.buck.rules.BuildRuleSuccess.Type;
-import com.google.common.base.Functions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
@@ -192,11 +191,10 @@
     Comparator<BuildRule> comparator = RetainOrderComparator.createComparator(deps);
     ImmutableSortedSet<BuildRule> sortedDeps = ImmutableSortedSet.copyOf(comparator, deps);
 
-    BuildRuleParams buildRuleParams = new BuildRuleParams(
+    BuildRuleParams buildRuleParams = new FakeBuildRuleParams(
         buildTarget,
         sortedDeps,
-        visibilityPatterns,
-        /* pathRelativizer */ Functions.<String>identity());
+        visibilityPatterns);
     return new AbstractBuildRule(buildRuleParams) {
       @Override
       public BuildRuleType getType() {
diff --git a/test/com/facebook/buck/rules/AbstractCachingBuildRuleTest.java b/test/com/facebook/buck/rules/AbstractCachingBuildRuleTest.java
index bf64210..2b6f3ed 100644
--- a/test/com/facebook/buck/rules/AbstractCachingBuildRuleTest.java
+++ b/test/com/facebook/buck/rules/AbstractCachingBuildRuleTest.java
@@ -28,7 +28,6 @@
 import com.facebook.buck.event.BuckEventBusFactory;
 import com.facebook.buck.event.FakeBuckEventListener;
 import com.facebook.buck.model.BuildTarget;
-import com.facebook.buck.model.BuildTargetPattern;
 import com.facebook.buck.step.AbstractExecutionStep;
 import com.facebook.buck.step.ExecutionContext;
 import com.facebook.buck.step.Step;
@@ -39,7 +38,6 @@
 import com.facebook.buck.testutil.integration.DebuggableTemporaryFolder;
 import com.facebook.buck.util.ProjectFilesystem;
 import com.facebook.buck.util.concurrent.MoreFutures;
-import com.google.common.base.Functions;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -131,9 +129,6 @@
     resetAll();
 
     String expectedRuleKeyHash = Hashing.sha1().newHasher()
-        .putBytes(RuleKey.Builder.buckVersionUID.getBytes())
-        .putByte(RuleKey.Builder.SEPARATOR)
-
         .putByte(RuleKey.Builder.SEPARATOR)
         .putBytes("name".getBytes())
         .putByte(RuleKey.Builder.SEPARATOR)
@@ -235,10 +230,7 @@
   @Test
   public void testAbiRuleCanAvoidRebuild()
       throws InterruptedException, ExecutionException, IOException {
-    BuildRuleParams buildRuleParams = new BuildRuleParams(buildTarget,
-        /* sortedDeps */ ImmutableSortedSet.<BuildRule>of(),
-        /* visibilityPatterns */ ImmutableSet.<BuildTargetPattern>of(),
-        /* pathRelativizer */ Functions.<String>identity());
+    BuildRuleParams buildRuleParams = new FakeBuildRuleParams(buildTarget);
     TestAbstractCachingBuildRule buildRule = new TestAbstractCachingBuildRule(buildRuleParams);
 
     // The EventBus should be updated with events indicating how the rule was built.
@@ -393,10 +385,7 @@
     Comparator<BuildRule> comparator = RetainOrderComparator.createComparator(deps);
     ImmutableSortedSet<BuildRule> sortedDeps = ImmutableSortedSet.copyOf(comparator, deps);
 
-    BuildRuleParams buildRuleParams = new BuildRuleParams(buildTarget,
-        sortedDeps,
-        /* visibilityPatterns */ ImmutableSet.<BuildTargetPattern>of(),
-        /* pathRelativizer */ Functions.<String>identity());
+    BuildRuleParams buildRuleParams = new FakeBuildRuleParams(buildTarget, sortedDeps);
     return new BuildableAbstractCachingBuildRule(buildRuleParams,
         inputRules,
         pathToOutputFile,
diff --git a/test/com/facebook/buck/rules/BUCK b/test/com/facebook/buck/rules/BUCK
index 5d840b8..72bb8b7 100644
--- a/test/com/facebook/buck/rules/BUCK
+++ b/test/com/facebook/buck/rules/BUCK
@@ -5,7 +5,9 @@
     'FakeAbstractBuildRuleBuilderParams.java',
     'FakeBuildableContext.java',
     'FakeBuildRule.java',
+    'FakeBuildRuleParams.java',
     'FakeInputRule.java',
+    'FakeRuleKeyBuilderFactory.java',
     'FakeTestRule.java',
     'RetainOrderComparator.java',
   ],
diff --git a/test/com/facebook/buck/rules/BuildRuleParamsFactory.java b/test/com/facebook/buck/rules/BuildRuleParamsFactory.java
index cf5a81d..484ce3f 100644
--- a/test/com/facebook/buck/rules/BuildRuleParamsFactory.java
+++ b/test/com/facebook/buck/rules/BuildRuleParamsFactory.java
@@ -17,10 +17,7 @@
 package com.facebook.buck.rules;
 
 import com.facebook.buck.model.BuildTarget;
-import com.facebook.buck.model.BuildTargetPattern;
-import com.google.common.base.Functions;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSortedSet;
 
 public class BuildRuleParamsFactory {
 
@@ -32,10 +29,6 @@
    *     that returns the parameter it receives verbatim.
    */
   public static BuildRuleParams createTrivialBuildRuleParams(BuildTarget buildTarget) {
-    return new BuildRuleParams(
-        Preconditions.checkNotNull(buildTarget),
-        /* deps */ ImmutableSortedSet.<BuildRule>of(),
-        /* visibilityPatterns */ ImmutableSortedSet.<BuildTargetPattern>of(),
-        /* pathRelativizer */ Functions.<String>identity());
+    return new FakeBuildRuleParams(Preconditions.checkNotNull(buildTarget));
   }
 }
diff --git a/test/com/facebook/buck/rules/FakeAbstractBuildRuleBuilderParams.java b/test/com/facebook/buck/rules/FakeAbstractBuildRuleBuilderParams.java
index 706a36c..55336db 100644
--- a/test/com/facebook/buck/rules/FakeAbstractBuildRuleBuilderParams.java
+++ b/test/com/facebook/buck/rules/FakeAbstractBuildRuleBuilderParams.java
@@ -19,12 +19,16 @@
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
 
-public class FakeAbstractBuildRuleBuilderParams implements
-    AbstractBuildRuleBuilderParams {
+public class FakeAbstractBuildRuleBuilderParams implements AbstractBuildRuleBuilderParams {
 
   @Override
   public Function<String, String> getPathRelativizer() {
     return Functions.identity();
   }
 
+  @Override
+  public RuleKeyBuilderFactory getRuleKeyBuilderFactory() {
+    return new FakeRuleKeyBuilderFactory();
+  }
+
 }
diff --git a/test/com/facebook/buck/rules/FakeBuildRule.java b/test/com/facebook/buck/rules/FakeBuildRule.java
index bfec7a1..016c560 100644
--- a/test/com/facebook/buck/rules/FakeBuildRule.java
+++ b/test/com/facebook/buck/rules/FakeBuildRule.java
@@ -19,7 +19,6 @@
 import com.facebook.buck.model.BuildTarget;
 import com.facebook.buck.model.BuildTargetPattern;
 import com.facebook.buck.step.Step;
-import com.google.common.base.Functions;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -43,11 +42,7 @@
       ImmutableSortedSet<BuildRule> deps,
       ImmutableSet<BuildTargetPattern> visibilityPatterns) {
     this(type,
-        new BuildRuleParams(
-            target,
-            deps,
-            visibilityPatterns,
-            /* pathRelativizer */ Functions.<String>identity()));
+        new FakeBuildRuleParams(target, deps, visibilityPatterns));
   }
 
   public FakeBuildRule(BuildRuleType type, BuildRuleParams buildRuleParams) {
diff --git a/test/com/facebook/buck/rules/FakeBuildRuleParams.java b/test/com/facebook/buck/rules/FakeBuildRuleParams.java
new file mode 100644
index 0000000..51675dd
--- /dev/null
+++ b/test/com/facebook/buck/rules/FakeBuildRuleParams.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013-present Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.facebook.buck.rules;
+
+import com.facebook.buck.model.BuildTarget;
+import com.facebook.buck.model.BuildTargetPattern;
+import com.google.common.base.Functions;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+
+public class FakeBuildRuleParams extends BuildRuleParams {
+
+  public FakeBuildRuleParams(BuildTarget buildTarget) {
+    this(buildTarget, /* deps */ ImmutableSortedSet.<BuildRule>of());
+  }
+
+  public FakeBuildRuleParams(BuildTarget buildTarget, ImmutableSortedSet<BuildRule> deps) {
+    this(buildTarget, deps, /* visibilityPatterns */ ImmutableSet.of(BuildTargetPattern.MATCH_ALL));
+  }
+
+  public FakeBuildRuleParams(BuildTarget buildTarget,
+      ImmutableSortedSet<BuildRule> deps,
+      ImmutableSet<BuildTargetPattern> visibilityPatterns) {
+    super(buildTarget,
+        deps,
+        visibilityPatterns,
+        /* pathRelativizer */ Functions.<String>identity(),
+        new FakeRuleKeyBuilderFactory());
+  }
+
+}
diff --git a/test/com/facebook/buck/rules/FakeRuleKeyBuilderFactory.java b/test/com/facebook/buck/rules/FakeRuleKeyBuilderFactory.java
new file mode 100644
index 0000000..3d32a82
--- /dev/null
+++ b/test/com/facebook/buck/rules/FakeRuleKeyBuilderFactory.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012-present Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.facebook.buck.rules;
+
+import com.facebook.buck.rules.RuleKey.Builder;
+
+/**
+ * Basic implementation of {@link RuleKeyBuilderFactory} that does not inject any contextual
+ * information when creating a {@link RuleKey.Builder}.
+ */
+public class FakeRuleKeyBuilderFactory implements RuleKeyBuilderFactory {
+
+  @Override
+  public Builder newInstance(BuildRule buildRule) {
+    return RuleKey.builder(buildRule);
+  }
+
+}
diff --git a/test/com/facebook/buck/rules/FakeTestRule.java b/test/com/facebook/buck/rules/FakeTestRule.java
index 7c350f6..79fd7ab 100644
--- a/test/com/facebook/buck/rules/FakeTestRule.java
+++ b/test/com/facebook/buck/rules/FakeTestRule.java
@@ -20,7 +20,6 @@
 import com.facebook.buck.step.ExecutionContext;
 import com.facebook.buck.step.Step;
 import com.facebook.buck.test.TestResults;
-import com.google.common.base.Functions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
@@ -41,11 +40,7 @@
                        ImmutableSet<BuildTargetPattern> visibilityPatterns) {
     this(type,
         labels,
-        new BuildRuleParams(
-            target,
-            deps,
-            visibilityPatterns,
-            /* pathRelativizer */ Functions.<String>identity()));
+        new FakeBuildRuleParams(target, deps, visibilityPatterns));
   }
 
   public FakeTestRule(BuildRuleType type,
diff --git a/test/com/facebook/buck/rules/ProjectConfigRuleTest.java b/test/com/facebook/buck/rules/ProjectConfigRuleTest.java
index ad87f1b..8153b22 100644
--- a/test/com/facebook/buck/rules/ProjectConfigRuleTest.java
+++ b/test/com/facebook/buck/rules/ProjectConfigRuleTest.java
@@ -21,11 +21,8 @@
 
 import com.facebook.buck.java.DefaultJavaLibraryRule;
 import com.facebook.buck.java.JavaLibraryRule;
+import com.facebook.buck.model.BuildTarget;
 import com.facebook.buck.model.BuildTargetFactory;
-import com.facebook.buck.model.BuildTargetPattern;
-import com.google.common.base.Functions;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.util.concurrent.ListenableFuture;
 
 import org.easymock.EasyMockSupport;
@@ -61,11 +58,8 @@
         DefaultJavaLibraryRule.newJavaLibraryRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
         .setBuildTarget(BuildTargetFactory.newInstance("//javatests:lib")));
 
-    BuildRuleParams buildRuleParams = new BuildRuleParams(
-        BuildTargetFactory.newInstance("//javatests:project_config"),
-        /* deps */ ImmutableSortedSet.<BuildRule>of(),
-        /* visibility */ ImmutableSet.<BuildTargetPattern>of(),
-        /* pathRelativizer */ Functions.<String>identity());
+    BuildRuleParams buildRuleParams = new FakeBuildRuleParams(
+        new BuildTarget("//javatests", "project_config"));
     return new ProjectConfigRule(
         buildRuleParams,
         /* srcRule */ javaRule,
diff --git a/test/com/facebook/buck/shell/ExportFileTest.java b/test/com/facebook/buck/shell/ExportFileTest.java
index d1d02e6..4d2e1b0 100644
--- a/test/com/facebook/buck/shell/ExportFileTest.java
+++ b/test/com/facebook/buck/shell/ExportFileTest.java
@@ -20,13 +20,12 @@
 import com.facebook.buck.event.BuckEventBusFactory;
 import com.facebook.buck.graph.MutableDirectedGraph;
 import com.facebook.buck.model.BuildTarget;
-import com.facebook.buck.model.BuildTargetFactory;
-import com.facebook.buck.model.BuildTargetPattern;
 import com.facebook.buck.rules.ArtifactCache;
 import com.facebook.buck.rules.BuildContext;
 import com.facebook.buck.rules.BuildRule;
 import com.facebook.buck.rules.BuildRuleParams;
 import com.facebook.buck.rules.DependencyGraph;
+import com.facebook.buck.rules.FakeBuildRuleParams;
 import com.facebook.buck.rules.FakeBuildableContext;
 import com.facebook.buck.rules.JavaPackageFinder;
 import com.facebook.buck.step.Step;
@@ -36,11 +35,8 @@
 import com.facebook.buck.testutil.MoreAsserts;
 import com.facebook.buck.util.AndroidPlatformTarget;
 import com.facebook.buck.util.ProjectFilesystem;
-import com.google.common.base.Functions;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 
@@ -61,11 +57,7 @@
 
   @Before
   public void createFixtures() {
-    BuildTarget target = BuildTargetFactory.newInstance("//:example.html");
-    params = new BuildRuleParams(target,
-        ImmutableSortedSet.<BuildRule>of(),
-        ImmutableSet.<BuildTargetPattern>of(),
-        /* pathRelativizer */ Functions.<String>identity());
+    params = new FakeBuildRuleParams(new BuildTarget("//", "example.html"));
     root = new File(".");
     context = getBuildContext(root);
   }
diff --git a/test/com/facebook/buck/shell/ShTestRuleTest.java b/test/com/facebook/buck/shell/ShTestRuleTest.java
index dce1299..ee1083a 100644
--- a/test/com/facebook/buck/shell/ShTestRuleTest.java
+++ b/test/com/facebook/buck/shell/ShTestRuleTest.java
@@ -18,15 +18,11 @@
 
 import static org.junit.Assert.assertTrue;
 
-import com.facebook.buck.model.BuildTargetFactory;
-import com.facebook.buck.model.BuildTargetPattern;
-import com.facebook.buck.rules.BuildRule;
-import com.facebook.buck.rules.BuildRuleParams;
+import com.facebook.buck.model.BuildTarget;
+import com.facebook.buck.rules.FakeBuildRuleParams;
 import com.facebook.buck.step.ExecutionContext;
 import com.facebook.buck.util.ProjectFilesystem;
-import com.google.common.base.Functions;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
 
 import org.easymock.EasyMock;
 import org.easymock.EasyMockSupport;
@@ -44,7 +40,7 @@
   @Test
   public void testHasTestResultFiles() {
     ShTestRule shTest = new ShTestRule(
-        createBuildRuleParams(),
+        new FakeBuildRuleParams(new BuildTarget("//test/com/example", "my_sh_test")),
         "run_test.sh",
         /* labels */ ImmutableSet.<String>of());
 
@@ -58,12 +54,4 @@
     assertTrue("hasTestResultFiles() should return true if result.json exists.",
         shTest.hasTestResultFiles(executionContext));
   }
-
-  private static BuildRuleParams createBuildRuleParams() {
-    return new BuildRuleParams(
-        BuildTargetFactory.newInstance("//test/com/example:my_sh_test"),
-        /* deps */ ImmutableSortedSet.<BuildRule>of(),
-        /* visibilityPatterns */ ImmutableSet.<BuildTargetPattern>of(),
-        /* pathRelativizer */ Functions.<String>identity());
-  }
 }