('/**\\n   * Create a new {@link KijiResult} backed by Cassandra.\\n   *\\n   * @param entityId EntityId of the row from which to read cells.\\n   * @param dataRequest KijiDataRequest defining the values to retrieve.\\n   * @param table The table being viewed.\\n   * @param layout The layout of the table.\\n   * @param columnTranslator A column name translator for the table.\\n   * @param decoderProvider A cell decoder provider for the table.\\n   * @param <T> The type of value in the {@code KijiCell} of this view.\\n   * @return an {@code KijiResult}.\\n   * @throws IOException On error while decoding cells.\\n   */', '')

b'/**\n   * Create a new {@link KijiResult} backed by Cassandra.\n   *\n   * @param entityId EntityId of the row from which to read cells.\n   * @param dataRequest KijiDataRequest defining the values to retrieve.\n   * @param table The table being viewed.\n   * @param layout The layout of the table.\n   * @param columnTranslator A column name translator for the table.\n   * @param decoderProvider A cell decoder provider for the table.\n   * @param <T> The type of value in the {@code KijiCell} of this view.\n   * @return an {@code KijiResult}.\n   * @throws IOException On error while decoding cells.\n   */'public static <T> KijiResult<T> create(
      final EntityId entityId,
      final KijiDataRequest dataRequest,
      final CassandraKijiTable table,
      final KijiTableLayout layout,
      final CassandraColumnNameTranslator columnTranslator,
      final CellDecoderProvider decoderProvider
  ) throws IOException {
    final KijiDataRequestBuilder unpagedRequestBuilder = KijiDataRequest.builder();
    final KijiDataRequestBuilder pagedRequestBuilder = KijiDataRequest.builder();
    unpagedRequestBuilder.withTimeRange(
        dataRequest.getMinTimestamp(),
        dataRequest.getMaxTimestamp());
    pagedRequestBuilder.withTimeRange(dataRequest.getMinTimestamp(), dataRequest.getMaxTimestamp());

    for (final Column columnRequest : dataRequest.getColumns()) {
      if (columnRequest.getFilter() != null) {
        throw new UnsupportedOperationException(
            String.format("Cassandra Kiji does not support filters on column requests: %s.",
                columnRequest));
      }
      if (columnRequest.isPagingEnabled()) {
        pagedRequestBuilder.newColumnsDef(columnRequest);
      } else {
        unpagedRequestBuilder.newColumnsDef(columnRequest);
      }
    }

    final CellDecoderProvider requestDecoderProvider =
        decoderProvider.getDecoderProviderForRequest(dataRequest);

    final KijiDataRequest unpagedRequest = unpagedRequestBuilder.build();
    final KijiDataRequest pagedRequest = pagedRequestBuilder.build();

    if (unpagedRequest.isEmpty() && pagedRequest.isEmpty()) {
      return new EmptyKijiResult<T>(entityId, dataRequest);
    }

    final MaterializedKijiResult<T> materializedKijiResult;
    if (!unpagedRequest.isEmpty()) {
      materializedKijiResult =
          createMaterialized(
              table.getURI(),
              entityId,
              unpagedRequest,
              layout,
              columnTranslator,
              requestDecoderProvider,
              table.getAdmin());
    } else {
      materializedKijiResult = null;
    }

    final CassandraPagedKijiResult<T> pagedKijiResult;
    if (!pagedRequest.isEmpty()) {
      pagedKijiResult =
          new CassandraPagedKijiResult<T>(
              entityId,
              pagedRequest,
              table,
              layout,
              columnTranslator,
              requestDecoderProvider);
    } else {
      pagedKijiResult = null;
    }

    if (unpagedRequest.isEmpty()) {
      return pagedKijiResult;
    } else if (pagedRequest.isEmpty()) {
      return materializedKijiResult;
    } else {
      return DefaultKijiResult.create(dataRequest, materializedKijiResult, pagedKijiResult);
    }
  }

@Test
  public void testGetMatContents() throws Exception {
    KijiDataRequestBuilder builder = KijiDataRequest.builder().addColumns(ColumnsDef.create()
            .withMaxVersions(10)
            .add(PRIMITIVE_STRING, null)
            .add(STRING_MAP_1, null));
    KijiDataRequest request = builder.build();
    final EntityId eid = mTable.getEntityId(ROW);
    KijiResult<Object> view = mReader.getResult(eid, request);
    SortedMap<KijiColumnName, List<KijiCell<Object>>> map =
        KijiResult.Helpers.getMaterializedContents(view);
    for (KijiColumnName col: map.keySet()) {
      KijiResult<Object> newResult = view.narrowView(col);
      Iterator<KijiCell<Object>> it = newResult.iterator();
      for (KijiCell<Object> cell: map.get(col)) {
        assertEquals(cell, it.next());
      }
      assertTrue(!it.hasNext());
    }
  }


('/**\\n   * Check if the given annotation key is valid.\\n   *\\n   * @param key the annotation key to check.\\n   * @return whether the key is valid.\\n   */', '')

b'/**\n   * Check if the given annotation key is valid.\n   *\n   * @param key the annotation key to check.\n   * @return whether the key is valid.\n   */'public static boolean isValidAnnotationKey(
      final String key
  ) {
    return key.matches(ALLOWED_ANNOTATION_KEY_PATTERN);
  }

@Test
  public void testRegex() {
    final String valid = "abcABC012_";
    assertTrue(CassandraKijiTableAnnotator.isValidAnnotationKey(valid));

    final List<String> invalidStrings =
        Lists.newArrayList("abc?", "abc.", "a$", "a!", "a#", "a-", "");
    for (String invalid : invalidStrings) {
      assertFalse(CassandraKijiTableAnnotator.isValidAnnotationKey(invalid));
    }
  }


['(\'/**\\\\n   * Gets a builder configured with default Kiji URI fields.\\\\n   *\\\\n   * More precisely, the following defaults are initialized:\\\\n   *
\\\\n   *
The Zookeeper quorum and client port is taken from the Hadoop <tt>Configuration</tt>
\\\\n   *
The Kiji instance name is set to <tt>KConstants.DEFAULT_INSTANCE_NAME</tt>\\\\n   *       (<tt>"default"</tt>).
\\\\n   *
The table name and column names are explicitly left unset.
\\\\n   *
\\\\n   *\\\\n   * @return A builder configured with this Kiji URI.\\\\n   */\', \'\')']

b'/**\n   * Gets a builder configured with default Kiji URI fields.\n   *\n   * More precisely, the following defaults are initialized:\n   *
\n   *
The Zookeeper quorum and client port is taken from the Hadoop <tt>Configuration</tt>
\n   *
The Kiji instance name is set to <tt>KConstants.DEFAULT_INSTANCE_NAME</tt>\n   *       (<tt>"default"</tt>).
\n   *
The table name and column names are explicitly left unset.
\n   *
\n   *\n   * @return A builder configured with this Kiji URI.\n   */'public static HBaseKijiURIBuilder newBuilder() {
    return new HBaseKijiURIBuilder();
  }

@Test
  public void testKijiURIBuilderWithInstance() {
    final KijiURI uri = KijiURI.newBuilder("kiji-hbase://zkhost:1234/instance1/table").build();
    assertEquals("instance1", uri.getInstance());
    final KijiURI modified =
        KijiURI.newBuilder(uri).withInstanceName("instance2").build();
    assertEquals("instance2", modified.getInstance());
    assertEquals("instance1", uri.getInstance());
  }


@Test
  public void testSetColumn() {
    KijiURI uri = KijiURI.newBuilder("kiji-hbase://zkhost/instance/table/").build();
    assertTrue(uri.getColumns().isEmpty());
    uri =
        KijiURI.newBuilder(uri).withColumnNames(Arrays.asList("testcol1", "testcol2"))
            .build();
    assertEquals(2, uri.getColumns().size());
  }


@Test
  public void testSetZookeeperQuorum() {
    final KijiURI uri = KijiURI.newBuilder("kiji-hbase://zkhost/instance/table/col").build();
    final KijiURI modified = KijiURI.newBuilder(uri)
        .withZookeeperQuorum(new String[] {"zkhost1", "zkhost2"}).build();
    assertEquals(2, modified.getZookeeperQuorum().size());
    assertEquals("zkhost1", modified.getZookeeperQuorum().get(0));
    assertEquals("zkhost2", modified.getZookeeperQuorum().get(1));
  }


@Test
  public void testTrailingUnset() {
    final KijiURI uri = KijiURI.newBuilder("kiji-hbase://zkhost/.unset/table/.unset").build();
    KijiURI result = KijiURI.newBuilder(uri).withTableName(".unset").build();
    assertEquals("kiji-hbase://zkhost:2181/", result.toString());
  }


@Test
  public void testEscapedMapColumnQualifier() {
    final KijiURI uri =
        KijiURI.newBuilder("kiji-hbase://zkhost/instance/table/map:one%20two").build();
    assertEquals("map:one two", uri.getColumns().get(0).getName());
  }


@Test
  public void testConstructedUriIsEscaped() {
    // SCHEMA-6. Column qualifier must be URL-encoded in KijiURI.
    final KijiURI uri = KijiURI.newBuilder("kiji-hbase://zkhost/instance/table/")
        .addColumnName(KijiColumnName.create("map:one two")).build();
    assertEquals("kiji-hbase://zkhost:2181/instance/table/map:one%20two/", uri.toString());
  }


('/**\\n   * Constructs an HBase Scan that describes the data requested in the KijiDataRequest.\\n   *\\n   * @param tableLayout The layout of the Kiji table to read from.  This is required for\\n   *     determining the mapping between Kiji columns and HBase columns.\\n   * @return An HBase Scan descriptor.\\n   * @throws IOException If there is an error.\\n   */', '')

b'/**\n   * Constructs an HBase Scan that describes the data requested in the KijiDataRequest.\n   *\n   * @param tableLayout The layout of the Kiji table to read from.  This is required for\n   *     determining the mapping between Kiji columns and HBase columns.\n   * @return An HBase Scan descriptor.\n   * @throws IOException If there is an error.\n   */'public Scan toScan(final KijiTableLayout tableLayout) throws IOException {
    return toScan(tableLayout, new HBaseScanOptions());
  }

@Test
  public void testDataRequestToScanEmpty() throws IOException {
    KijiDataRequest request = KijiDataRequest.builder().build();
    HBaseDataRequestAdapter hbaseDataRequest =
        new HBaseDataRequestAdapter(request, mColumnNameTranslator);
    assertFalse(hbaseDataRequest.toScan(mTableLayout).hasFamilies());
  }


('/** {@inheritDoc} */', '')

('', '// No state, so all FirstKeyOnlyFilters are the same\n')

b'/** {@inheritDoc} */'@Override
  public int hashCode() {
    // No state, so all FirstKeyOnlyFilters are the same
    return new HashCodeBuilder().toHashCode();
  }

@Test
  public void testHashCodeAndEquals() {
    KijiFirstKeyOnlyColumnFilter filter1 = new KijiFirstKeyOnlyColumnFilter();
    KijiFirstKeyOnlyColumnFilter filter2 = new KijiFirstKeyOnlyColumnFilter();

    assertEquals(filter1.hashCode(), filter2.hashCode());
    assertEquals(filter1, filter2);
  }


["('/**\\\\n   * Constructs an HBase Get that describes the data requested in the KijiDataRequest for\\\\n   * a particular entity/row.\\\\n   *\\\\n   * @param entityId The row to build an HBase Get request for.\\\\n   * @param tableLayout The layout of the Kiji table to read from.  This is required for\\\\n   *     determining the mapping between Kiji columns and HBase columns.\\\\n   * @return An HBase Get descriptor.\\\\n   * @throws IOException If there is an error.\\\\n   */', '')", "('', '// Context to translate user Kiji filters into HBase filters:\\n')", "('', '// Get request we are building and returning:\\n')", "('', '// Filters for each requested column: OR(<filter-for-column-1>, <filter-for-column2>, ...)\\n')", '(\'\', "// There\'s a shortcoming in the HBase API that doesn\'t allow us to specify per-column\\n")', "('', '// filters for timestamp ranges and max versions.  We need to generate a request that\\n')", "('', '// will include all versions that we need, and add filters for the individual columns.\\n')", "('', '// As of HBase 0.94, the ColumnPaginationFilter, which we had been using to permit per-column\\n')", "('', '// maxVersions settings, no longer pages over multiple versions for the same column. We can\\n')", "('', '// still use it, however, to limit fully-qualified columns with maxVersions = 1 to return only\\n')", '(\'\', "// the most recent version in the request\'s time range. All other columns will use the largest\\n")', "('', '// maxVersions seen on any column request.\\n')", "('', '// Fortunately, although we may retrieve more versions per column than we need from HBase, we\\n')", '(\'\', "// can still honor the user\'s requested maxVersions when returning the versions in\\n")', "('', '// HBaseKijiRowData.\\n')", "('', '// Largest of the max-versions from all the requested columns.\\n')", "('', '// Columns with paging are excluded (max-versions does not make sense when paging):\\n')", "('', '// If every column is paged, we should add a keyonly filter to a single column, so we can have\\n')", "('', '// access to entityIds in our KijiRowData that is constructed.\\n')", "('', '// Do not include max-versions from columns with paging enabled:\\n')", "('', '// Requests a fully-qualified column.\\n')", "('', '// Adds this column to the Get request, and also as a filter.\\n')", "('', '//\\n')", "('', '// Filters are required here because we might end up requesting all cells from the\\n')", "('', '// HBase family (ie. from the Kiji locality group), if a map-type family from that\\n')", "('', '// locality group is also requested.\\n')", "('', '// Requests all columns in a Kiji group-type family.\\n')", "('', '// Expand the family request into individual column requests:\\n')", "('', '// Requests all columns in a Kiji map-type family.\\n')", "('', '// We need to request all columns in the HBase family (ie. in the Kiji locality group)\\n')", "('', '// and add a column prefix-filter to select only the columns from that Kiji family:\\n')", "('', '// All requested columns have paging enabled.\\n')", "('', '// We just need to know whether a row has data in at least one of the requested columns.\\n')", "('', '// Stop at the first valid key using AND(columnFilters, FirstKeyOnlyFilter):\\n')"]

b'/**\n   * Constructs an HBase Get that describes the data requested in the KijiDataRequest for\n   * a particular entity/row.\n   *\n   * @param entityId The row to build an HBase Get request for.\n   * @param tableLayout The layout of the Kiji table to read from.  This is required for\n   *     determining the mapping between Kiji columns and HBase columns.\n   * @return An HBase Get descriptor.\n   * @throws IOException If there is an error.\n   */'public Get toGet(
      final EntityId entityId,
      final KijiTableLayout tableLayout
  ) throws IOException {

    // Context to translate user Kiji filters into HBase filters:
    final KijiColumnFilter.Context filterContext =
        new NameTranslatingFilterContext(mColumnNameTranslator);

    // Get request we are building and returning:
    final Get get = new Get(entityId.getHBaseRowKey());

    // Filters for each requested column: OR(<filter-for-column-1>, <filter-for-column2>, ...)
    final FilterList columnFilters = new FilterList(FilterList.Operator.MUST_PASS_ONE);

    // There's a shortcoming in the HBase API that doesn't allow us to specify per-column
    // filters for timestamp ranges and max versions.  We need to generate a request that
    // will include all versions that we need, and add filters for the individual columns.

    // As of HBase 0.94, the ColumnPaginationFilter, which we had been using to permit per-column
    // maxVersions settings, no longer pages over multiple versions for the same column. We can
    // still use it, however, to limit fully-qualified columns with maxVersions = 1 to return only
    // the most recent version in the request's time range. All other columns will use the largest
    // maxVersions seen on any column request.

    // Fortunately, although we may retrieve more versions per column than we need from HBase, we
    // can still honor the user's requested maxVersions when returning the versions in
    // HBaseKijiRowData.

    // Largest of the max-versions from all the requested columns.
    // Columns with paging are excluded (max-versions does not make sense when paging):
    int largestMaxVersions = 1;

    // If every column is paged, we should add a keyonly filter to a single column, so we can have
    // access to entityIds in our KijiRowData that is constructed.
    boolean completelyPaged = mKijiDataRequest.isPagingEnabled() ? true : false;

    for (KijiDataRequest.Column columnRequest : mKijiDataRequest.getColumns()) {
      final KijiColumnName kijiColumnName = columnRequest.getColumnName();
      final HBaseColumnName hbaseColumnName =
          mColumnNameTranslator.toHBaseColumnName(kijiColumnName);

      if (!columnRequest.isPagingEnabled()) {
        completelyPaged = false;

        // Do not include max-versions from columns with paging enabled:
        largestMaxVersions = Math.max(largestMaxVersions, columnRequest.getMaxVersions());
      }

      if (kijiColumnName.isFullyQualified()) {
        // Requests a fully-qualified column.
        // Adds this column to the Get request, and also as a filter.
        //
        // Filters are required here because we might end up requesting all cells from the
        // HBase family (ie. from the Kiji locality group), if a map-type family from that
        // locality group is also requested.
        addColumn(get, hbaseColumnName);
        columnFilters.addFilter(toFilter(columnRequest, hbaseColumnName, filterContext));

      } else {
        final FamilyLayout fLayout = tableLayout.getFamilyMap().get(kijiColumnName.getFamily());
        if (fLayout.isGroupType()) {
          // Requests all columns in a Kiji group-type family.
          // Expand the family request into individual column requests:
          for (String qualifier : fLayout.getColumnMap().keySet()) {
            final KijiColumnName fqKijiColumnName =
                KijiColumnName.create(kijiColumnName.getFamily(), qualifier);
            final HBaseColumnName fqHBaseColumnName =
                mColumnNameTranslator.toHBaseColumnName(fqKijiColumnName);
            addColumn(get, fqHBaseColumnName);
            columnFilters.addFilter(toFilter(columnRequest, fqHBaseColumnName, filterContext));
          }

        } else if (fLayout.isMapType()) {
          // Requests all columns in a Kiji map-type family.
          // We need to request all columns in the HBase family (ie. in the Kiji locality group)
          // and add a column prefix-filter to select only the columns from that Kiji family:
          get.addFamily(hbaseColumnName.getFamily());
          columnFilters.addFilter(toFilter(columnRequest, hbaseColumnName, filterContext));

        } else {
          throw new InternalKijiError("Family is neither group-type nor map-type");
        }
      }
    }

    if (completelyPaged) {
      // All requested columns have paging enabled.
      Preconditions.checkState(largestMaxVersions == 1);

      // We just need to know whether a row has data in at least one of the requested columns.
      // Stop at the first valid key using AND(columnFilters, FirstKeyOnlyFilter):
      get.setFilter(new FilterList(
          FilterList.Operator.MUST_PASS_ALL, columnFilters, new FirstKeyOnlyFilter()));
    } else {
      get.setFilter(columnFilters);
    }

    return get
        .setTimeRange(mKijiDataRequest.getMinTimestamp(), mKijiDataRequest.getMaxTimestamp())
        .setMaxVersions(largestMaxVersions);
  }

@Test
  public void testDataRequestToGetEmpty() throws IOException {
    KijiDataRequest request = KijiDataRequest.builder().build();
    HBaseDataRequestAdapter hbaseDataRequest =
        new HBaseDataRequestAdapter(request, mColumnNameTranslator);
    assertFalse(
        hbaseDataRequest.toGet(mEntityIdFactory.getEntityId("entity"), mTableLayout).hasFamilies());
  }


('/** {@inheritDoc} */', '')

b'/** {@inheritDoc} */'@Override
  public KijiTable openTable(String tableName) throws IOException {
    final State state = mState.get();
    Preconditions.checkState(state == State.OPEN,
        "Cannot open table in Kiji instance %s in state %s.", this, state);

    if (!getTableNames().contains(tableName)) {
      throw new KijiTableNotFoundException(
          KijiURI.newBuilder(mURI).withTableName(tableName).build());
    }

    return new HBaseKijiTable(
        this,
        tableName,
        mConf,
        mHTableFactory,
        mInstanceMonitor.getTableLayoutMonitor(tableName));
  }

@Test
  public void testOpenUnknownTable() throws Exception {
    final Kiji kiji = getKiji();

    try {
      final KijiTable table = kiji.openTable("unknown");
      Assert.fail("Should not be able to open a table that does not exist!");
    } catch (KijiTableNotFoundException ktnfe) {
      // Expected!
      LOG.debug("Expected error: {}", ktnfe);
      Assert.assertEquals("unknown", ktnfe.getTableURI().getTable());
    }
  }


('/**\\n   * Create a new {@link KijiResult} backed by HBase.\\n   *\\n   * @param entityId EntityId of the row from which to read cells.\\n   * @param dataRequest KijiDataRequest defining the values to retrieve.\\n   * @param unpagedRawResult The unpaged results from the row.\\n   * @param table The table being viewed.\\n   * @param layout The layout of the table.\\n   * @param columnTranslator A column name translator for the table.\\n   * @param decoderProvider A cell decoder provider for the table.\\n   * @param <T> The type of value in the {@code KijiCell} of this view.\\n   * @return an {@code HBaseKijiResult}.\\n   * @throws IOException if error while decoding cells.\\n   */', '')

b'/**\n   * Create a new {@link KijiResult} backed by HBase.\n   *\n   * @param entityId EntityId of the row from which to read cells.\n   * @param dataRequest KijiDataRequest defining the values to retrieve.\n   * @param unpagedRawResult The unpaged results from the row.\n   * @param table The table being viewed.\n   * @param layout The layout of the table.\n   * @param columnTranslator A column name translator for the table.\n   * @param decoderProvider A cell decoder provider for the table.\n   * @param <T> The type of value in the {@code KijiCell} of this view.\n   * @return an {@code HBaseKijiResult}.\n   * @throws IOException if error while decoding cells.\n   */'public static <T> KijiResult<T> create(
      final EntityId entityId,
      final KijiDataRequest dataRequest,
      final Result unpagedRawResult,
      final HBaseKijiTable table,
      final KijiTableLayout layout,
      final HBaseColumnNameTranslator columnTranslator,
      final CellDecoderProvider decoderProvider
  ) throws IOException {
    final Collection<Column> columnRequests = dataRequest.getColumns();
    final KijiDataRequestBuilder unpagedRequestBuilder = KijiDataRequest.builder();
    final KijiDataRequestBuilder pagedRequestBuilder = KijiDataRequest.builder();
    unpagedRequestBuilder.withTimeRange(
        dataRequest.getMinTimestamp(),
        dataRequest.getMaxTimestamp());
    pagedRequestBuilder.withTimeRange(dataRequest.getMinTimestamp(), dataRequest.getMaxTimestamp());

    for (Column columnRequest : columnRequests) {
      if (columnRequest.isPagingEnabled()) {
        pagedRequestBuilder.newColumnsDef(columnRequest);
      } else {
        unpagedRequestBuilder.newColumnsDef(columnRequest);
      }
    }

    final CellDecoderProvider requestDecoderProvider =
        decoderProvider.getDecoderProviderForRequest(dataRequest);

    final KijiDataRequest unpagedRequest = unpagedRequestBuilder.build();
    final KijiDataRequest pagedRequest = pagedRequestBuilder.build();

    if (unpagedRequest.isEmpty() && pagedRequest.isEmpty()) {
      return new EmptyKijiResult<T>(entityId, dataRequest);
    }

    final HBaseMaterializedKijiResult<T> materializedKijiResult;
    if (!unpagedRequest.isEmpty()) {
      materializedKijiResult =
          HBaseMaterializedKijiResult.create(
              entityId,
              unpagedRequest,
              unpagedRawResult,
              layout,
              columnTranslator,
              requestDecoderProvider);
    } else {
      materializedKijiResult = null;
    }

    final HBasePagedKijiResult<T> pagedKijiResult;
    if (!pagedRequest.isEmpty()) {
      pagedKijiResult =
          new HBasePagedKijiResult<T>(
              entityId,
              pagedRequest,
              table,
              layout,
              columnTranslator,
              requestDecoderProvider);
    } else {
      pagedKijiResult = null;
    }

    if (unpagedRequest.isEmpty()) {
      return pagedKijiResult;
    } else if (pagedRequest.isEmpty()) {
      return materializedKijiResult;
    } else {
      return DefaultKijiResult.create(dataRequest, materializedKijiResult, pagedKijiResult);
    }
  }

@Test
  public void testGetFullyQualifiedColumn() throws Exception {
    for (KijiColumnName column : ImmutableList.of(PRIMITIVE_STRING, STRING_MAP_1)) {
      for (int pageSize : ImmutableList.of(0, 1, 2, 10)) {
        { // Single version | no timerange
          final KijiDataRequest request = KijiDataRequest
              .builder()
              .addColumns(
                  ColumnsDef.create()
                      .withPageSize(pageSize)
                      .add(column.getFamily(), column.getQualifier()))
              .build();

          testViewGet(request, Iterables.limit(ROW_DATA.get(column).entrySet(), 1));
        }

        { // Single version | timerange
          final KijiDataRequest request = KijiDataRequest
              .builder()
              .addColumns(
                  ColumnsDef.create()
                      .withPageSize(pageSize)
                      .add(column.getFamily(), column.getQualifier()))
              .withTimeRange(4, 6)
              .build();

          testViewGet(
              request,
              Iterables.limit(ROW_DATA.get(column).subMap(6L, false, 4L, true).entrySet(), 1));
        }

        { // Multiple versions | no timerange
          final KijiDataRequest request = KijiDataRequest
              .builder()
              .addColumns(
                  ColumnsDef.create()
                      .withPageSize(pageSize)
                      .withMaxVersions(100)
                      .add(column.getFamily(), column.getQualifier()))
              .build();

          testViewGet(
              request,
              ROW_DATA.get(column).entrySet());
        }

        { // Multiple versions | timerange
          final KijiDataRequest request = KijiDataRequest
              .builder()
              .addColumns(
                  ColumnsDef.create()
                      .withPageSize(pageSize)
                      .withMaxVersions(100)
                      .add(column.getFamily(), column.getQualifier()))
              .withTimeRange(4, 6)
              .build();

          testViewGet(
              request,
              ROW_DATA.get(column).subMap(6L, false, 4L, true).entrySet());
        }
      }
    }
  }


@Test
  public void testGetMultipleFullyQualifiedColumns() throws Exception {
    final KijiColumnName column1 = PRIMITIVE_STRING;
    final KijiColumnName column2 = STRING_MAP_1;

    for (int pageSize : ImmutableList.of(0, 1, 2, 10)) {

      { // Single version | no timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create()
                    .withPageSize(pageSize)
                    .add(column1.getFamily(), column1.getQualifier())
                    .add(column2.getFamily(), column2.getQualifier()))
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            Iterables.limit(ROW_DATA.get(column1).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            Iterables.limit(ROW_DATA.get(column2).entrySet(), 1);

        testViewGet(request, Iterables.concat(column1Entries, column2Entries));
      }

      { // Single version | timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create()
                    .withPageSize(pageSize)
                    .add(column1.getFamily(), column1.getQualifier())
                    .add(column2.getFamily(), column2.getQualifier()))
            .withTimeRange(4, 6)
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            Iterables.limit(ROW_DATA.get(column1).subMap(6L, false, 4L, true).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            Iterables.limit(ROW_DATA.get(column2).subMap(6L, false, 4L, true).entrySet(), 1);

        testViewGet(request, Iterables.concat(column1Entries, column2Entries));
      }

      { // Multiple versions | no timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create()
                    .withPageSize(pageSize)
                    .withMaxVersions(100)
                    .add(column1.getFamily(), column1.getQualifier())
                    .add(column2.getFamily(), column2.getQualifier()))
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries = ROW_DATA.get(column1).entrySet();
        final Iterable<? extends Entry<Long, ?>> column2Entries = ROW_DATA.get(column2).entrySet();

        testViewGet(request, Iterables.concat(column1Entries, column2Entries));
      }

      { // Multiple versions | timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create()
                    .withPageSize(pageSize)
                    .withMaxVersions(100)
                    .add(column1.getFamily(), column1.getQualifier())
                    .add(column2.getFamily(), column2.getQualifier()))
            .withTimeRange(4, 6)
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            ROW_DATA.get(column1).subMap(6L, false, 4L, true).entrySet();
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            ROW_DATA.get(column2).subMap(6L, false, 4L, true).entrySet();

        testViewGet(request, Iterables.concat(column1Entries, column2Entries));
      }

      { // Mixed versions | timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create()
                    .withPageSize(pageSize)
                    .withMaxVersions(100)
                    .add(column1.getFamily(), column1.getQualifier()))
            .addColumns(
                ColumnsDef.create()
                    .withPageSize(pageSize)
                    .withMaxVersions(1)
                    .add(column2.getFamily(), column2.getQualifier()))
            .withTimeRange(4, 6)
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            ROW_DATA.get(column1).subMap(6L, false, 4L, true).entrySet();
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            Iterables.limit(ROW_DATA.get(column2).subMap(6L, false, 4L, true).entrySet(), 1);

        testViewGet(request, Iterables.concat(column1Entries, column2Entries));
      }

      { // Mixed versions | no timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create()
                    .withPageSize(pageSize)
                    .withMaxVersions(1)
                    .add(column1.getFamily(), column1.getQualifier()))
            .addColumns(
                ColumnsDef.create()
                    .withPageSize(pageSize)
                    .withMaxVersions(100)
                    .add(column2.getFamily(), column2.getQualifier()))
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            Iterables.limit(ROW_DATA.get(column1).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            ROW_DATA.get(column2).entrySet();

        testViewGet(request, Iterables.concat(column1Entries, column2Entries));
      }
    }
  }


@Test
  public void testGetFamilyColumn() throws Exception {
    final Map<String, ? extends List<KijiColumnName>> families =
        ImmutableMap.of(
            PRIMITIVE_FAMILY, ImmutableList.of(PRIMITIVE_DOUBLE, PRIMITIVE_STRING),
            STRING_MAP_FAMILY, ImmutableList.of(STRING_MAP_1, STRING_MAP_2));

    for (Entry<String, ? extends List<KijiColumnName>> family : families.entrySet()) {
      for (int pageSize : ImmutableList.of(0, 1, 2, 10)) {

        final KijiColumnName familyColumn = KijiColumnName.create(family.getKey(), null);
        final KijiColumnName column1 = family.getValue().get(0);
        final KijiColumnName column2 = family.getValue().get(1);

        { // Single version | no timerange
          final KijiDataRequest request = KijiDataRequest
              .builder()
              .addColumns(ColumnsDef.create().withPageSize(pageSize).add(familyColumn))
              .build();

          final Iterable<? extends Entry<Long, ?>> column1Entries =
              Iterables.limit(ROW_DATA.get(column1).entrySet(), 1);
          final Iterable<? extends Entry<Long, ?>> column2Entries =
              Iterables.limit(ROW_DATA.get(column2).entrySet(), 1);

          testViewGet(request, Iterables.concat(column1Entries, column2Entries));
        }

        { // Single version | timerange
          final KijiDataRequest request = KijiDataRequest
              .builder()
              .addColumns(ColumnsDef.create().withPageSize(pageSize).add(familyColumn))
              .withTimeRange(4, 6)
              .build();

          final Iterable<? extends Entry<Long, ?>> column1Entries =
              Iterables.limit(ROW_DATA.get(column1).subMap(6L, false, 4L, true).entrySet(), 1);
          final Iterable<? extends Entry<Long, ?>> column2Entries =
              Iterables.limit(ROW_DATA.get(column2).subMap(6L, false, 4L, true).entrySet(), 1);

          testViewGet(request, Iterables.concat(column1Entries, column2Entries));
        }

        { // Multiple versions | no timerange
          final KijiDataRequest request = KijiDataRequest
              .builder()
              .addColumns(
                  ColumnsDef
                      .create()
                      .withPageSize(pageSize)
                      .withMaxVersions(100)
                      .add(familyColumn))
              .build();

          final Iterable<? extends Entry<Long, ?>> column1Entries =
              ROW_DATA.get(column1).entrySet();
          final Iterable<? extends Entry<Long, ?>> column2Entries =
              ROW_DATA.get(column2).entrySet();

          testViewGet(request, Iterables.concat(column1Entries, column2Entries));
        }

        { // Multiple versions | timerange
          final KijiDataRequest request = KijiDataRequest
              .builder()
              .addColumns(
                  ColumnsDef
                      .create()
                      .withPageSize(pageSize)
                      .withMaxVersions(100)
                      .add(familyColumn))
              .withTimeRange(4, 6)
              .build();

          final Iterable<? extends Entry<Long, ?>> column1Entries =
              ROW_DATA.get(column1).subMap(6L, false, 4L, true).entrySet();
          final Iterable<? extends Entry<Long, ?>> column2Entries =
              ROW_DATA.get(column2).subMap(6L, false, 4L, true).entrySet();

          testViewGet(request, Iterables.concat(column1Entries, column2Entries));
        }
      }
    }
  }


@Test
  public void testGetMultipleFamilyColumns() throws Exception {
    final KijiColumnName familyColumn1 = KijiColumnName.create(PRIMITIVE_FAMILY, null);
    final KijiColumnName familyColumn2 = KijiColumnName.create(STRING_MAP_FAMILY, null);

    final KijiColumnName column1 = PRIMITIVE_DOUBLE;
    final KijiColumnName column2 = PRIMITIVE_STRING;
    final KijiColumnName column3 = STRING_MAP_1;
    final KijiColumnName column4 = STRING_MAP_2;

    for (int pageSize : ImmutableList.of(0, 1, 2, 10)) {

      { // Single version | no timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(ColumnsDef.create().add(familyColumn1))
            .addColumns(ColumnsDef.create().add(familyColumn2))
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            Iterables.limit(ROW_DATA.get(column1).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            Iterables.limit(ROW_DATA.get(column2).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column3Entries =
            Iterables.limit(ROW_DATA.get(column3).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column4Entries =
            Iterables.limit(ROW_DATA.get(column4).entrySet(), 1);

        testViewGet(
            request,
            Iterables.concat(column1Entries, column2Entries, column3Entries, column4Entries));
      }

      { // Single version | timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(ColumnsDef.create().withPageSize(pageSize).add(familyColumn1))
            .addColumns(ColumnsDef.create().withPageSize(pageSize).add(familyColumn2))
            .withTimeRange(4, 6)
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            Iterables.limit(ROW_DATA.get(column1).subMap(6L, false, 4L, true).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            Iterables.limit(ROW_DATA.get(column2).subMap(6L, false, 4L, true).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column3Entries =
            Iterables.limit(ROW_DATA.get(column3).subMap(6L, false, 4L, true).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column4Entries =
            Iterables.limit(ROW_DATA.get(column4).subMap(6L, false, 4L, true).entrySet(), 1);

        testViewGet(
            request,
            Iterables.concat(column1Entries, column2Entries, column3Entries, column4Entries));
      }

      { // Multiple versions | no timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create().withPageSize(pageSize).withMaxVersions(100).add(familyColumn1))
            .addColumns(
                ColumnsDef.create().withPageSize(pageSize).withMaxVersions(100).add(familyColumn2))
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries = ROW_DATA.get(column1).entrySet();
        final Iterable<? extends Entry<Long, ?>> column2Entries = ROW_DATA.get(column2).entrySet();
        final Iterable<? extends Entry<Long, ?>> column3Entries = ROW_DATA.get(column3).entrySet();
        final Iterable<? extends Entry<Long, ?>> column4Entries = ROW_DATA.get(column4).entrySet();

        testViewGet(
            request,
            Iterables.concat(column1Entries, column2Entries, column3Entries, column4Entries));
      }

      { // Multiple versions | timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create().withPageSize(pageSize).withMaxVersions(100).add(familyColumn1))
            .addColumns(
                ColumnsDef.create().withPageSize(pageSize).withMaxVersions(100).add(familyColumn2))
            .withTimeRange(4, 6)
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            ROW_DATA.get(column1).subMap(6L, false, 4L, true).entrySet();
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            ROW_DATA.get(column2).subMap(6L, false, 4L, true).entrySet();
        final Iterable<? extends Entry<Long, ?>> column3Entries =
            ROW_DATA.get(column3).subMap(6L, false, 4L, true).entrySet();
        final Iterable<? extends Entry<Long, ?>> column4Entries =
            ROW_DATA.get(column4).subMap(6L, false, 4L, true).entrySet();

        testViewGet(
            request,
            Iterables.concat(column1Entries, column2Entries, column3Entries, column4Entries));
      }

      { // Mixed versions | no timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create().withPageSize(pageSize).withMaxVersions(2).add(familyColumn1))
            .addColumns(
                ColumnsDef.create().withPageSize(pageSize).withMaxVersions(100).add(familyColumn2))
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            Iterables.limit(ROW_DATA.get(column1).entrySet(), 2);
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            Iterables.limit(ROW_DATA.get(column2).entrySet(), 2);
        final Iterable<? extends Entry<Long, ?>> column3Entries = ROW_DATA.get(column3).entrySet();
        final Iterable<? extends Entry<Long, ?>> column4Entries = ROW_DATA.get(column4).entrySet();

        testViewGet(
            request,
            Iterables.concat(column1Entries, column2Entries, column3Entries, column4Entries));
      }

      { // Multiple versions | timerange
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create().withPageSize(pageSize).withMaxVersions(100).add(familyColumn1))
            .addColumns(
                ColumnsDef.create().withPageSize(pageSize).withMaxVersions(1).add(familyColumn2))
            .withTimeRange(4, 6)
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            ROW_DATA.get(column1).subMap(6L, false, 4L, true).entrySet();
        final Iterable<? extends Entry<Long, ?>> column2Entries =
            ROW_DATA.get(column2).subMap(6L, false, 4L, true).entrySet();
        final Iterable<? extends Entry<Long, ?>> column3Entries =
            Iterables.limit(ROW_DATA.get(column3).subMap(6L, false, 4L, true).entrySet(), 1);
        final Iterable<? extends Entry<Long, ?>> column4Entries =
            Iterables.limit(ROW_DATA.get(column4).subMap(6L, false, 4L, true).entrySet(), 1);

        testViewGet(
            request,
            Iterables.concat(column1Entries, column2Entries, column3Entries, column4Entries));
      }
    }
  }


@Test
  public void testNarrowView() throws Exception {
    final KijiColumnName familyColumn1 = KijiColumnName.create(PRIMITIVE_FAMILY, null);
    final KijiColumnName familyColumn2 = KijiColumnName.create(STRING_MAP_FAMILY, null);

    final KijiColumnName column1 = PRIMITIVE_DOUBLE;
    final KijiColumnName column2 = PRIMITIVE_STRING;
    final KijiColumnName column3 = STRING_MAP_1;
    final KijiColumnName column4 = STRING_MAP_2;

    for (int pageSize : ImmutableList.of(0)) {

      final KijiDataRequest request = KijiDataRequest
          .builder()
          .addColumns(
              ColumnsDef.create().withPageSize(pageSize).withMaxVersions(100).add(familyColumn1))
          .addColumns(
              ColumnsDef.create().withPageSize(pageSize).withMaxVersions(100).add(column3))
          .addColumns(ColumnsDef.create().withPageSize(pageSize).add(column4))
          .withTimeRange(2, 10)
          .build();

      final KijiResult<Object> view = mReader.getResult(mTable.getEntityId(ROW), request);
      try {
        testViewGet(view.narrowView(PRIMITIVE_LONG), ImmutableList.<Entry<Long, ?>>of());

        final Iterable<? extends Entry<Long, ?>> column1Entries =
            ROW_DATA.get(column1).subMap(10L, false, 2L, true).entrySet();
        testViewGet(view.narrowView(column1), column1Entries);

        final Iterable<? extends Entry<Long, ?>> column2Entries =
            ROW_DATA.get(column2).subMap(10L, false, 2L, true).entrySet();
        testViewGet(view.narrowView(column2), column2Entries);

        testViewGet(view.narrowView(familyColumn1),
            Iterables.concat(column1Entries, column2Entries));

        final Iterable<? extends Entry<Long, ?>> column3Entries =
            ROW_DATA.get(column3).subMap(10L, false, 2L, true).entrySet();
        testViewGet(view.narrowView(column3), column3Entries);

        final Iterable<? extends Entry<Long, ?>> column4Entries =
            Iterables.limit(ROW_DATA.get(column4).subMap(10L, false, 2L, true).entrySet(), 1);
        testViewGet(view.narrowView(column4), column4Entries);

        testViewGet(view.narrowView(familyColumn2),
            Iterables.concat(column3Entries, column4Entries));
      } finally {
        view.close();
      }
    }
  }


@Test
  public void testGetWithFilters() throws Exception {
    final KijiColumnName column1 = PRIMITIVE_STRING;
    final KijiColumnName column2 = STRING_MAP_1;

    for (int pageSize : ImmutableList.of(0, 1, 2, 10)) {
      { // single column | CRF
        final KijiDataRequest request = KijiDataRequest
            .builder()
            .addColumns(
                ColumnsDef.create()
                    .withPageSize(pageSize)
                    .withFilter(
                        new KijiColumnRangeFilter(
                            STRING_MAP_1.getQualifier(), true,
                            STRING_MAP_2.getQualifier(), false))
                    .withMaxVersions(10)
                    .add(column2.getFamily(), null))
            .build();

        final Iterable<? extends Entry<Long, ?>> column1Entries = ROW_DATA.get(column2).entrySet();

        testViewGet(request, column1Entries);
      }
    }
  }


@Test
  public void testGetMatContents() throws Exception {
    KijiDataRequestBuilder builder = KijiDataRequest.builder().addColumns(ColumnsDef.create()
        .withMaxVersions(10)
        .add(PRIMITIVE_STRING, null)
            .add(STRING_MAP_1, null));
    KijiDataRequest request = builder.build();
    final EntityId eid = mTable.getEntityId(ROW);
    KijiResult<Object> view = mReader.getResult(eid, request);
    SortedMap<KijiColumnName, List<KijiCell<Object>>> map =
        KijiResult.Helpers.getMaterializedContents(view);
    for (KijiColumnName col: map.keySet()) {
      KijiResult<Object> newResult = view.narrowView(col);
      Iterator<KijiCell<Object>> it = newResult.iterator();
      for (KijiCell<Object> cell: map.get(col)) {
        assertEquals(cell, it.next());
      }
      assertTrue(!it.hasNext());
    }

  }


@Test
  public void testRegex() {
    final String valid = "abcABC012_";
    assertTrue(HBaseKijiTableAnnotator.isValidAnnotationKey(valid));

    final List<String> invalidStrings =
        Lists.newArrayList("abc?", "abc.", "a$", "a!", "a#", "a-", "");
    for (String invalid : invalidStrings) {
      assertFalse(HBaseKijiTableAnnotator.isValidAnnotationKey(invalid));
    }
  }


('/** {@inheritDoc} */', '')

b'/** {@inheritDoc} */'@Override
  public int hashCode() {
    return new HashCodeBuilder()
        .append(this.mChance)
        .toHashCode();
  }

@Test
  public void testHashCodeAndEquals() {
    KijiRowFilter rowFilter1 = getBaseKijiRowFilter();
    KijiRowFilter rowFilter2 = getBaseKijiRowFilter();

    assertEquals(rowFilter1.hashCode(), rowFilter2.hashCode());
    assertEquals(rowFilter1, rowFilter2);
  }


@inheritDoc

b'/** {@inheritDoc} */'@Override
  public synchronized void setDataVersion(ProtocolVersion version) throws IOException {
    final State state = mState.get();
    Preconditions.checkState(state == State.OPEN,
        "Cannot set data version in SystemTable instance in state %s.", state);
    putValue(KEY_DATA_VERSION, Bytes.toBytes(version.toString()));
  }

@Test
  public void testSetDataVersion() throws IOException {
    final Configuration conf = HBaseConfiguration.create();
    final HTableDescriptor desc = new HTableDescriptor();
    final FakeHTable table = new FakeHTable("system", desc, conf, false, 0, true, true, null);

    final KijiURI uri = KijiURI.newBuilder("kiji://test/instance").build();
    final HBaseSystemTable systemTable = new HBaseSystemTable(uri, table);
    systemTable.setDataVersion(ProtocolVersion.parse("kiji-100"));
    assertEquals(ProtocolVersion.parse("kiji-100"), systemTable.getDataVersion());
    systemTable.close();
  }


('/** {@inheritDoc} */', '')

b'/** {@inheritDoc} */'@Override
  public byte[] encode(final DecodedCell<?> cell) throws IOException {
    return encode(cell.getData());
  }

@Test
  public void testWriterSchemaNotInferrable() throws IOException {
    final Kiji kiji = getKiji();
    final CellSpec cellSpec = CellSpec.create()
        .setCellSchema(CellSchema.newBuilder()
            .setType(SchemaType.AVRO)
            .setAvroValidationPolicy(AvroValidationPolicy.DEVELOPER)
            .build())
        .setSchemaTable(kiji.getSchemaTable());
    final AvroCellEncoder encoder = new AvroCellEncoder(cellSpec);
    try {
      encoder.encode(new Object());
      Assert.fail("AvroCellEncoder.encode() should throw a KijiEncodingException.");
    } catch (KijiEncodingException kee) {
      LOG.info("Expected error: '{}'", kee.getMessage());
      Assert.assertTrue(kee.getMessage().contains("Unable to infer Avro writer schema for value"));
    }
  }


('/** {@inheritDoc} */', '')

b'/** {@inheritDoc} */'@Override
  public String toString() {
    return Objects.toStringHelper(KijiPaginationFilter.class)
        .add("max-qualifiers", mMaxQualifiers)
        .add("offset", mOffset)
        .add("filter", mInputFilter)
        .toString();
  }

@Test
  public void testGroupTypeColumnPaging() throws IOException {
    EntityId id = mTable.getEntityId("me");
    final KijiTableWriter writer = mTable.openTableWriter();
    writer.put(id, "info", "name", 1L, "me");
    writer.put(id, "info", "name", 2L, "me-too");
    writer.put(id, "info", "name", 3L, "me-three");
    writer.put(id, "info", "name", 4L, "me-four");
    writer.put(id, "info", "name", 5L, "me-five");
    ResourceUtils.closeOrLog(writer);
    final KijiColumnFilter columnFilter = new KijiPaginationFilter(1);
    final KijiDataRequestBuilder builder = KijiDataRequest.builder();
    builder.newColumnsDef().withMaxVersions(5).withFilter(columnFilter).add("info", "name");
    final KijiDataRequest dataRequest = builder.build();
    EntityId meId = mTable.getEntityId(Bytes.toBytes("me"));
    KijiRowData myRowData = mReader.get(meId, dataRequest);
    final NavigableMap<Long, CharSequence> resultMap = myRowData.getValues("info", "name");
    assertEquals("The number of returned values is incorrect:", 1, resultMap.size());
    assertTrue(null != resultMap.get(5L));
    assertEquals("me-five", resultMap.get(5L).toString());
  }


('/** {@inheritDoc} */', '')

@Test
  public void testGroupTypeColumnPaging2() throws IOException {
    EntityId id = mTable.getEntityId("me");
    final KijiTableWriter writer = mTable.openTableWriter();
    writer.put(id, "info", "name", 1L, "me");
    writer.put(id, "info", "name", 2L, "me-too");
    writer.put(id, "info", "name", 3L, "me-three");
    writer.put(id, "info", "name", 4L, "me-four");
    writer.put(id, "info", "name", 5L, "me-five");
    ResourceUtils.closeOrLog(writer);
    final KijiColumnFilter columnFilter = new KijiPaginationFilter(1);
    final KijiDataRequestBuilder builder = KijiDataRequest.builder();
    builder.newColumnsDef().withMaxVersions(5).withFilter(columnFilter).add("info", "name");
    final KijiDataRequest dataRequest = builder.build();
    EntityId meId = mTable.getEntityId("me");
    KijiRowData myRowData = mReader.get(meId, dataRequest);
    final NavigableMap<Long, CharSequence> resultMap = myRowData.getValues("info", "name");
    assertEquals("The number of returned values is incorrect:", 1, resultMap.size());
    assertTrue(null != resultMap.get(5L));
    assertEquals("me-five", resultMap.get(5L).toString());
  }


('/** {@inheritDoc} */', '')

@Test
  public void testMapTypeColumnPaging() throws IOException {
    final KijiTableWriter writer = mTable.openTableWriter();
    EntityId id = mTable.getEntityId("me");
    writer.put(id, "jobs", "e", 1L, "always coming in 5th");
    writer.put(id, "jobs", "d", 2L, "always coming in 4th");
    writer.put(id, "jobs", "c", 3L, "always coming in 3rd");
    writer.put(id, "jobs", "b", 4L, "always coming in 2nd");
    writer.put(id, "jobs", "a", 5L, "always coming in 1st");
    ResourceUtils.closeOrLog(writer);
    final KijiColumnFilter columnFilter = new KijiPaginationFilter(1);
    final KijiDataRequestBuilder builder = KijiDataRequest.builder();
    builder.newColumnsDef().withMaxVersions(5).withFilter(columnFilter).addFamily("jobs");
    final KijiDataRequest dataRequest = builder.build();
    EntityId meId = mTable.getEntityId(Bytes.toBytes("me"));
    KijiRowData myRowData = mReader.get(meId, dataRequest);
    final NavigableMap<String, NavigableMap<Long, CharSequence>> resultMap
        = myRowData.<CharSequence>getValues("jobs");
    assertEquals("The number of returned values is incorrect:", 1, resultMap.size());
    assertTrue(null != resultMap.get("a"));
    assertEquals("always coming in 1st", resultMap.get("a").get(5L).toString());
  }


('/** {@inheritDoc} */', '')

@Test
  public void testFilterMergeColumnPaging() throws IOException {
    final KijiTableWriter writer = mTable.openTableWriter();
    EntityId id = mTable.getEntityId("me");
    writer.put(id, "jobs", "b", 1L, "always coming in 5th");
    writer.put(id, "jobs", "b", 2L, "always coming in 4th");
    writer.put(id, "jobs", "b", 3L, "always coming in 3rd");
    writer.put(id, "jobs", "a", 4L, "always coming in 2nd");
    writer.put(id, "jobs", "a", 5L, "always coming in 1st");
    ResourceUtils.closeOrLog(writer);
    final KijiColumnFilter columnFilter =
        new KijiPaginationFilter(new RegexQualifierColumnFilter("b"), 1);
    final KijiDataRequestBuilder builder = KijiDataRequest.builder();
    builder.newColumnsDef().withMaxVersions(5).withFilter(columnFilter).addFamily("jobs");
    final KijiDataRequest dataRequest = builder.build();
    EntityId meId = mTable.getEntityId(Bytes.toBytes("me"));
    KijiRowData myRowData = mReader.get(meId, dataRequest);
    final NavigableMap<String, NavigableMap<Long, CharSequence>> resultMap
        = myRowData.<CharSequence>getValues("jobs");
    assertEquals("The number of returned values is incorrect: ", 1, resultMap.get("b").size());
    assertEquals("Incorrect first value of first page:", "always coming in 3rd",
        resultMap.get("b").get(3L).toString());
  }


('/** {@inheritDoc} */', '')

('', '// Validate that the family exists\n')

('', '// Validate that the qualifier exists within the layout\n')

b'/** {@inheritDoc} */'@Override
  public HBaseColumnName toHBaseColumnName(KijiColumnName kijiColumnName)
      throws NoSuchColumnException {
    final String familyName = kijiColumnName.getFamily();
    final String qualifierName = kijiColumnName.getQualifier();

    // Validate that the family exists
    final FamilyLayout family = mLayout.getFamilyMap().get(familyName);
    if (family == null) {
      throw new NoSuchColumnException(String.format("No family %s in table %s.",
          familyName, mLayout.getName()));
    }

    // Validate that the qualifier exists within the layout
    if (!family.getColumnMap().containsKey(qualifierName)) {
      throw new NoSuchColumnException(String.format(
          "No qualifier %s in family %s of table %s.",
          qualifierName, familyName, mLayout.getName()));
    }

    return new HBaseColumnName(
        Bytes.toBytes(kijiColumnName.getFamily()),
        Bytes.toBytes(kijiColumnName.getQualifier()));
  }

@Test
  public void testTranslateFromKijiToHBase() throws Exception {
    HBaseColumnName infoName = mTranslator.toHBaseColumnName(KijiColumnName.create("info:name"));
    assertEquals("info", infoName.getFamilyAsString());
    assertEquals("name", infoName.getQualifierAsString());

    HBaseColumnName infoEmail = mTranslator.toHBaseColumnName(KijiColumnName.create("info:email"));
    assertEquals("info", infoEmail.getFamilyAsString());
    assertEquals("email", infoEmail.getQualifierAsString());

    HBaseColumnName recommendationsProduct = mTranslator.toHBaseColumnName(
        KijiColumnName.create("recommendations:product"));
    assertEquals("recommendations", recommendationsProduct.getFamilyAsString());
    assertEquals("product", recommendationsProduct.getQualifierAsString());

    HBaseColumnName purchases = mTranslator.toHBaseColumnName(
        KijiColumnName.create("recommendations:product"));
    assertEquals("recommendations", purchases.getFamilyAsString());
    assertEquals("product", purchases.getQualifierAsString());
  }


('/** {@inheritDoc} */', '')

('', '// Validate that the qualifier exists\n')

b'/** {@inheritDoc} */'@Override
  public KijiColumnName toKijiColumnName(HBaseColumnName hbaseColumnName)
      throws NoSuchColumnException {
    LOG.debug("Translating HBase column name '{}' to Kiji column name.", hbaseColumnName);

    final String familyName = Bytes.toString(hbaseColumnName.getFamily());
    final String qualifierName = Bytes.toString(hbaseColumnName.getQualifier());

    final FamilyLayout family = mLayout.getFamilyMap().get(familyName);

    // Validate that the family exists
    if (family == null) {
      throw new NoSuchColumnException(String.format("No family %s in layout for table %s.",
          familyName, mLayout.getName()));
    }

    // Validate that the qualifier exists
    final ColumnLayout qualifier = family.getColumnMap().get(qualifierName);
    if (qualifier == null) {
      throw new NoSuchColumnException(String.format("No qualifier %s in family %s of table %s.",
          qualifierName, familyName, mLayout.getName()));
    }

    final KijiColumnName kijiColumnName = new KijiColumnName(familyName, qualifierName);

    LOG.debug("Translated to Kiji column '{}'.", kijiColumnName);
    return kijiColumnName;
  }

@Test(expected = NoSuchColumnException.class)
  public void testNoSuchKijiLocalityGroup() throws Exception {
    mTranslator.toKijiColumnName(getHBaseColumnName("fakeFamily", "fakeQualifier"));
  }


('/** {@inheritDoc} */', '')

@Test(expected = NoSuchColumnException.class)
  public void testNoSuchKijiColumn() throws Exception {
    mTranslator.toKijiColumnName(getHBaseColumnName("recommendations", "fakeQualifier"));
  }


('/** {@inheritDoc} */', '')

@Test(expected = NoSuchColumnException.class)
  public void testNoSuchHBaseColumn() throws Exception {
    mTranslator.toHBaseColumnName(KijiColumnName.create("doesnt:exist"));
  }


('/** {@inheritDoc} */', '')

b'/** {@inheritDoc} */'@Override
  public int hashCode() {
    return HASH_CODE;
  }

@Test
  public void testEqualsAndHashCode() {
    final StripValueRowFilter filter1 = new StripValueRowFilter();
    final StripValueRowFilter filter2 = new StripValueRowFilter();
    assertEquals(filter1, filter2);
    assertEquals(filter1.hashCode(), filter2.hashCode());
  }


('/** {@inheritDoc}*/', '')

('', '// Validate the Kiji family\n')

('', '// Validate the Kiji qualifier\n')

b'/** {@inheritDoc}*/'@Override
  public HBaseColumnName toHBaseColumnName(KijiColumnName kijiColumnName)
      throws NoSuchColumnException {

    final String familyName = kijiColumnName.getFamily();
    final String qualifierName = kijiColumnName.getQualifier();

    // Validate the Kiji family
    final FamilyLayout family = mLayout.getFamilyMap().get(familyName);
    if (family == null) {
      throw new NoSuchColumnException(kijiColumnName.toString());
    }

    // Validate the Kiji qualifier
    if (family.isGroupType() && !family.getColumnMap().containsKey(qualifierName)) {
      throw new NoSuchColumnException(kijiColumnName.toString());
    }

    final byte[] localityGroupBytes = Bytes.toBytes(family.getLocalityGroup().getName());
    final byte[] familyBytes = Bytes.toBytes(familyName);
    final byte[] qualifierBytes = Bytes.toBytes(qualifierName);

    final byte[] hbaseQualifierBytes =
        ShortColumnNameTranslator.concatWithSeparator(SEPARATOR, familyBytes, qualifierBytes);

    return new HBaseColumnName(localityGroupBytes, hbaseQualifierBytes);
  }

@Test
  public void testTranslateFromKijiToHBase() throws Exception {
    HBaseColumnName infoName = mTranslator.toHBaseColumnName(KijiColumnName.create("info:name"));
    assertEquals("default", infoName.getFamilyAsString());
    assertEquals("info:name", infoName.getQualifierAsString());

    HBaseColumnName infoEmail =
        mTranslator.toHBaseColumnName(KijiColumnName.create("info:email"));
    assertEquals("default", infoEmail.getFamilyAsString());
    assertEquals("info:email", infoEmail.getQualifierAsString());

    HBaseColumnName recommendationsProduct = mTranslator.toHBaseColumnName(
        KijiColumnName.create("recommendations:product"));
    assertEquals("inMemory", recommendationsProduct.getFamilyAsString());
    assertEquals("recommendations:product", recommendationsProduct.getQualifierAsString());

    HBaseColumnName purchases =
        mTranslator.toHBaseColumnName(KijiColumnName.create("purchases:foo"));
    assertEquals("inMemory", purchases.getFamilyAsString());
    assertEquals("purchases:foo", purchases.getQualifierAsString());
  }


('/** {@inheritDoc}*/', '')

('', '// Parse the HBase qualifier as a byte[] in order to save a String instantiation\n')

('', '// Group type family.\n')

('', '// Map type family.\n')

b'/** {@inheritDoc}*/'@Override
  public KijiColumnName toKijiColumnName(HBaseColumnName hbaseColumnName)
      throws NoSuchColumnException {
    LOG.debug("Translating HBase column name {} to Kiji column name.", hbaseColumnName);

    final String localityGroupName = Bytes.toString(hbaseColumnName.getFamily());

    final LocalityGroupLayout localityGroup = mLayout.getLocalityGroupMap().get(localityGroupName);
    if (localityGroup == null) {
      throw new NoSuchColumnException(String.format("No locality group %s in table %s.",
          localityGroupName, mLayout.getName()));
    }

    // Parse the HBase qualifier as a byte[] in order to save a String instantiation
    final byte[] hbaseQualifier = hbaseColumnName.getQualifier();
    final int index = ArrayUtils.indexOf(hbaseQualifier, SEPARATOR);
    if (index == -1) {
      throw new NoSuchColumnException(String.format(
          "Missing separator in HBase column %s.", hbaseColumnName));
    }
    final String familyName = Bytes.toString(hbaseQualifier, 0, index);
    final String qualifierName =
        Bytes.toString(hbaseQualifier, index + 1, hbaseQualifier.length - index - 1);

    final FamilyLayout family = mLayout.getFamilyMap().get(familyName);
    if (family == null) {
      throw new NoSuchColumnException(String.format(
          "No family %s in locality group %s of table %s.",
          familyName, localityGroupName, mLayout.getName()));
    }

    if (family.isGroupType()) {
      // Group type family.
      if (!family.getColumnMap().containsKey(qualifierName)) {
        throw new NoSuchColumnException(String.format(
            "No qualifier %s in family %s of table %s.",
            qualifierName, familyName, mLayout.getName()));
      }
      final KijiColumnName kijiColumnName = new KijiColumnName(familyName, qualifierName);
      LOG.debug("Translated to Kiji group type column {}.", kijiColumnName);
      return kijiColumnName;
    } else {
      // Map type family.
      assert family.isMapType();
      final KijiColumnName kijiColumnName = new KijiColumnName(familyName, qualifierName);
      LOG.debug("Translated to Kiji map type column '{}'.", kijiColumnName);
      return kijiColumnName;
    }
  }

@Test(expected = NoSuchColumnException.class)
  public void testNoSuchKijiLocalityGroup() throws Exception {
    mTranslator
        .toKijiColumnName(getHBaseColumnName("fakeLocalityGroup", "fakeFamily:fakeQualifier"));
  }


('/** {@inheritDoc}*/', '')

('', '// Group type family.\n')

('', '// Map type family.\n')

@Test(expected = NoSuchColumnException.class)
  public void testNoSuchKijiFamily() throws Exception {
    mTranslator.toKijiColumnName(getHBaseColumnName("inMemory", "fakeFamily:fakeQualifier"));
  }


('/** {@inheritDoc}*/', '')

('', '// Group type family.\n')

('', '// Map type family.\n')

@Test(expected = NoSuchColumnException.class)
  public void testNoSuchKijiColumn() throws Exception {
    mTranslator.toKijiColumnName(getHBaseColumnName("inMemory", "recommendations:fakeQualifier"));
  }


('/** {@inheritDoc}*/', '')

('', '// Group type family.\n')

('', '// Map type family.\n')

@Test(expected = NoSuchColumnException.class)
  public void testCorruptQualifier() throws Exception {
    mTranslator.toKijiColumnName(getHBaseColumnName("inMemory", "fakeFamilyfakeQualifier"));
  }


('/** {@inheritDoc}*/', '')

('', '// Group type family.\n')

('', '// Map type family.\n')

@Test
  public void testMultipleSeparators() throws Exception {
    KijiColumnName kijiColumnName =
        mTranslator.toKijiColumnName(getHBaseColumnName("inMemory", "purchases:left:right"));
    assertEquals("purchases", kijiColumnName.getFamily());
    assertEquals("left:right", kijiColumnName.getQualifier());
  }


('/** {@inheritDoc}*/', '')

('', '// Validate the Kiji family\n')


('/** {@inheritDoc} */', '')
('', '// Unqualified column\n')
('', '// Group type family.\n')
('', '// Map type family.\n')

b'/** {@inheritDoc} */'@Override
  public HBaseColumnName toHBaseColumnName(final KijiColumnName kijiColumnName)
      throws NoSuchColumnException {
    final String familyName = kijiColumnName.getFamily();
    final String qualifierName = kijiColumnName.getQualifier();

    final FamilyLayout family = mLayout.getFamilyMap().get(familyName);
    if (family == null) {
      throw new NoSuchColumnException(kijiColumnName.toString());
    }

    final ColumnId localityGroupID = family.getLocalityGroup().getId();
    final ColumnId familyID = family.getId();

    final byte[] localityGroupBytes = Bytes.toBytes(localityGroupID.toString());
    final byte[] familyBytes = Bytes.toBytes(familyID.toString());

    if (qualifierName == null) {
      // Unqualified column
      return new HBaseColumnName(localityGroupBytes,
          concatWithSeparator(SEPARATOR, familyBytes, new byte[]{}));
    } else if (family.isGroupType()) {
      // Group type family.
      final ColumnId qualifierID = family.getColumnIdNameMap().inverse().get(qualifierName);
      final byte[] qualifierBytes = Bytes.toBytes(qualifierID.toString());

      return new HBaseColumnName(localityGroupBytes,
          concatWithSeparator(SEPARATOR, familyBytes, qualifierBytes));
    } else {
      // Map type family.
      assert family.isMapType();
      final byte[] qualifierBytes = Bytes.toBytes(qualifierName);

      return new HBaseColumnName(
          localityGroupBytes,
          concatWithSeparator(SEPARATOR, familyBytes, qualifierBytes));
    }
  }

@Test
  public void testTranslateFromKijiToHBase() throws Exception {
    HBaseColumnName infoName = mTranslator.toHBaseColumnName(KijiColumnName.create("info:name"));
    assertEquals("B", infoName.getFamilyAsString());
    assertEquals("B:B", infoName.getQualifierAsString());

    HBaseColumnName infoEmail = mTranslator.toHBaseColumnName(KijiColumnName.create("info:email"));
    assertEquals("B", infoEmail.getFamilyAsString());
    assertEquals("B:C", infoEmail.getQualifierAsString());

    HBaseColumnName recommendationsProduct = mTranslator.toHBaseColumnName(
        KijiColumnName.create("recommendations:product"));
    assertEquals("C", recommendationsProduct.getFamilyAsString());
    assertEquals("B:B", recommendationsProduct.getQualifierAsString());

    HBaseColumnName purchases =
        mTranslator.toHBaseColumnName(KijiColumnName.create("purchases:foo"));
    assertEquals("C", purchases.getFamilyAsString());
    assertEquals("C:foo", purchases.getQualifierAsString());
  }


('/** {@inheritDoc} */', '')

('', '// Group type family.\n')

('', '// Map type family.\n')

b'/** {@inheritDoc} */'@Override
  public KijiColumnName toKijiColumnName(HBaseColumnName hbaseColumnName)
      throws NoSuchColumnException {
    LOG.debug("Translating HBase column name '{}' to Kiji column name...", hbaseColumnName);
    final ColumnId localityGroupID = ColumnId.fromByteArray(hbaseColumnName.getFamily());
    final LocalityGroupLayout localityGroup =
        mLayout.getLocalityGroupMap().get(mLayout.getLocalityGroupIdNameMap().get(localityGroupID));
    if (localityGroup == null) {
      throw new NoSuchColumnException(String.format("No locality group with ID %s in table %s.",
          localityGroupID.getId(), mLayout.getName()));
    }

    // Parse the HBase qualifier as a byte[] in order to save a String instantiation
    final byte[] hbaseQualifier = hbaseColumnName.getQualifier();
    final int index = ArrayUtils.indexOf(hbaseQualifier, SEPARATOR);
    if (index == -1) {
      throw new NoSuchColumnException(String.format(
          "Missing separator in HBase column %s.", hbaseColumnName));
    }
    final ColumnId familyID = ColumnId.fromString(Bytes.toString(hbaseQualifier, 0, index));
    final String rawQualifier =
        Bytes.toString(hbaseQualifier, index + 1, hbaseQualifier.length - index - 1);

    final FamilyLayout family =
        localityGroup.getFamilyMap().get(localityGroup.getFamilyIdNameMap().get(familyID));
    if (family == null) {
      throw new NoSuchColumnException(String.format(
          "No family with ID %s in locality group %s of table %s.",
          familyID.getId(), localityGroup.getName(), mLayout.getName()));
    }

    if (family.isGroupType()) {
      // Group type family.
      final ColumnId qualifierID = ColumnId.fromString(rawQualifier);
      final ColumnLayout qualifier =
          family.getColumnMap().get(family.getColumnIdNameMap().get(qualifierID));
      if (qualifier == null) {
        throw new NoSuchColumnException(String.format(
            "No column with ID %s in family %s of table %s.",
            qualifierID.getId(), family.getName(), mLayout.getName()));
      }
      final KijiColumnName kijiColumnName =
          new KijiColumnName(family.getName(), qualifier.getName());
      LOG.debug("Translated to Kiji group column {}.", kijiColumnName);
      return kijiColumnName;
    } else {
      // Map type family.
      assert family.isMapType();
      final KijiColumnName kijiColumnName = new KijiColumnName(family.getName(), rawQualifier);
      LOG.debug("Translated to Kiji map column '{}'.", kijiColumnName);
      return kijiColumnName;
    }
  }

@Test(expected = NoSuchColumnException.class)
  public void testNoSuchKijiLocalityGroup() throws Exception {
    mTranslator.toKijiColumnName(getHBaseColumnName("D", "E:E"));
  }


('/** {@inheritDoc} */', '')

('', '// Group type family.\n')

('', '// Map type family.\n')

@Test(expected = NoSuchColumnException.class)
  public void testNoSuchKijiFamily() throws Exception {
    mTranslator.toKijiColumnName(getHBaseColumnName("C", "E:E"));
  }


Creates a new @code HBaseColumnName instance @param family HBase column family not null @param qualifier HBase column qualifier not null

b'/**\n   * Creates a new {@code HBaseColumnName} instance.\n   *\n   * @param family HBase column family, not null.\n   * @param qualifier HBase column qualifier, not null.\n   */'public HBaseColumnName(byte[] family, byte[] qualifier) {
    mFamily = family;
    mQualifier = qualifier;
  }

@Test
  public void testHBaseColumnName() {
    HBaseColumnName column = new HBaseColumnName(Bytes.toBytes("foo"), Bytes.toBytes("bar"));
    assertArrayEquals(Bytes.toBytes("foo"), column.getFamily());
    assertEquals("foo", column.getFamilyAsString());
    assertArrayEquals(Bytes.toBytes("bar"), column.getQualifier());
    assertEquals("bar", column.getQualifierAsString());
  }


('/** {@inheritDoc} */', '')

('', '// Group type family.\n')

('', '// Map type family.\n')

@Test(expected = NoSuchColumnException.class)
  public void testNoSuchKijiColumn() throws Exception {
    mTranslator.toKijiColumnName(getHBaseColumnName("C", "B:E"));
  }


('/** {@inheritDoc} */', '')

('', '// Group type family.\n')

('', '// Map type family.\n')

@Test(expected = NoSuchColumnException.class)
  public void testCorruptQualifier() throws Exception {
    mTranslator.toKijiColumnName(getHBaseColumnName("C", "BE"));
  }


['("/**\\\\n   * Get a table layout monitor for the provided table.  The returned table layout monitor should\\\\n   * be closed when no longer needed.\\\\n   *\\\\n   * @param tableName of table\'s monitor to retrieve.\\\\n   * @return a table layout monitor for the table.\\\\n   */", \'\')']

b"/**\n   * Get a table layout monitor for the provided table.  The returned table layout monitor should\n   * be closed when no longer needed.\n   *\n   * @param tableName of table's monitor to retrieve.\n   * @return a table layout monitor for the table.\n   */"public TableLayoutMonitor getTableLayoutMonitor(String tableName) {
    Preconditions.checkState(mState.get() == State.OPEN, "InstanceMonitor is closed.");
    LOG.debug("Retrieving TableLayoutMonitor for table {} with userID {}.",
        KijiURI.newBuilder(mInstanceURI).withTableName(tableName).build(), mUserID);
    return new ReferencedTableLayoutMonitor(tableName, mTableLayoutMonitors);
  }

@Test
  public void testCanRetrieveTableMonitor() throws Exception {
    TableLayoutMonitor monitor = mInstanceMonitor.getTableLayoutMonitor(mTableURI.getTable());
    Assert.assertEquals("layout-1.0", monitor.getLayout().getDesc().getVersion());
  }


('/**\\n   * Validates a new table layout against a reference layout for mutual compatibility.\\n   *\\n   * @param reference the reference layout against which to validate.\\n   * @param layout the new layout to validate.\\n   * @throws IOException in case of an IO Error reading from the schema table.\\n   *     Throws InvalidLayoutException if the layouts are incompatible.\\n   */', '')

('', '// Layout versions older than layout-1.3.0 do not require validation\n')

('', '// Accumulator for error messages which will be used to create an exception if errors occur.\n')

('', '// Iterate through all families/columns in the new layout,\n')

('', '// find a potential matching reference family/column,\n')

('', '// and validate the reader/writer schema sets.\n')

('', '// If no matching family/column exists in the reference layout the newly create column is valid.\n')

('', '// If there is a reference layout, check for a locality group matching the ID of the LG for\n')

('', '// this family.  Locality Group IDs should not change between layouts.\n')

('', '// If there is a matching reference LG get its layout by name.\n')

('', '// The ColumnId of the FamilyLayout from the table layout.  Also matches the FamilyLayout for\n')

('', '// this family in the reference layout if present.\n')

('', '// If the family is map-type, get the CellSchema for all values in the family.\n')

('', '// If there is a matching reference LG, check for the existence of this family.\n')

('', '// If the FamilyLayout from both table layouts are map type, compare their CellSchemas.\n')

('', '// If the FamilyLayout changed from group-type to map-type between table layout versions\n')

('', '// that is an incompatible change.\n')

('', '// If the reference FamilyLayout is null this indicates a new family, which is inherently\n')

('', '// compatible, but we still have to validate that the new readers and writers are\n')

('', '// internally compatible.\n')

('', '// Check for a matching family from the reference layout.\n')

('', '// If there is a matching reference family and it is the same family type, iterate\n')

('', '// through the columns checking schema compatibility.  Only checks columns from the new\n')

('', '// layout because removed columns are inherently valid.\n')

('', '// If there is a column from the reference layout with the same column ID, get its\n')

('', '// layout.\n')

('', '// CellSchema.\n')

('', '// If there is no matching column, refCellSchema will be null and this will only test\n')

('', '// that the new reader and writer schemas are internally compatible.\n')

('', '// If the FamilyLayout changed from map-type to group-type between table layout versions\n')

('', '// internally compatible.\n')

('', '// If there were any incompatibility errors, throw an exception.\n')

b'/**\n   * Validates a new table layout against a reference layout for mutual compatibility.\n   *\n   * @param reference the reference layout against which to validate.\n   * @param layout the new layout to validate.\n   * @throws IOException in case of an IO Error reading from the schema table.\n   *     Throws InvalidLayoutException if the layouts are incompatible.\n   */'public void validate(KijiTableLayout reference, KijiTableLayout layout) throws IOException {

    final ProtocolVersion layoutVersion = ProtocolVersion.parse(layout.getDesc().getVersion());

    if (layoutVersion.compareTo(Versions.LAYOUT_VALIDATION_VERSION) < 0) {
      // Layout versions older than layout-1.3.0 do not require validation
      return;
    }

    // Accumulator for error messages which will be used to create an exception if errors occur.
    final List<String> incompatabilityMessages = Lists.newArrayList();

    // Iterate through all families/columns in the new layout,
    // find a potential matching reference family/column,
    // and validate the reader/writer schema sets.
    // If no matching family/column exists in the reference layout the newly create column is valid.
    for (FamilyLayout flayout : layout.getFamilies()) {
      final ColumnId lgid = flayout.getLocalityGroup().getId();

      LocalityGroupLayout refLGLayout = null;
      if (reference != null) {
        // If there is a reference layout, check for a locality group matching the ID of the LG for
        // this family.  Locality Group IDs should not change between layouts.
        final String refLGName = reference.getLocalityGroupIdNameMap().get(lgid);
        if (refLGName != null) {
          // If there is a matching reference LG get its layout by name.
          refLGLayout = reference.getLocalityGroupMap().get(refLGName);
        }
      }

      // The ColumnId of the FamilyLayout from the table layout.  Also matches the FamilyLayout for
      // this family in the reference layout if present.
      final ColumnId familyId = flayout.getId();

      if (flayout.isMapType()) {
        // If the family is map-type, get the CellSchema for all values in the family.
        final CellSchema cellSchema = flayout.getDesc().getMapSchema();

        FamilyLayout refFamilyLayout = null;
        if (refLGLayout != null) {
          // If there is a matching reference LG, check for the existence of this family.
          final String refFamilyName = refLGLayout.getFamilyIdNameMap().get(familyId);
          if (refFamilyName != null) {
            refFamilyLayout = refLGLayout.getFamilyMap().get(refFamilyName);
          }
        }

        if (refFamilyLayout != null) {
          if (refFamilyLayout.isMapType()) {
            // If the FamilyLayout from both table layouts are map type, compare their CellSchemas.
            final CellSchema refCellSchema = refFamilyLayout.getDesc().getMapSchema();

            incompatabilityMessages.addAll(addColumnNamestoIncompatibilityMessages(
                flayout.getName(), null, validateCellSchema(refCellSchema, cellSchema)));
          } else if (refFamilyLayout.isGroupType()) {
            // If the FamilyLayout changed from group-type to map-type between table layout versions
            // that is an incompatible change.
            incompatabilityMessages.add(String.format(
                "Family: %s changed from group-type to map-type.", refFamilyLayout.getName()));
          } else {
            throw new InternalKijiError(String.format(
                "Family: %s is neither map-type nor group-type.", refFamilyLayout.getName()));
          }
        } else {
          // If the reference FamilyLayout is null this indicates a new family, which is inherently
          // compatible, but we still have to validate that the new readers and writers are
          // internally compatible.
          incompatabilityMessages.addAll(addColumnNamestoIncompatibilityMessages(
              flayout.getName(), null, validateCellSchema(null, cellSchema)));
        }
      } else if (flayout.isGroupType()) {
        // Check for a matching family from the reference layout.
        FamilyLayout refFamilyLayout = null;
        if (refLGLayout != null) {
          final String refFamilyName = refLGLayout.getFamilyIdNameMap().get(familyId);
          if (refFamilyName != null) {
            refFamilyLayout = refLGLayout.getFamilyMap().get(refFamilyName);
          }
        }

        if (refFamilyLayout != null) {
          if (refFamilyLayout.isGroupType()) {
            // If there is a matching reference family and it is the same family type, iterate
            // through the columns checking schema compatibility.  Only checks columns from the new
            // layout because removed columns are inherently valid.
            for (ColumnLayout columnLayout : flayout.getColumns()) {
              final CellSchema cellSchema = columnLayout.getDesc().getColumnSchema();

              final String refColumnName =
                  refFamilyLayout.getColumnIdNameMap().get(columnLayout.getId());
              ColumnLayout refColumnLayout = null;
              if (refColumnName != null) {
                // If there is a column from the reference layout with the same column ID, get its
                // layout.
                refColumnLayout = refFamilyLayout.getColumnMap().get(refColumnName);
              }
              // If there is a column from the reference layout with the same column ID, get its
              // CellSchema.
              final CellSchema refCellSchema =
                  (refColumnLayout == null) ? null : refColumnLayout.getDesc().getColumnSchema();

              // If there is no matching column, refCellSchema will be null and this will only test
              // that the new reader and writer schemas are internally compatible.
              incompatabilityMessages.addAll(addColumnNamestoIncompatibilityMessages(
                  flayout.getName(),
                  columnLayout.getName(),
                  validateCellSchema(refCellSchema, cellSchema)));
            }
          } else if (refFamilyLayout.isMapType()) {
            // If the FamilyLayout changed from map-type to group-type between table layout versions
            // that is an incompatible change.
            incompatabilityMessages.add(String.format(
                "Family: %s changed from map-type to group-type.", refFamilyLayout.getName()));
          } else {
            throw new InternalKijiError(String.format(
                "Family: %s is neither map-type nor group-type.", refFamilyLayout.getName()));
          }
        } else {
          // If the reference FamilyLayout is null this indicates a new family, which is inherently
          // compatible, but we still have to validate that the new readers and writers are
          // internally compatible.
          for (ColumnLayout columnLayout : flayout.getColumns()) {
            final CellSchema cellSchema = columnLayout.getDesc().getColumnSchema();
            incompatabilityMessages.addAll(addColumnNamestoIncompatibilityMessages(
                flayout.getName(), columnLayout.getName(), validateCellSchema(null, cellSchema)));
          }
        }

      } else {
        throw new InternalKijiError(String.format(
            "Family: %s is neither map-type nor group-type.", flayout.getName()));
      }
    }

    // If there were any incompatibility errors, throw an exception.
    if (incompatabilityMessages.size() != 0) {
      throw new InvalidLayoutSchemaException(incompatabilityMessages);
    }
  }

@Test
  public void testAvroValidationChanges() throws IOException {
    final TableLayoutUpdateValidator validator = new TableLayoutUpdateValidator(getKiji());
    final TableLayoutDesc basicDesc = KijiTableLayouts.getLayout(KijiTableLayouts.SCHEMA_REG_TEST);
    basicDesc.setVersion("layout-1.3.0");
    final KijiColumnName validatedColumn = KijiColumnName.create("info:fullname");
    final Schema intSchema = Schema.create(Type.INT);
    final Schema stringSchema = Schema.create(Type.STRING);

    final TableLayoutDesc strictIntDesc = new TableLayoutBuilder(basicDesc, getKiji())
        .withAvroValidationPolicy(validatedColumn, AvroValidationPolicy.STRICT)
        .withReader(validatedColumn, intSchema)
        .build();
    final TableLayoutDesc strictStringDesc = new TableLayoutBuilder(basicDesc, getKiji())
        .withAvroValidationPolicy(validatedColumn, AvroValidationPolicy.STRICT)
        .withWriter(validatedColumn, stringSchema)
        .build();
    final TableLayoutDesc developerIntDesc = new TableLayoutBuilder(basicDesc, getKiji())
        .withAvroValidationPolicy(validatedColumn, AvroValidationPolicy.DEVELOPER)
        .withReader(validatedColumn, intSchema)
        .build();
    final TableLayoutDesc developerStringDesc = new TableLayoutBuilder(basicDesc, getKiji())
        .withAvroValidationPolicy(validatedColumn, AvroValidationPolicy.DEVELOPER)
        .withWriter(validatedColumn, stringSchema)
        .build();
    final TableLayoutDesc noneIntDesc = new TableLayoutBuilder(basicDesc, getKiji())
        .withAvroValidationPolicy(validatedColumn, AvroValidationPolicy.NONE)
        .withReader(validatedColumn, intSchema)
        .build();
    final TableLayoutDesc noneStringDesc = new TableLayoutBuilder(basicDesc, getKiji())
        .withAvroValidationPolicy(validatedColumn, AvroValidationPolicy.NONE)
        .withWriter(validatedColumn, stringSchema)
        .build();
    final TableLayoutDesc schema10IntDesc = new TableLayoutBuilder(basicDesc, getKiji())
        .withAvroValidationPolicy(validatedColumn, AvroValidationPolicy.SCHEMA_1_0)
        .withReader(validatedColumn, intSchema)
        .build();
    final TableLayoutDesc schema10StringDesc = new TableLayoutBuilder(basicDesc, getKiji())
        .withAvroValidationPolicy(validatedColumn, AvroValidationPolicy.SCHEMA_1_0)
        .withWriter(validatedColumn, stringSchema)
        .build();

    final List<TableLayoutDesc> intDescs =
        Lists.newArrayList(strictIntDesc, developerIntDesc, noneIntDesc, schema10IntDesc);

    // Increasing or decreasing validation strictness is acceptable in either direction.  The new
    // layout sets the validation policy which will be run.  For an increase in validation to
    // succeed old readers and writers must be internally compatible and compatible with new readers
    // and writers.

    // Test each validation mode modified to STRICT.
    for (TableLayoutDesc intDesc : intDescs) {
      // Increasing the layout validation to STRICT should throw an exception.
      try {
        validator.validate(
            KijiTableLayout.newLayout(intDesc), KijiTableLayout.newLayout(strictStringDesc));
        fail("validate should have thrown InvalidLayoutSchemaException because int and string are "
            + "incompatible.");
      } catch (InvalidLayoutSchemaException ilse) {
        assertTrue(ilse.getReasons().contains(
            "In column: 'info:fullname' Reader schema: \"int\" is incompatible with "
            + "writer schema: \"string\"."));
        assertTrue(ilse.getReasons().size() == 1);
      }
    }

    // Test each validation mode modified to DEVELOPER.
    for (TableLayoutDesc intDesc : intDescs) {
      // Increasing the layout validation to DEVELOPER should throw an exception.
      try {
        validator.validate(
            KijiTableLayout.newLayout(intDesc), KijiTableLayout.newLayout(developerStringDesc));
        fail("validate should have thrown InvalidLayoutSchemaException because int and string are "
            + "incompatible.");
      } catch (InvalidLayoutSchemaException ilse) {
        assertTrue(ilse.getReasons().contains(
            "In column: 'info:fullname' Reader schema: \"int\" is incompatible with "
            + "writer schema: \"string\"."));
        assertTrue(ilse.getReasons().size() == 1);
      }
    }

    // Test each validation mode modified to SCHEMA_1_0.
    for (TableLayoutDesc intDesc : intDescs) {
      // Reducing the layout validation to SCHEMA_1_0 should eliminate errors.
      validator.validate(
          KijiTableLayout.newLayout(intDesc), KijiTableLayout.newLayout(schema10StringDesc));
    }

    // Test each validation mode modified to NONE.
    for (TableLayoutDesc intDesc : intDescs) {
      // Reducing the layout validation to NONE should eliminate errors.
      validator.validate(
            KijiTableLayout.newLayout(intDesc), KijiTableLayout.newLayout(noneStringDesc));
    }
  }


('/**\\n   * Validates a new table layout against a reference layout for mutual compatibility.\\n   *\\n   * @param reference the reference layout against which to validate.\\n   * @param layout the new layout to validate.\\n   * @throws IOException in case of an IO Error reading from the schema table.\\n   *     Throws InvalidLayoutException if the layouts are incompatible.\\n   */', '')

('', '// Layout versions older than layout-1.3.0 do not require validation\n')

('', '// Accumulator for error messages which will be used to create an exception if errors occur.\n')

('', '// Iterate through all families/columns in the new layout,\n')

('', '// find a potential matching reference family/column,\n')

('', '// and validate the reader/writer schema sets.\n')

('', '// If no matching family/column exists in the reference layout the newly create column is valid.\n')

('', '// If there is a reference layout, check for a locality group matching the ID of the LG for\n')

('', '// this family.  Locality Group IDs should not change between layouts.\n')

('', '// If there is a matching reference LG get its layout by name.\n')

('', '// The ColumnId of the FamilyLayout from the table layout.  Also matches the FamilyLayout for\n')

('', '// this family in the reference layout if present.\n')

('', '// If the family is map-type, get the CellSchema for all values in the family.\n')

('', '// If there is a matching reference LG, check for the existence of this family.\n')

('', '// If the FamilyLayout from both table layouts are map type, compare their CellSchemas.\n')

('', '// If the FamilyLayout changed from group-type to map-type between table layout versions\n')

('', '// that is an incompatible change.\n')

('', '// If the reference FamilyLayout is null this indicates a new family, which is inherently\n')

('', '// compatible, but we still have to validate that the new readers and writers are\n')

('', '// internally compatible.\n')

('', '// Check for a matching family from the reference layout.\n')

('', '// If there is a matching reference family and it is the same family type, iterate\n')

('', '// through the columns checking schema compatibility.  Only checks columns from the new\n')

('', '// layout because removed columns are inherently valid.\n')

('', '// If there is a column from the reference layout with the same column ID, get its\n')

('', '// layout.\n')

('', '// CellSchema.\n')

('', '// If there is no matching column, refCellSchema will be null and this will only test\n')

('', '// that the new reader and writer schemas are internally compatible.\n')

('', '// If the FamilyLayout changed from map-type to group-type between table layout versions\n')

('', '// internally compatible.\n')

('', '// If there were any incompatibility errors, throw an exception.\n')

@Test
  public void testOldLayoutVersions() throws IOException {
    final TableLayoutUpdateValidator validator = new TableLayoutUpdateValidator(getKiji());
    {
      final TableLayoutDesc desc =
          KijiTableLayouts.getLayout(INVALID_AVRO_VALIDATION_TEST);
      desc.setVersion(Versions.LAYOUT_1_2_0.toString());

      try {
        KijiTableLayout.createUpdatedLayout(desc,  null);
        fail("Must throw InvalidLayoutException "
            + "because AVRO cell type requires layout version >= 1.3.0");
      } catch (InvalidLayoutException ile) {
        LOG.info("Expected error: {}", ile.getMessage());
        assertTrue(ile.getMessage(),
            ile.getMessage().contains(
                "Cell type AVRO requires table layout version >= layout-1.3.0, "
                + "got version layout-1.2.0"));
      }
    }

    // Layout-1.3.0 does support validation.  The layout is invalid and will throw an exception.
    final TableLayoutDesc desc =
        KijiTableLayouts.getLayout(INVALID_AVRO_VALIDATION_TEST);
    try {
      validator.validate(null, KijiTableLayout.newLayout(desc));
      fail("should have thrown InvalidLayoutSchemaException because int and string are "
          + "incompatible.");
    } catch (InvalidLayoutSchemaException ilse) {
      assertTrue(ilse.getReasons().contains(
          "In column: 'info:fullname' Reader schema: \"int\" is incompatible with "
          + "writer schema: \"string\"."));
    }
  }


('/**\\n   * Validates a new table layout against a reference layout for mutual compatibility.\\n   *\\n   * @param reference the reference layout against which to validate.\\n   * @param layout the new layout to validate.\\n   * @throws IOException in case of an IO Error reading from the schema table.\\n   *     Throws InvalidLayoutException if the layouts are incompatible.\\n   */', '')

('', '// Layout versions older than layout-1.3.0 do not require validation\n')

('', '// Accumulator for error messages which will be used to create an exception if errors occur.\n')

('', '// Iterate through all families/columns in the new layout,\n')

('', '// find a potential matching reference family/column,\n')

('', '// and validate the reader/writer schema sets.\n')

('', '// If no matching family/column exists in the reference layout the newly create column is valid.\n')

('', '// If there is a reference layout, check for a locality group matching the ID of the LG for\n')

('', '// this family.  Locality Group IDs should not change between layouts.\n')

('', '// If there is a matching reference LG get its layout by name.\n')

('', '// The ColumnId of the FamilyLayout from the table layout.  Also matches the FamilyLayout for\n')

('', '// this family in the reference layout if present.\n')

('', '// If the family is map-type, get the CellSchema for all values in the family.\n')

('', '// If there is a matching reference LG, check for the existence of this family.\n')

('', '// If the FamilyLayout from both table layouts are map type, compare their CellSchemas.\n')

('', '// If the FamilyLayout changed from group-type to map-type between table layout versions\n')

('', '// that is an incompatible change.\n')

('', '// If the reference FamilyLayout is null this indicates a new family, which is inherently\n')

('', '// compatible, but we still have to validate that the new readers and writers are\n')

('', '// internally compatible.\n')

('', '// Check for a matching family from the reference layout.\n')

('', '// If there is a matching reference family and it is the same family type, iterate\n')

('', '// through the columns checking schema compatibility.  Only checks columns from the new\n')

('', '// layout because removed columns are inherently valid.\n')

('', '// If there is a column from the reference layout with the same column ID, get its\n')

('', '// layout.\n')

('', '// CellSchema.\n')

('', '// If there is no matching column, refCellSchema will be null and this will only test\n')

('', '// that the new reader and writer schemas are internally compatible.\n')

('', '// If the FamilyLayout changed from map-type to group-type between table layout versions\n')

('', '// internally compatible.\n')

('', '// If there were any incompatibility errors, throw an exception.\n')

@Test
  public void testAddRemoveModifyColumns() throws IOException {
    final TableLayoutUpdateValidator validator = new TableLayoutUpdateValidator(getKiji());
    final KijiColumnName validatedColumn = KijiColumnName.create("info:qual0");
    final TableLayoutDesc desc = new TableLayoutBuilder(
        KijiTableLayouts.getLayout(AVRO_VALIDATION_TEST), getKiji())
        .withReader(validatedColumn, TestRecord5.SCHEMA$)
        .withAvroValidationPolicy(validatedColumn, AvroValidationPolicy.STRICT)
        .withLayoutId("original")
        .build();

    // The initial layout is valid.
    validator.validate(null, KijiTableLayout.newLayout(desc));

    // Create an update which removes a column, adds a column, and modifies the set of readers for a
    // column in a compatible way.
    final TableLayoutDesc updateDesc =
        KijiTableLayouts.getLayout(AVRO_VALIDATION_UPDATE_TEST);
    updateDesc.setReferenceLayout("original");
    updateDesc.setLayoutId("updated");
    final TableLayoutDesc newDesc = new TableLayoutBuilder(updateDesc, getKiji())
        .withReader(validatedColumn, TestRecord4.SCHEMA$)
        .build();

    validator.validate(KijiTableLayout.newLayout(desc), KijiTableLayout.newLayout(newDesc));
  }


Initializes a ZooKeeper client The new ZooKeeperClient is returned with a retain count of one @param zkAddress Address of the ZooKeeper quorum as a commaseparated list of hostport

b'/**\n   * Initializes a ZooKeeper client. The new ZooKeeperClient is returned with a retain count of one.\n   *\n   * @param zkAddress Address of the ZooKeeper quorum, as a comma-separated list of "host:port".\n   */'private ZooKeeperClient(String zkAddress) {
    this.mZKAddress = zkAddress;
    LOG.debug("Created {}", this);
  }

@Test
  public void testZooKeeperClient() throws Exception {
    final ZooKeeperClient client = ZooKeeperClient.getZooKeeperClient(getZKAddress());

    try {
      Preconditions.checkNotNull(client.getZKClient(1.0));

      // Kill the ZooKeeper session
      KillSession.kill(client.getZKClient(1.0), getZKAddress());

      // This operation should block until a new ZooKeeper session is established, then proceed:
      client.createNodeRecursively(new File("/a/b/c/d/e/f"));

      Assert.assertEquals(0, client.exists(new File("/a/b/c/d/e/f")).getVersion());

    } finally {
      client.release();
    }
  }