Package com.linkedin.data.transform.patch

Source Code of com.linkedin.data.transform.patch.TestPatchOnData

/*
   Copyright (c) 2012 LinkedIn Corp.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

/**
* $id$
*/
package com.linkedin.data.transform.patch;


import com.fasterxml.jackson.core.JsonParseException;
import com.linkedin.data.DataMap;
import com.linkedin.data.transform.DataComplexProcessor;
import com.linkedin.data.transform.DataProcessingException;
import org.testng.annotations.Test;

import java.io.IOException;

import static com.linkedin.data.TestUtil.dataMapFromString;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;


public class TestPatchOnData
{

  /**
   * Set of tests. Each test contains a description, data, on which patch
   * will be performed and expected result.
   * Data and patch are expressed as JSON strings.
   *
   * For clarity it is allowed to use ' instead of ". Every ' character will be
   * replaced by " before parsing. THIS IS ONLY RELATED TO THIS TEST CLASS
   * TO MAKE TESTS CASES MORE CLEAR, PEGASUS DOESN'T DO ANYTHING LIKE THAT.
   */
  public static final String[][] TESTS = new String[][] {
    {
      /*description:*/"Patch is empty. Data object should not be modified.",
      /*data:*/       "{'a': 10, 'b': {'c': 'aaa'}}",
      /*patch:*/     "{}",
      /*expected*/    "{'a': 10, 'b': {'c': 'aaa'}}"
    },
    {
      /*description:*/"Delete field that does not exist should not cause error or stop processing, it " +
          "should be ignored.",
      /*data:*/       "{'a': 10, 'b': {'c': 'aaa'}}",
      /*patch:*/     "{'$delete': ['d', 'a'], 'b': { '$delete': ['e']}}",
      /*expected*/    "{'b': {'c': 'aaa'}}"
    },
    {
      /*description:*/"Branch of patch with deeply nested $delete field should be ignored when such a " +
          "branch does not exist in object.",
      /*data:*/       "{'a': 10, 'b': {'c': 'aaa'}}",
      /*patch:*/     "{'e': { '$delete': ['c']}}",
      /*expected*/    "{'a': 10, 'b': {'c': 'aaa'}}"
    },
    {
      /*description:*/"Branch of patch with deeply nested $delete field should not be ignored when such a " +
            "branch does not exist in object and deeply nested $delete resides along with deeply nested $set.",
      /*data:*/       "{'a': 10, 'b': {'c': 'aaa'}}",
      /*patch:*/     "{'e': { '$delete': ['c'], '$set': {'q': 1}}}",
      /*expected*/    "{'a': 10, 'b': {'c': 'aaa'}, 'e': {'q': 1}}"
    },
    {
      /*description:*/ "Patch of two fields of simple type at the root level." +
          " $set command should overwrite value if it already" +
          "exists in data and add to the parent object if it doesn't exist.",
      /*data:*/        "{'a': 10, 'b': {'c': 'aaa'}}",
      /*patch:*/      "{'$set': {'a': 20, 'd': 'ola'}}",
      /*expected*/     "{'a': 20, 'b': {'c': 'aaa'}, 'd': 'ola'}"
    },
    {
      /*description:*/"$delete command containing two fields at root level and one field at " +
            "nested level. Specified fields should be remved.",
      /*data:*/       "{'a': 10, 'b': {'c': 'aaa', 'e': 'hej'}, 'd': 'ola'}",
      /*patch:*/     "{'$delete': ['a', 'd'], 'b': {'$delete': ['e']}}",
      /*expected*/    "{'b': {'c': 'aaa'}}"
    },
    {
      /*description:*/"Deeply nested $delete operation aong with $set operation, while data object " +
          "does not have branch those commands reside in. In such case the $set operation should " +
          "succeed and missing path leading to it should be created.",
      /*data:*/       "{'a': 10}",
      /*patch:*/     "{'$delete': ['a', 'd'], 'b': { 'c': {'$delete': ['a'], '$set': {'e': 'f'}}}}",
      /*expected*/    "{'b': {'c': {'e': 'f'}}}"
    },
    {
      /*description:*/"Deeply nested $set operation. Only referenced field is set, rest of fields " +
          "remain unchanged.",
      /*data:*/
      "{"                       +
      "  'a' : 0,"            +
      "  'b' : {"             +
      "     'b1' : 0,"        +
      "     'b2' : {"         +
      "        'c1' : 0,"     +
      "        'c2' : {"      +
      "           'd1' : 0"   +
      "        }"               +
      "     }"                  +
      "   }"                    +
      "}",
      /*patch:*/     "{ 'b' : { 'b2' : { 'c2' : { '$set' : { 'd1' : 3 } } } }}",
      /*expected*/
      "{"                       +
      "  'a' : 0,"            +
      "  'b' : {"             +
      "     'b1' : 0,"        +
      "     'b2' : {"         +
      "        'c1' : 0,"     +
      "        'c2' : {"      +
      "           'd1' : 3"   +
      "        }"               +
      "     }"                  +
      "   }"                    +
      "}",

    }

  };

  private void genericPatchTest(DataMap data, DataMap patch,
                                        DataMap expected, String description) throws DataProcessingException {
    String dataBefore = data.toString();
    DataComplexProcessor processor = new DataComplexProcessor(new Patch(), patch, data);
    processor.run(false);
    assertEquals(data, expected, "The following test failed: \n" + description  +
                 "\nData: " + dataBefore + "\nPatch: " + patch +
                 "\nExpected: " + expected + "\nActual result: " + data);
  }

  @Test
  public void testPatchOnData() throws JsonParseException,
      IOException,
      DataProcessingException
  {
    for (String[] testCase : TESTS) {
      genericPatchTest(dataMapFromString(testCase[1].replace('\'', '"')),
                               dataMapFromString(testCase[2].replace('\'', '"')),
                               dataMapFromString(testCase[3].replace('\'', '"')),
                               testCase[0]);
    }
  }

  @Test
  public void testImplicitSetOperationInPatchIsNotSupported() throws JsonParseException, IOException, DataProcessingException {
    DataComplexProcessor processor = new DataComplexProcessor(new Patch(),
                                                      dataMapFromString("{ \"a\": 1 }")//command $set should be used
                                                      dataMapFromString("{}"));
    boolean thrown = false;
    try
    {
      processor.run(false);
    }
    catch (DataProcessingException e)
    {
      thrown = true;
    }
    if (!thrown)
      fail("expected DataProcessingException to be thrown");

  }

  @Test
  public void testMergingSimpleTypeValueWithComplexPatchNotSupported() throws JsonParseException, IOException, DataProcessingException {
    DataComplexProcessor processor = new DataComplexProcessor(new Patch(),
                                                      dataMapFromString("{ \"a\": { \"b\": 1} }")//command $set should be used
                                                      dataMapFromString("{\"a\": 1}"));
    boolean thrown = false;
    try
    {
      processor.run(false);
    }
    catch (DataProcessingException e)
    {
      thrown = true;
    }
    if (!thrown)
      fail("expected DataProcessingException to be thrown");
  }

  @Test
  public void testDeleteAndSetSameField() throws JsonParseException, IOException, DataProcessingException {
    DataComplexProcessor processor = new DataComplexProcessor(new Patch(),
                                                      dataMapFromString(
                                                        "{ \"$set\": { \"b\": 1}, \"$delete\": [\"b\"] }")//command $set should be used
                                                      dataMapFromString("{\"a\": 1}"));
    boolean thrown = false;
    try
    {
      processor.run(false);
    }
    catch (DataProcessingException e)
    {
      thrown = true;
    }
    if (!thrown)
      fail("expected DataProcessingException to be thrown");
  }

  @Test
  public void testDeleteAndBeBranchAtSameTime() throws JsonParseException, IOException, DataProcessingException {
    DataComplexProcessor processor = new DataComplexProcessor(new Patch(),
                                                      dataMapFromString(
                                                        "{ \"b\": { \"$set\": { \"b\": 1} }, \"$delete\": [\"b\"] }")//command $set should be used
                                                      dataMapFromString("{\"a\": 1}"));
    boolean thrown = false;
    try
    {
      processor.run(false);
    }
    catch (DataProcessingException e)
    {
      thrown = true;
    }
    if (!thrown)
      fail("expected DataProcessingException to be thrown");
  }

  @Test
  public void testSetAndBeBranchAtSameTime() throws JsonParseException, IOException, DataProcessingException {
    DataComplexProcessor processor = new DataComplexProcessor(new Patch(),
                                                      dataMapFromString(
                                                        "{ \"b\": { \"$set\": { \"b\": 1} }, \"$set\": {\"b\": 1} }")//command $set should be used
                                                      dataMapFromString("{\"a\": 1}"));
    boolean thrown = false;
    try
    {
      processor.run(false);
    }
    catch (DataProcessingException e)
    {
      thrown = true;
    }
    if (!thrown)
      fail("expected DataProcessingException to be thrown");
  }

}
TOP

Related Classes of com.linkedin.data.transform.patch.TestPatchOnData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.