You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2021/05/21 13:47:32 UTC

[ignite-3] 01/02: Add tests.

This is an automated email from the ASF dual-hosted git repository.

amashenkov pushed a commit to branch ignite-14759
in repository https://gitbox.apache.org/repos/asf/ignite-3.git

commit fd3171aa70e5ebec1c24483373c4240ea2b6ce85
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Fri May 21 15:25:32 2021 +0300

    Add tests.
---
 .../table/IndexColumnConfigurationSchema.java      |   4 +-
 .../runner/app/DynamicTableCreationTest.java       | 105 ++++++++++++++-----
 .../internal/runner/app/TableCreationTest.java     |  48 +++++++--
 .../ignite/internal/schema/SchemaManager.java      |  16 +--
 .../ignite/internal/schema/SchemaRegistry.java     |   6 +-
 .../org/apache/ignite/internal/schema/RowTest.java | 113 ++++++++++++++++-----
 6 files changed, 219 insertions(+), 73 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/IndexColumnConfigurationSchema.java b/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/IndexColumnConfigurationSchema.java
index e915040..3cf584c 100644
--- a/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/IndexColumnConfigurationSchema.java
+++ b/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/IndexColumnConfigurationSchema.java
@@ -30,6 +30,6 @@ public class IndexColumnConfigurationSchema {
     String name;
 
     /** Ascending flag. */
-    @Value
-    boolean asc;
+    @Value(hasDefault = true)
+    boolean asc = true;
 }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/DynamicTableCreationTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/DynamicTableCreationTest.java
index 13b8217..1cd05b6 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/DynamicTableCreationTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/DynamicTableCreationTest.java
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.UUID;
 import org.apache.ignite.app.Ignite;
 import org.apache.ignite.app.IgnitionManager;
+import org.apache.ignite.table.KeyValueBinaryView;
 import org.apache.ignite.table.Table;
 import org.apache.ignite.table.Tuple;
 import org.junit.jupiter.api.Disabled;
@@ -77,37 +78,53 @@ class DynamicTableCreationTest {
      */
     @Test
     void testDynamicSimpleTableCreation() {
-        List<Ignite> clusterNodex = new ArrayList<>();
+        List<Ignite> clusterNodes = new ArrayList<>();
 
         for (String nodeBootstrapCfg : nodesBootstrapCfg)
-            clusterNodex.add(IgnitionManager.start(nodeBootstrapCfg));
+            clusterNodes.add(IgnitionManager.start(nodeBootstrapCfg));
 
-        assertEquals(3, clusterNodex.size());
+        assertEquals(3, clusterNodes.size());
 
         // Create table on node 0.
-        clusterNodex.get(0).tables().createTable("tbl1", tbl -> tbl
+        clusterNodes.get(0).tables().createTable("tbl1", tbl -> tbl
+            .changeName("tbl1")
             .changeReplicas(1)
             .changePartitions(10)
             .changeColumns(cols -> cols
-                .create("key", c -> c.changeType(t -> t.changeType("INT64")))
-                .create("val", c -> c.changeType(t -> t.changeType("INT64")))
+                .create("key", c -> c.changeName("key").changeNullable(false).changeType(t -> t.changeType("INT64")))
+                .create("val", c -> c.changeName("val").changeNullable(true).changeType(t -> t.changeType("INT64")))
             )
             .changeIndices(idxs -> idxs
                 .create("PK", idx -> idx
+                    .changeName("PK")
                     .changeType("PRIMARY")
+                    .changeColNames(new String[] {"key"})
                     .changeColumns(c -> c
-                        .create("key", t -> {
-                        }))
+                        .create("key", t -> t.changeName("key")))
                     .changeAffinityColumns(new String[] {"key"}))
             ));
 
         // Put data on node 1.
-        Table tbl1 = clusterNodex.get(1).tables().table("tbl1");
-        tbl1.insert(tbl1.tupleBuilder().set("key", 1L).set("val", 111L).build());
+        Table tbl1 = clusterNodes.get(1).tables().table("tbl1");
+        KeyValueBinaryView kvView1 = tbl1.kvView();
+
+        tbl1.insert(tbl1.tupleBuilder().set("key", 1L).set("val", 111).build());
+        kvView1.put(tbl1.tupleBuilder().set("key", 2L).build(), tbl1.tupleBuilder().set("val", 222).build());
 
         // Get data on node 2.
-        Table tbl2 = clusterNodex.get(2).tables().table("tbl1");
-        assertEquals(111L, tbl2.get(tbl2.tupleBuilder().set("key", 1L).build()));
+        Table tbl2 = clusterNodes.get(2).tables().table("tbl1");
+        KeyValueBinaryView kvView2 = tbl2.kvView();
+
+        final Tuple keyTuple1 = tbl2.tupleBuilder().set("key", 1L).build();
+        final Tuple keyTuple2 = kvView2.tupleBuilder().set("key", 2L).build();
+
+        assertEquals(111, (Integer)kvView2.get(keyTuple1).value("key"));
+        assertEquals(222, (Integer)kvView2.get(keyTuple2).value("key"));
+
+        assertEquals(111, (Integer)tbl2.get(keyTuple1).value("val"));
+        assertEquals(111, (Integer)kvView2.get(keyTuple1).value("val"));
+        assertEquals(222, (Integer)tbl2.get(keyTuple2).value("val"));
+        assertEquals(222, (Integer)kvView2.get(keyTuple2).value("val"));
     }
 
     /**
@@ -124,39 +141,73 @@ class DynamicTableCreationTest {
 
         // Create table on node 0.
         clusterNodes.get(0).tables().createTable("tbl1", tbl -> tbl
+            .changeName("tbl1")
             .changeReplicas(1)
             .changePartitions(10)
             .changeColumns(cols -> cols
-                .create("key", c -> c.changeType(t -> t.changeType("UUID")))
-                .create("affKey", c -> c.changeType(t -> t.changeType("INT64")))
-                .create("valStr", c -> c.changeType(t -> t.changeType("STRING")))
-                .create("valInt", c -> c.changeType(t -> t.changeType("INT32")))
-                .create("valNullable", c -> c.changeType(t -> t.changeType("INT8")).changeNullable(true))
+                .create("key", c -> c.changeName("key").changeNullable(false).changeType(t -> t.changeType("UUID")))
+                .create("affKey", c -> c.changeName("affKey").changeNullable(false).changeType(t -> t.changeType("INT64")))
+                .create("valStr", c -> c.changeName("valStr").changeNullable(true).changeType(t -> t.changeType("STRING")))
+                .create("valInt", c -> c.changeName("valInt").changeNullable(true).changeType(t -> t.changeType("INT32")))
+                .create("valNull", c -> c.changeName("valNull").changeNullable(true).changeType(t -> t.changeType("INT16")).changeNullable(true))
             )
             .changeIndices(idxs -> idxs
                 .create("PK", idx -> idx
+                    .changeName("PK")
                     .changeType("PRIMARY")
+                    .changeColNames(new String[] {"key", "affKey"})
                     .changeColumns(c -> c
-                        .create("key", t -> {
-                        })
-                        .create("affKey", t -> {
-                        }))
+                        .create("key", t -> t.changeName("key").changeAsc(true))
+                        .create("affKey", t -> t.changeName("affKey").changeAsc(false)))
                     .changeAffinityColumns(new String[] {"affKey"}))
             ));
 
         final UUID uuid = UUID.randomUUID();
+        final UUID uuid2 = UUID.randomUUID();
 
         // Put data on node 1.
         Table tbl1 = clusterNodes.get(1).tables().table("tbl1");
+        KeyValueBinaryView kvView1 = tbl1.kvView();
+
         tbl1.insert(tbl1.tupleBuilder().set("key", uuid).set("affKey", 42L)
-            .set("valStr", "String value").set("valInt", 73L).set("valNullable", null).build());
+            .set("valStr", "String value").set("valInt", 73).set("valNull", null).build());
+
+        kvView1.put(kvView1.tupleBuilder().set("key", uuid2).set("affKey", 4242L).build(),
+            kvView1.tupleBuilder().set("valStr", "String value 2").set("valInt", 7373).set("valNull", null).build());
 
         // Get data on node 2.
         Table tbl2 = clusterNodes.get(2).tables().table("tbl1");
-        final Tuple val = tbl2.get(tbl1.tupleBuilder().set("key", uuid).set("affKey", 42L).build());
-
-        assertEquals("String value", val.value("valStr"));
-        assertEquals(73L, (Long)val.value("valInt"));
-        assertNull(val.value("valNullable"));
+        KeyValueBinaryView kvView2 = tbl2.kvView();
+
+        final Tuple keyTuple1 = tbl2.tupleBuilder().set("key", uuid).set("affKey", 42L).build();
+        final Tuple keyTuple2 = kvView2.tupleBuilder().set("key", uuid2).set("affKey", 4242L).build();
+
+        // KV view must NOT return key columns in value.
+        assertNull(kvView2.get(keyTuple1).value("key"));
+        assertNull(kvView2.get(keyTuple1).value("affKey"));
+        assertNull(kvView2.get(keyTuple2).value("key"));
+        assertNull(kvView2.get(keyTuple2).value("affKey"));
+
+        // Record binary view MUST return key columns in value.
+        assertEquals(uuid, tbl2.get(keyTuple1).value("key"));
+        assertEquals(42L, (Long)tbl2.get(keyTuple1).value("affKey"));
+        assertEquals(uuid2, tbl2.get(keyTuple2).value("key"));
+        assertEquals(4242L, (Long)tbl2.get(keyTuple2).value("affKey"));
+
+        assertEquals("String value", tbl2.get(keyTuple1).value("valStr"));
+        assertEquals(73, (Integer)tbl2.get(keyTuple1).value("valInt"));
+        assertNull(tbl2.get(keyTuple1).value("valNull"));
+
+        assertEquals("String value 2", tbl2.get(keyTuple2).value("valStr"));
+        assertEquals(7373, (Integer)tbl2.get(keyTuple2).value("valInt"));
+        assertNull(tbl2.get(keyTuple2).value("valNull"));
+
+        assertEquals("String value", kvView2.get(keyTuple1).value("valStr"));
+        assertEquals(73, (Integer)kvView2.get(keyTuple1).value("valInt"));
+        assertNull(kvView2.get(keyTuple1).value("valNull"));
+
+        assertEquals("String value 2", kvView2.get(keyTuple2).value("valStr"));
+        assertEquals(7373, (Integer)kvView2.get(keyTuple2).value("valInt"));
+        assertNull(kvView2.get(keyTuple2).value("valNull"));
     }
 }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/TableCreationTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/TableCreationTest.java
index 035caad..e9834ae 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/TableCreationTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/TableCreationTest.java
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.UUID;
 import org.apache.ignite.app.Ignite;
 import org.apache.ignite.app.IgnitionManager;
+import org.apache.ignite.table.KeyValueBinaryView;
 import org.apache.ignite.table.Table;
 import org.apache.ignite.table.Tuple;
 import org.junit.jupiter.api.Assertions;
@@ -162,29 +163,58 @@ class TableCreationTest {
 
         clusterNodes.forEach(Assertions::assertNotNull);
 
-        { /* Table 1.*/
+        { /* Table 1. */
             Table tbl1 = clusterNodes.get(1).tables().table("tbl1");
-            tbl1.insert(tbl1.tupleBuilder().set("key", 1L).set("val", 111L).build());
+            KeyValueBinaryView kvView1 = tbl1.kvView();
+
+            tbl1.insert(tbl1.tupleBuilder().set("key", 1L).set("val", 111).build());
+            kvView1.put(tbl1.tupleBuilder().set("key", 2L).build(), tbl1.tupleBuilder().set("val", 222).build());
 
             Table tbl2 = clusterNodes.get(2).tables().table("tbl1");
-            assertEquals(111L, tbl2.get(tbl2.tupleBuilder().set("key", 1L).build()));
+            KeyValueBinaryView kvView2 = tbl2.kvView();
+
+            final Tuple keyTuple1 = tbl2.tupleBuilder().set("key", 1L).build();
+            final Tuple keyTuple2 = kvView2.tupleBuilder().set("key", 2L).build();
+
+            assertEquals(111, (Integer)tbl2.get(keyTuple1).value("val"));
+            assertEquals(111, (Integer)kvView1.get(keyTuple1).value("val"));
+            assertEquals(222, (Integer)tbl2.get(keyTuple2).value("val"));
+            assertEquals(222, (Integer)kvView1.get(keyTuple2).value("val"));
         }
 
         { /* Table 2. */
             final UUID uuid = UUID.randomUUID();
+            final UUID uuid2 = UUID.randomUUID();
 
             // Put data on node 1.
             Table tbl1 = clusterNodes.get(1).tables().table("tbl1");
+            KeyValueBinaryView kvView1 = tbl1.kvView();
+
             tbl1.insert(tbl1.tupleBuilder().set("key", uuid).set("affKey", 42L)
-                .set("valStr", "String value").set("valInt", 73L).set("valNullable", null).build());
+                .set("valStr", "String value").set("valInt", 73).set("valNullable", null).build());
+
+            kvView1.put(kvView1.tupleBuilder().set("key", uuid2).set("affKey", 4242L).build(),
+                kvView1.tupleBuilder().set("valStr", "String value 2").set("valInt", 7373).set("valNullable", null).build());
 
             // Get data on node 2.
             Table tbl2 = clusterNodes.get(2).tables().table("tbl1");
-            final Tuple val = tbl2.get(tbl1.tupleBuilder().set("key", uuid).set("affKey", 42L).build());
-
-            assertEquals("String value", val.value("valStr"));
-            assertEquals(73L, (Long)val.value("valInt"));
-            assertNull(val.value("valNullable"));
+            KeyValueBinaryView kvView2 = tbl2.kvView();
+
+            final Tuple keyTuple1 = tbl2.tupleBuilder().set("key", uuid).set("affKey", 42L).build();
+            final Tuple keyTuple2 = kvView2.tupleBuilder().set("key", uuid2).set("affKey", 4242L).build();
+
+            assertEquals("String value", tbl2.get(keyTuple1).value("valStr"));
+            assertEquals("String value", kvView2.get(keyTuple1).value("valStr"));
+            assertEquals("String value 2", tbl2.get(keyTuple2).value("valStr"));
+            assertEquals("String value 2", kvView2.get(keyTuple2).value("valStr"));
+            assertEquals(73, (Integer)tbl2.get(keyTuple1).value("valInt"));
+            assertEquals(73, (Integer)kvView2.get(keyTuple1).value("valInt"));
+            assertEquals(7373, (Integer)tbl2.get(keyTuple2).value("valInt"));
+            assertEquals(7373, (Integer)kvView2.get(keyTuple2).value("valInt"));
+            assertNull(tbl2.get(keyTuple1).value("valNullable"));
+            assertNull(kvView2.get(keyTuple1).value("valNullable"));
+            assertNull(tbl2.get(keyTuple2).value("valNullable"));
+            assertNull(kvView2.get(keyTuple2).value("valNullable"));
         }
     }
 }
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaManager.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaManager.java
index 58361d3..90b6fc5 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaManager.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaManager.java
@@ -110,7 +110,7 @@ public class SchemaManager extends Producer<SchemaEvent, SchemaEventParameters>
         metaStorageMgr.registerWatchByPrefix(new ByteArray(INTERNAL_PREFIX), new WatchListener() {
             @Override public boolean onUpdate(@NotNull WatchEvent events) {
                 for (EntryEvent evt : events.entryEvents()) {
-                    String keyTail = evt.newEntry().key().toString().substring(INTERNAL_PREFIX.length() - 1);
+                    String keyTail = evt.newEntry().key().toString().substring(INTERNAL_PREFIX.length());
 
                     int verPos = keyTail.indexOf(INTERNAL_VER_SUFFIX);
 
@@ -254,13 +254,13 @@ public class SchemaManager extends Producer<SchemaEvent, SchemaEventParameters>
      */
     private NativeType createType(ColumnTypeView type) {
         switch (type.type().toLowerCase()) {
-            case "byte":
+            case "int8":
                 return NativeTypes.BYTE;
-            case "short":
+            case "int16":
                 return NativeTypes.SHORT;
-            case "int":
+            case "int32":
                 return NativeTypes.INTEGER;
-            case "long":
+            case "int64":
                 return NativeTypes.LONG;
             case "float":
                 return NativeTypes.FLOAT;
@@ -269,11 +269,13 @@ public class SchemaManager extends Producer<SchemaEvent, SchemaEventParameters>
             case "uuid":
                 return NativeTypes.UUID;
             case "bitmask":
+                assert type.length() > 0;
+
                 return NativeTypes.bitmaskOf(type.length());
             case "string":
-                return NativeTypes.stringOf(type.length());
+                return type.length() == 0 ? NativeTypes.STRING : NativeTypes.stringOf(type.length());
             case "bytes":
-                return NativeTypes.blobOf(type.length());
+                return type.length() == 0 ? NativeTypes.BYTES : NativeTypes.blobOf(type.length());
 
             default:
                 throw new IllegalStateException("Unsupported column type: " + type.type());
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaRegistry.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaRegistry.java
index 8da7278..777adf1 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaRegistry.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaRegistry.java
@@ -17,6 +17,9 @@
 
 package org.apache.ignite.internal.schema;
 
+import org.apache.ignite.internal.schema.registry.SchemaRegistryException;
+import org.jetbrains.annotations.NotNull;
+
 /**
  * Table schema registry interface.
  */
@@ -29,6 +32,7 @@ public interface SchemaRegistry {
     /**
      * @param ver Schema version.
      * @return Schema of given version.
+     * @throws SchemaRegistryException If schema was not found.
      */
-    SchemaDescriptor schema(int ver);
+    @NotNull SchemaDescriptor schema(int ver) throws SchemaRegistryException;
 }
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/RowTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/RowTest.java
index cdb1d31..08ef37f 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/RowTest.java
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/RowTest.java
@@ -40,11 +40,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
  * Tests row assembling and reading.
  */
 public class RowTest {
-    /** */
+    /** Random. */
     private Random rnd;
 
     /**
-     *
+     * Initialization.
      */
     @BeforeEach
     public void initRandom() {
@@ -56,10 +56,42 @@ public class RowTest {
     }
 
     /**
-     *
+     * Check row serialization for schema with nullable fix-sized columns only.
      */
     @Test
-    public void fixedSizes() {
+    public void nullableFixSizedColumns() {
+        Column[] keyCols = new Column[] {
+            new Column("keyByteCol", BYTE, false),
+            new Column("keyShortCol", SHORT, false),
+            new Column("keyIntCol", INTEGER, false),
+            new Column("keyLongCol", LONG, false),
+            new Column("keyFloatCol", FLOAT, false),
+            new Column("keyDoubleCol", DOUBLE, false),
+            new Column("keyUuidCol", UUID, false),
+            new Column("keyBitmask1Col", NativeTypes.bitmaskOf(4), false),
+            new Column("keyBitmask2Col", NativeTypes.bitmaskOf(22), false)
+        };
+
+        Column[] valCols = new Column[] {
+            new Column("valByteCol", BYTE, false),
+            new Column("valShortCol", SHORT, false),
+            new Column("valIntCol", INTEGER, false),
+            new Column("valLongCol", LONG, false),
+            new Column("valFloatCol", FLOAT, false),
+            new Column("valDoubleCol", DOUBLE, false),
+            new Column("valUuidCol", UUID, false),
+            new Column("valBitmask1Col", NativeTypes.bitmaskOf(4), false),
+            new Column("valBitmask2Col", NativeTypes.bitmaskOf(22), false)
+        };
+
+        checkSchema(keyCols, valCols);
+    }
+
+    /**
+     * Check row serialization for schema with non-nullable fix-sized columns only.
+     */
+    @Test
+    public void fixSizedColumns() {
         Column[] keyCols = new Column[] {
             new Column("keyByteCol", BYTE, true),
             new Column("keyShortCol", SHORT, true),
@@ -88,17 +120,17 @@ public class RowTest {
     }
 
     /**
-     *
+     * Check row serialization for schema with various columns.
      */
     @Test
-    public void variableSizes() {
+    public void mixedColumns() {
         Column[] keyCols = new Column[] {
-            new Column("keyByteCol", BYTE, true),
-            new Column("keyShortCol", SHORT, true),
-            new Column("keyIntCol", INTEGER, true),
-            new Column("keyLongCol", LONG, true),
-            new Column("keyBytesCol", BYTES, true),
-            new Column("keyStringCol", STRING, true),
+            new Column("keyByteCol", BYTE, false),
+            new Column("keyShortCol", SHORT, false),
+            new Column("keyIntCol", INTEGER, false),
+            new Column("keyLongCol", LONG, false),
+            new Column("keyBytesCol", BYTES, false),
+            new Column("keyStringCol", STRING, false),
         };
 
         Column[] valCols = new Column[] {
@@ -114,10 +146,28 @@ public class RowTest {
     }
 
     /**
-     *
+     * Check row serialization for schema with non-nullable varlen columns only.
+     */
+    @Test
+    public void varlenColumns() {
+        Column[] keyCols = new Column[] {
+            new Column("keyBytesCol", BYTES, false),
+            new Column("keyStringCol", STRING, false),
+        };
+
+        Column[] valCols = new Column[] {
+            new Column("valBytesCol", BYTES, false),
+            new Column("valStringCol", STRING, false),
+        };
+
+        checkSchema(keyCols, valCols);
+    }
+
+    /**
+     * Check row serialization for schema with nullable varlen columns only.
      */
     @Test
-    public void mixedSizes() {
+    public void nullableVarlenColumns() {
         Column[] keyCols = new Column[] {
             new Column("keyBytesCol", BYTES, true),
             new Column("keyStringCol", STRING, true),
@@ -132,7 +182,10 @@ public class RowTest {
     }
 
     /**
+     * Checks schema is independent from prodived column order.
      *
+     * @param keyCols Key columns.
+     * @param valCols Value columns.
      */
     private void checkSchema(Column[] keyCols, Column[] valCols) {
         checkSchemaShuffled(keyCols, valCols);
@@ -144,38 +197,38 @@ public class RowTest {
     }
 
     /**
+     * Checks schema for given columns.
      *
+     * @param keyCols Key columns.
+     * @param valCols Value columns.
      */
     private void checkSchemaShuffled(Column[] keyCols, Column[] valCols) {
         SchemaDescriptor sch = new SchemaDescriptor(java.util.UUID.randomUUID(), 1, keyCols, valCols);
 
-        Object[] checkArr = sequence(sch);
+        Object[] checkArr = generateRowValues(sch);
 
         checkValues(sch, checkArr);
 
-        while (checkArr[0] != null) {
-            int idx = 0;
+        for (int idx = 0; idx < checkArr.length; idx++) {
+            if (!sch.column(idx).nullable())
+                continue;
 
             Object prev = checkArr[idx];
             checkArr[idx] = null;
 
             checkValues(sch, checkArr);
 
-            while (idx < checkArr.length - 1 && checkArr[idx + 1] != null) {
-                checkArr[idx] = prev;
-                prev = checkArr[idx + 1];
-                checkArr[idx + 1] = null;
-                idx++;
-
-                checkValues(sch, checkArr);
-            }
+            checkArr[idx] = prev;
         }
     }
 
     /**
+     * Generate row values for given row schema.
      *
+     * @param schema Row schema.
+     * @return Row values.
      */
-    private Object[] sequence(SchemaDescriptor schema) {
+    private Object[] generateRowValues(SchemaDescriptor schema) {
         Object[] res = new Object[schema.length()];
 
         for (int i = 0; i < res.length; i++) {
@@ -188,14 +241,20 @@ public class RowTest {
     }
 
     /**
+     * Generates random value of a given type.
      *
+     * @param type Value type.
+     * @return Random value of requested type.
      */
     private Object generateRandomValue(NativeType type) {
         return TestUtils.generateRandomValue(rnd, type);
     }
 
     /**
+     * Validates row values after serialization-deserialization.
      *
+     * @param schema Row schema.
+     * @param vals Row values.
      */
     private void checkValues(SchemaDescriptor schema, Object... vals) {
         assertEquals(schema.keyColumns().length() + schema.valueColumns().length(), vals.length);
@@ -312,7 +371,7 @@ public class RowTest {
     }
 
     /**
-     *
+     * Suffle columns.
      */
     private void shuffle(Column[] cols) {
         Collections.shuffle(Arrays.asList(cols));