From 06d8f737c7af95bb94f83ae91e76f555a72e23af Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Wed, 18 Mar 2015 12:27:44 +0000
Subject: [PATCH] SSDM-1621: AssignDataSetToSampleTest: All tests refactored in
 order to use EntityGraphGenerator.

SVN: 33685
---
 .../business/bo/entitygraph/DataSetNode.java  |   9 +
 .../bo/entitygraph/EntityGraphGenerator.java  |   1 +
 .../systemtest/AssignDataSetToSampleTest.java | 390 ++++++++++++------
 .../openbis/systemtest/base/BaseTest.java     |  67 ++-
 .../base/builder/DataSetUpdateBuilder.java    |  10 +-
 5 files changed, 330 insertions(+), 147 deletions(-)

diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/entitygraph/DataSetNode.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/entitygraph/DataSetNode.java
index a4e25ff5e77..75870c97a87 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/entitygraph/DataSetNode.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/entitygraph/DataSetNode.java
@@ -100,6 +100,15 @@ public final class DataSetNode extends EntityNode
         }
     }
     
+    void hasParents(DataSetNode...someParentDataSets)
+    {
+        for (DataSetNode parentDataSet : someParentDataSets)
+        {
+            parents.add(parentDataSet);
+            parentDataSet.children.add(this);
+        }
+    }
+    
     @Override
     public String toString()
     {
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/entitygraph/EntityGraphGenerator.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/entitygraph/EntityGraphGenerator.java
index dee614076a8..c837ef4e7a2 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/entitygraph/EntityGraphGenerator.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/entitygraph/EntityGraphGenerator.java
@@ -104,6 +104,7 @@ public final class EntityGraphGenerator
         private void handle(DataSetNode dataSet, List<String> parts)
         {
             dataSet.hasChildren(getDataSets("children", parts));
+            dataSet.hasParents(getDataSets("parents", parts));
             dataSet.hasComponents(getDataSets("components", parts));
         }
         
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/AssignDataSetToSampleTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/AssignDataSetToSampleTest.java
index 189dc76ec01..b77b52059c9 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/AssignDataSetToSampleTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/AssignDataSetToSampleTest.java
@@ -20,11 +20,11 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.fail;
 
-import org.testng.AssertJUnit;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import ch.systemsx.cisd.common.exceptions.AuthorizationFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.entitygraph.DataSetNode;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.entitygraph.EntityGraphGenerator;
@@ -48,6 +48,7 @@ import ch.systemsx.cisd.openbis.systemtest.base.auth.SpaceDomain;
 
 /**
  * @author anttil
+ * @author Franz-Josef Elmer
  */
 public class AssignDataSetToSampleTest extends BaseTest
 {
@@ -64,30 +65,59 @@ public class AssignDataSetToSampleTest extends BaseTest
     Space destinationSpace;
     
     @Test
-    public void containerWithAComponentOfWrongTypeReassignedFromExperimentToSampleWithoutExperiment()
+    public void reassignTheTwoOriginalDataSetsOfPublishedDataSetsToDifferentOriginalSampleAndExperiment()
     {
-        EntityGraphGenerator g = parseAndCreateGraph("E1, data sets: DS1[NECT] DS2\n"
-                + "S2, data sets: DS5[NET]\n"
-                + "DS1[NECT], components: DS2\n");
+        EntityGraphGenerator g = parseAndCreateGraph("E1, samples: S1, data sets: DS3 DS4 DS5 DS6\n"
+                + "E2, data sets: DS1 DS2\n"
+                + "E3, samples: S3\n"
+                + "S1, data sets: DS3\n"
+                + "DS1, components: DS3\n"
+                + "DS2, components: DS4\n"
+                + "DS3, components: DS5 DS6\n");
+
+        reassignToSample(g.ds(3), g.s(3));
+        reassignToExperiment(g.ds(4), g.e(3));
+
+        assertEquals("E1, samples: S1\n"
+                + "E2, data sets: DS1 DS2\n"
+                + "E3, samples: S3, data sets: DS3 DS4 DS5 DS6\n"
+                + "S3, data sets: DS3\n"
+                + "DS1, components: DS3\n"
+                + "DS2, components: DS4\n"
+                + "DS3, components: DS5 DS6\n", renderGraph(g));
+        repository.assertModified(g.e(1), g.e(3));
+        repository.assertModified(g.s(1), g.s(3));
+        repository.assertModified(g.ds(3), g.ds(4), g.ds(5), g.ds(6));
+        repository.assertUnmodified(g);
+    }
+    
+    @Test
+    public void reassignTwoPublishedDataSetToAnotherPublicExperiment()
+    {
+        EntityGraphGenerator g = parseAndCreateGraph("E1, samples: S1, data sets: DS3 DS4 DS5 DS6\n"
+                + "E2, data sets: DS1 DS2\n"
+                + "E3\n"
+                + "S1, data sets: DS3\n"
+                + "DS1, components: DS3\n"
+                + "DS2, components: DS4\n"
+                + "DS3, components: DS5 DS6\n");
         
-        try
-        {
-            reassignToSample(g.ds(1), g.s(2));
-            fail("UserFailureException expected");
-        } catch (UserFailureException ex)
-        {
-            AbstractExternalData dataSet = repository.getDataSet(g.ds(2));
-            assertEquals("The dataset '" + dataSet.getCode()
-                    + "' cannot be connected to the sample '" + repository.getSample(g.s(2)).getIdentifier()
-                    + "' because the new sample is not connected to any experiment and the data set type (" 
-                    + dataSet.getDataSetType().getCode()
-                    + ") doesn't match one of the following regular expressions:   NO-EXP-.* ,   NE.*  .",
-                    ex.getMessage());
-        }
+        reassignToExperiment(g.ds(1), g.e(3));
+        reassignToExperiment(g.ds(2), g.e(3));
+        
+        assertEquals("E1, samples: S1, data sets: DS3 DS4 DS5 DS6\n"
+                + "E3, data sets: DS1 DS2\n"
+                + "S1, data sets: DS3\n"
+                + "DS1, components: DS3\n"
+                + "DS2, components: DS4\n"
+                + "DS3, components: DS5 DS6\n", renderGraph(g));
+        repository.assertModified(g.e(2), g.e(3));
+        repository.assertModified(g.ds(1), g.ds(2));
+        repository.assertUnmodified(g);
     }
     
     @Test
-    public void containerWithSomeComponentsReassigned()
+    public void containerWithSomeComponentsReassignedFromSampleWithoutExperimentToSampleWithExperiment()
     {
         EntityGraphGenerator g = parseAndCreateGraph("E1, data sets: DS4\n"
                 + "E2, samples: S2\n"
@@ -96,15 +126,38 @@ public class AssignDataSetToSampleTest extends BaseTest
                 + "DS1[NECT], components: DS2[NECT] DS3[NET]\n"
                 + "DS2[NECT], components: DS4");
         
-        reassignToExperiment(g.ds(1), g.e(2));
+        reassignToSample(g.ds(1), g.s(2));
         
         assertEquals("E1, data sets: DS4\n"
                 + "E2, samples: S2, data sets: DS1[NECT] DS2[NECT]\n"
+                + "S2, data sets: DS1[NECT] DS2[NECT]\n"
                 + "S3, data sets: DS3[NET]\n"
                 + "DS1[NECT], components: DS2[NECT] DS3[NET]\n"
                 + "DS2[NECT], components: DS4\n", renderGraph(g));
         repository.assertModified(g.e(2));
-        repository.assertModified(g.s(1));
+        repository.assertModified(g.s(1), g.s(2));
+        repository.assertModified(g.ds(1), g.ds(2));
+        repository.assertUnmodified(g);
+    }
+    
+    @Test
+    public void containerWithSomeComponentsReassignedFromSampleWithoutExperimentToSampleWithoutExperiment()
+    {
+        EntityGraphGenerator g = parseAndCreateGraph("E1, data sets: DS4\n"
+                + "S1, data sets: DS1[NECT] DS2[NECT]\n"
+                + "S2\n"
+                + "S3, data sets: DS3[NET]\n"
+                + "DS1[NECT], components: DS2[NECT] DS3[NET]\n"
+                + "DS2[NECT], components: DS4");
+        
+        reassignToSample(g.ds(1), g.s(2));
+        
+        assertEquals("E1, data sets: DS4\n"
+                + "S2, data sets: DS1[NECT] DS2[NECT]\n"
+                + "S3, data sets: DS3[NET]\n"
+                + "DS1[NECT], components: DS2[NECT] DS3[NET]\n"
+                + "DS2[NECT], components: DS4\n", renderGraph(g));
+        repository.assertModified(g.s(1), g.s(2));
         repository.assertModified(g.ds(1), g.ds(2));
         repository.assertUnmodified(g);
     }
@@ -297,6 +350,7 @@ public class AssignDataSetToSampleTest extends BaseTest
         repository.assertUnmodified(g);
     }
     
+    // This is screening test case where one container data set is moved to another plate.
     @Test
     public void containerWithAllItsComponentsReassignedFromSampleWithExperimentToSampleWithExperiment()
     {
@@ -387,145 +441,199 @@ public class AssignDataSetToSampleTest extends BaseTest
         repository.assertUnmodified(g);
     }
     
-    @Test(expectedExceptions =
-        { UserFailureException.class })
-    public void dataSetCannotBeAssignedToSpaceSample() throws Exception
-    {
-        Sample sample = create(aSample().inSpace(destinationSpace));
-        AbstractExternalData dataset = create(aDataSet().inSample(sourceSample));
-
-        perform(anUpdateOf(dataset).toSample(sample));
-    }
-
-    @Test(expectedExceptions =
-        { UserFailureException.class })
-    public void dataSetCannotBeAssignedToSharedSample() throws Exception
-    {
-        Sample sample = create(aSample());
-        AbstractExternalData dataset = create(aDataSet().inSample(sourceSample));
-
-        perform(anUpdateOf(dataset).toSample(sample));
-    }
-
     @Test
-    public void childDataSetCanBeAssignedToAnotherSample() throws Exception
+    public void containerWithAComponentOfWrongTypeReassignedFromExperimentToSampleWithoutExperiment()
     {
-        AbstractExternalData parent = create(aDataSet().inSample(sourceSample));
-        AbstractExternalData child = create(aDataSet().inSample(sourceSample).withParent(parent));
-
-        perform(anUpdateOf(child).toSample(destinationSample));
-
-        assertThat(child, is(inSample(destinationSample)));
+        EntityGraphGenerator g = parseAndCreateGraph("E1, data sets: DS1[NECT] DS2\n"
+                + "S2, data sets: DS5[NET]\n"
+                + "DS1[NECT], components: DS2\n");
+        
+        try
+        {
+            reassignToSample(g.ds(1), g.s(2));
+            fail("UserFailureException expected");
+        } catch (UserFailureException ex)
+        {
+            AbstractExternalData dataSet = repository.getDataSet(g.ds(2));
+            Sample sample = repository.getSample(g.s(2));
+            assertDataSetToSampleExceptionMessage(ex, sample, dataSet);
+        }
     }
-
+    
     @Test
-    public void sampleAssignmentOfParentDataSetIsNotChangedWhenChildDataSetIsAssignedToAnotherSample()
-            throws Exception
+    public void dataSetCannotBeAssignedToSpaceSample()
     {
-        AbstractExternalData parent = create(aDataSet().inSample(sourceSample));
-        AbstractExternalData child = create(aDataSet().inSample(sourceSample).withParent(parent));
+        EntityGraphGenerator g = parseAndCreateGraph("E1, data sets: DS1\nS2\n");
 
-        perform(anUpdateOf(child).toSample(destinationSample));
-
-        assertThat(parent, is(inSample(sourceSample)));
+        try
+        {
+            reassignToSample(g.ds(1), g.s(2));
+            fail("UserFailureException expected");
+        } catch (UserFailureException ex)
+        {
+            AbstractExternalData dataSet = repository.getDataSet(g.ds(1));
+            Sample sample = repository.getSample(g.s(2));
+            assertDataSetToSampleExceptionMessage(ex, sample, dataSet);
+        }
     }
 
     @Test
-    public void parentDataSetCanBeAssignedToAnotherSample() throws Exception
+    public void dataSetCannotBeAssignedToSharedSample()
     {
-        AbstractExternalData parent = create(aDataSet().inSample(sourceSample));
-        create(aDataSet().inSample(sourceSample).withParent(parent));
-
-        perform(anUpdateOf(parent).toSample(destinationSample));
+        Sample sample = create(aSample());
+        AbstractExternalData dataset = create(aDataSet().inSample(sourceSample));
 
-        assertThat(parent, is(inSample(destinationSample)));
+        try
+        {
+            String user = create(aSession().withInstanceRole(RoleCode.ADMIN));
+            reassignToSample(dataset.getCode(), sample.getPermId(), user);
+            fail("UserFailureException expected");
+        } catch (UserFailureException ex)
+        {
+            assertDataSetToSampleExceptionMessage(ex, sample, dataset);
+        }
     }
 
     @Test
-    public void sampleAssignmentOfChildDataSetIsNotChangedWhenParentDatasetIsAssignedToAnotherSample()
-            throws Exception
+    public void sampleAssignmentOfParentDataSetIsNotChangedWhenChildDataSetIsAssignedToAnotherSample()
     {
-        AbstractExternalData parent = create(aDataSet().inSample(sourceSample));
-        AbstractExternalData child = create(aDataSet().inSample(sourceSample).withParent(parent));
-
-        perform(anUpdateOf(parent).toSample(destinationSample));
-
-        assertThat(child, is(inSample(sourceSample)));
+        EntityGraphGenerator g = parseAndCreateGraph("E1, samples: S1, data sets: DS1 DS2\n"
+                + "E2, samples: S2\n"
+                + "S1, data sets: DS1 DS2\n"
+                + "DS1, parents: DS2\n");
+        
+        reassignToSample(g.ds(1), g.s(2));
+        
+        assertEquals("E1, samples: S1, data sets: DS2\n"
+                + "E2, samples: S2, data sets: DS1\n"
+                + "S1, data sets: DS2\n"
+                + "S2, data sets: DS1\n"
+                + "DS1, parents: DS2\n", renderGraph(g));
+        repository.assertModified(g.e(1), g.e(2));
+        repository.assertModified(g.s(1), g.s(2));
+        repository.assertModified(g.ds(1));
+        repository.assertUnmodified(g);
     }
 
     @Test
-    public void componentDataSetCanBeAssignedToAnotherSample() throws Exception
+    public void sampleAssignmentOfChildDataSetIsNotChangedWhenParentDatasetIsAssignedToAnotherSample()
     {
-        AbstractExternalData component = create(aDataSet().inSample(sourceSample));
-        create(aDataSet().inSample(sourceSample).withComponent(component));
-
-        perform(anUpdateOf(component).toSample(destinationSample));
-
-        assertThat(component, is(inSample(destinationSample)));
+        EntityGraphGenerator g = parseAndCreateGraph("E1, samples: S1, data sets: DS1 DS2\n"
+                + "E2, samples: S2\n"
+                + "S1, data sets: DS1 DS2\n"
+                + "DS1, parents: DS2\n");
+        
+        reassignToSample(g.ds(2), g.s(2));
+        
+        assertEquals("E1, samples: S1, data sets: DS1\n"
+                + "E2, samples: S2, data sets: DS2\n"
+                + "S1, data sets: DS1\n"
+                + "S2, data sets: DS2\n"
+                + "DS1, parents: DS2\n", renderGraph(g));
+        repository.assertModified(g.e(1), g.e(2));
+        repository.assertModified(g.s(1), g.s(2));
+        repository.assertModified(g.ds(2));
+        repository.assertUnmodified(g);
     }
 
     @Test
     public void sampleAssignmentOfContainerDataSetIsNotChangedWhenComponentDataSetIsAssignedToAnotherSample()
-            throws Exception
     {
-        AbstractExternalData component = create(aDataSet().inSample(sourceSample));
-        AbstractExternalData container = create(aDataSet().inSample(sourceSample).withComponent(component));
-
-        perform(anUpdateOf(component).toSample(destinationSample));
-
-        assertThat(container, is(inSample(sourceSample)));
+        EntityGraphGenerator g = parseAndCreateGraph("E1, samples: S1, data sets: DS1 DS2\n"
+                + "E2, samples: S2\n"
+                + "S1, data sets: DS1 DS2\n"
+                + "DS1, components: DS2\n");
+        
+        reassignToSample(g.ds(2), g.s(2));
+        
+        assertEquals("E1, samples: S1, data sets: DS1\n"
+                + "E2, samples: S2, data sets: DS2\n"
+                + "S1, data sets: DS1\n"
+                + "S2, data sets: DS2\n"
+                + "DS1, components: DS2\n", renderGraph(g));
+        repository.assertModified(g.e(1), g.e(2));
+        repository.assertModified(g.s(1), g.s(2));
+        repository.assertModified(g.ds(2));
+        repository.assertUnmodified(g);
     }
 
     @Test
-    public void containerDataSetCanBeAssignedToAnotherSample() throws Exception
+    public void sampleAssignmentOfComponentDataSetIsChangedWhenContainerDataSetIsAssignedToAnotherSample()
     {
-        AbstractExternalData component = create(aDataSet().inSample(sourceSample));
-        AbstractExternalData container = create(aDataSet().inSample(sourceSample).withComponent(component));
-
-        perform(anUpdateOf(container).toSample(destinationSample));
-
-        assertThat(container, is(inSample(destinationSample)));
+        EntityGraphGenerator g = parseAndCreateGraph("E1, samples: S1, data sets: DS1 DS2\n"
+                + "E2, samples: S2\n"
+                + "S1, data sets: DS1 DS2\n"
+                + "DS1, components: DS2\n");
+        
+        reassignToSample(g.ds(1), g.s(2));
+        
+        assertEquals("E1, samples: S1\n"
+                + "E2, samples: S2, data sets: DS1 DS2\n"
+                + "S2, data sets: DS1 DS2\n"
+                + "DS1, components: DS2\n", renderGraph(g));
+        repository.assertModified(g.e(1), g.e(2));
+        repository.assertModified(g.s(1), g.s(2));
+        repository.assertModified(g.ds(1), g.ds(2));
+        repository.assertUnmodified(g);
     }
 
     @Test
-    public void sampleAssignmentOfComponentDataSetIsNotChangedWhenContainerDataSetIsAssignedToAnotherSample()
-            throws Exception
+    public void dataSetCanBeUnassignedFromSample()
     {
-        AbstractExternalData component = create(aDataSet().inSample(sourceSample));
-        AbstractExternalData container = create(aDataSet().inSample(sourceSample).withComponent(component));
-
-        perform(anUpdateOf(container).toSample(destinationSample));
-
-        assertThat(component, is(inSample(sourceSample)));
+        EntityGraphGenerator g = parseAndCreateGraph("E1, samples: S1, data sets: DS1\n"
+                + "S1, data sets: DS1\n");
+        
+        reassignToSample(g.ds(1), null);
+        
+        assertEquals("E1, samples: S1, data sets: DS1\n", renderGraph(g));
+        repository.assertModified(g.s(1));
+        repository.assertModified(g.ds(1));
+        repository.assertUnmodified(g);
     }
 
-    @Test
-    public void dataSetCanBeUnassignedFromSample() throws Exception
+    private void assertDataSetToSampleExceptionMessage(UserFailureException ex, Sample sample, AbstractExternalData dataset)
     {
-        AbstractExternalData data = create(aDataSet().inSample(sourceSample));
-
-        perform(anUpdateOf(data).removingSample());
-
-        assertThat(data, hasNoSample());
-        assertThat(data, is(inExperiment(sourceExperiment)));
+        String postfix = sample.getSpace() == null ? "shared." :
+                "not connected to any experiment and the data set type ("
+                        + dataset.getDataSetType().getCode()
+                        + ") doesn't match one of the following regular expressions:   NO-EXP-.* ,   NE.*  .";
+        assertEquals("The dataset '" + dataset.getCode()
+                + "' cannot be connected to the sample '" + sample.getIdentifier()
+                + "' because the new sample is " + postfix, ex.getMessage());
     }
 
-    private void reassignToExperiment(DataSetNode dataSetNode, ExperimentNode experimentNode)
+    private void reassignToExperiment(DataSetNode dataSetNode, ExperimentNode experimentNodeOrNull)
     {
         AbstractExternalData dataSet = getDataSet(dataSetNode);
-        Experiment experiment = repository.getExperiment(experimentNode);
-        reassignToExperiment(dataSet.getCode(), experiment.getIdentifier());
+        String experimentIdentifierOrNull = null;
+        if (experimentNodeOrNull != null)
+        {
+            Experiment experiment = repository.getExperiment(experimentNodeOrNull);
+            if (experiment == null)
+            {
+                throw new IllegalArgumentException("Unknown experiment " + experimentNodeOrNull.getCode());
+            }
+            experimentIdentifierOrNull = experiment.getIdentifier();
+        }
+        String user = create(aSession().withInstanceRole(RoleCode.ADMIN));
+        reassignToExperiment(dataSet.getCode(), experimentIdentifierOrNull, user);
     }
 
-    private void reassignToSample(DataSetNode dataSetNode, SampleNode sampleNode)
+    private void reassignToSample(DataSetNode dataSetNode, SampleNode sampleNodeOrNull)
     {
         AbstractExternalData dataSet = getDataSet(dataSetNode);
-        Sample sample = repository.getSample(sampleNode);
-        if (sample == null)
+        String permIdOrNull = null;
+        if (sampleNodeOrNull != null)
         {
-            throw new IllegalArgumentException("Unknown sample " + sampleNode.getCode());
+            Sample sample = repository.getSample(sampleNodeOrNull);
+            if (sample == null)
+            {
+                throw new IllegalArgumentException("Unknown sample " + sampleNodeOrNull.getCode());
+            }
+            permIdOrNull = sample.getPermId();
         }
-        reassignToSample(dataSet.getCode(), sample.getPermId());
+        String user = create(aSession().withInstanceRole(RoleCode.ADMIN));
+        reassignToSample(dataSet.getCode(), permIdOrNull, user);
     }
 
     private AbstractExternalData getDataSet(DataSetNode dataSetNode)
@@ -538,22 +646,42 @@ public class AssignDataSetToSampleTest extends BaseTest
         return dataSet;
     }
     
-    protected void reassignToExperiment(String dataSetCode, String experimentIdentifier)
+    /**
+     * Reassign specified data set to specified experiment for the specified user. 
+     * If experiment is not specified unassignment is meant.
+     * Sub class for testing API V3 should override this method.
+     */
+    protected void reassignToExperiment(String dataSetCode, String experimentIdentifierOrNull, String user)
     {
         AbstractExternalData dataSet = etlService.tryGetDataSet(systemSessionToken, dataSetCode);
-        Experiment experiment = etlService.tryGetExperiment(systemSessionToken, 
-                ExperimentIdentifierFactory.parse(experimentIdentifier));
-        String user = create(aSession().withInstanceRole(RoleCode.ADMIN));
-        perform(anUpdateOf(dataSet).toExperiment(experiment).as(user));
+        if (experimentIdentifierOrNull != null)
+        {
+            Experiment experiment = etlService.tryGetExperiment(systemSessionToken, 
+                    ExperimentIdentifierFactory.parse(experimentIdentifierOrNull));
+            perform(anUpdateOf(dataSet).toExperiment(experiment).as(user));
+        } else
+        {
+            perform(anUpdateOf(dataSet).removingExperiment().as(user));
+        }
     }
 
-    protected void reassignToSample(String dataSetCode, String samplePermId)
+    /**
+     * Reassign specified data set to specified sample for the specified user. 
+     * If sample is not specified unassignment is meant.
+     * Sub class for testing API V3 should override this method.
+     */
+    protected void reassignToSample(String dataSetCode, String samplePermIdOrNull, String user)
     {
         AbstractExternalData dataSet = etlService.tryGetDataSet(systemSessionToken, dataSetCode);
-        SampleIdentifier sampleIdentifier = etlService.tryGetSampleIdentifier(systemSessionToken, samplePermId);
-        Sample sample = etlService.tryGetSampleWithExperiment(systemSessionToken, sampleIdentifier);
-        String user = create(aSession().withInstanceRole(RoleCode.ADMIN));
-        perform(anUpdateOf(dataSet).toSample(sample).as(user));
+        if (samplePermIdOrNull != null)
+        {
+            SampleIdentifier sampleIdentifier = etlService.tryGetSampleIdentifier(systemSessionToken, samplePermIdOrNull);
+            Sample sample = etlService.tryGetSampleWithExperiment(systemSessionToken, sampleIdentifier);
+            perform(anUpdateOf(dataSet).toSample(sample).as(user));
+        } else
+        {
+            perform(anUpdateOf(dataSet).removingSample().as(user));
+        }
     }
     
     Space unrelatedAdmin;
@@ -562,7 +690,7 @@ public class AssignDataSetToSampleTest extends BaseTest
 
     Space unrelatedNone;
 
-//    @Test(dataProvider = "rolesAllowedToAssignDataSetToSample", groups = "authorization")
+    @Test(dataProvider = "rolesAllowedToAssignDataSetToSample", groups = "authorization")
     public void assigningDataSetToSampleIsAllowedFor(RoleWithHierarchy sourceSpaceRole,
             RoleWithHierarchy destinationSpaceRole, RoleWithHierarchy instanceRole)
             throws Exception
@@ -575,11 +703,11 @@ public class AssignDataSetToSampleTest extends BaseTest
                         .withSpaceRole(RoleWithHierarchy.SPACE_ADMIN, unrelatedAdmin)
                         .withSpaceRole(RoleWithHierarchy.SPACE_OBSERVER, unrelatedObserver));
 
-        perform(anUpdateOf(dataset).toSample(destinationSample).as(user));
+        reassignToSample(dataset.getCode(), destinationSample.getPermId(), user);
     }
 
-//    @Test(dataProvider = "rolesNotAllowedToAssignDataSetToSample", expectedExceptions =
-//        { AuthorizationFailureException.class }, groups = "authorization")
+    @Test(dataProvider = "rolesNotAllowedToAssignDataSetToSample", expectedExceptions =
+        { AuthorizationFailureException.class }, groups = "authorization")
     public void assigningDataSetToSampleIsNotAllowedFor(RoleWithHierarchy sourceSpaceRole,
             RoleWithHierarchy destinationSpaceRole, RoleWithHierarchy instanceRole)
             throws Exception
@@ -592,7 +720,7 @@ public class AssignDataSetToSampleTest extends BaseTest
                         .withSpaceRole(RoleWithHierarchy.SPACE_ADMIN, unrelatedAdmin)
                         .withSpaceRole(RoleWithHierarchy.SPACE_OBSERVER, unrelatedObserver));
 
-        perform(anUpdateOf(dataset).toSample(destinationSample).as(user));
+        reassignToSample(dataset.getCode(), destinationSample.getPermId(), user);
     }
 
     @BeforeClass(dependsOnMethods = "loginAsSystem")
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/base/BaseTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/base/BaseTest.java
index 570825d19f5..a000f7cf834 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/base/BaseTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/base/BaseTest.java
@@ -538,6 +538,7 @@ public abstract class BaseTest extends AbstractTransactionalTestNGSpringContextT
         {
             StringBuilder builder2 = new StringBuilder();
             render(builder2, "components", repository.getComponentDataSetNodes(dataSetNode));
+            render(builder2, "parents", repository.getParentDataSetNodes(dataSetNode));
             appendNodeTo(builder, dataSetNode, builder2);
         }
         return builder.toString();
@@ -571,20 +572,13 @@ public abstract class BaseTest extends AbstractTransactionalTestNGSpringContextT
         repository = new EntityRepository();
         Space space = create(aSpace());
         Project project = create(aProject().inSpace(space));
-        for (ExperimentNode experimentNode : g.getExperiments().values())
-        {
-            addToRepository(experimentNode, create(anExperiment().inProject(project)));
-        }
-        for (SampleNode sampleNode : g.getSamples().values())
-        {
-            SampleBuilder sample = aSample().inSpace(space);
-            ExperimentNode experimentNode = sampleNode.getExperiment();
-            if (experimentNode != null)
-            {
-                sample.inExperiment(repository.getExperiment(experimentNode));
-            }
-            addToRepository(sampleNode, sample);
-        }
+        createExperiments(project, g);
+        createSamples(space, g);
+        createDataSets(g);
+    }
+
+    private void createDataSets(EntityGraphGenerator g)
+    {
         List<DataSetNode> dataSetNodes = new ArrayList<DataSetNode>(g.getDataSets().values());
         Collections.reverse(dataSetNodes);
         for (DataSetNode dataSetNode : dataSetNodes)
@@ -613,10 +607,44 @@ public abstract class BaseTest extends AbstractTransactionalTestNGSpringContextT
                     dataSet.withComponent(componentDataSet);
                 }
             }
+            List<DataSetNode> parents = dataSetNode.getParents();
+            for (DataSetNode parent : parents)
+            {
+                AbstractExternalData parentDataSet = repository.getDataSet(parent);
+                if (parentDataSet == null)
+                {
+                    throw new IllegalStateException("Data set " + parent.getCode() 
+                            + " is specified as parent of " + dataSetNode.getCode() 
+                            + " but hasn't yet created.");
+                }
+                dataSet.withParent(parentDataSet);
+            }
             addToRepository(dataSetNode, dataSet);
         }
     }
 
+    private void createSamples(Space space, EntityGraphGenerator g)
+    {
+        for (SampleNode sampleNode : g.getSamples().values())
+        {
+            SampleBuilder sample = aSample().inSpace(space);
+            ExperimentNode experimentNode = sampleNode.getExperiment();
+            if (experimentNode != null)
+            {
+                sample.inExperiment(repository.getExperiment(experimentNode));
+            }
+            addToRepository(sampleNode, sample);
+        }
+    }
+
+    private void createExperiments(Project project, EntityGraphGenerator g)
+    {
+        for (ExperimentNode experimentNode : g.getExperiments().values())
+        {
+            addToRepository(experimentNode, create(anExperiment().inProject(project)));
+        }
+    }
+
     private void addToRepository(ExperimentNode experimentNode, Experiment experiment)
     {
         try
@@ -767,6 +795,7 @@ public abstract class BaseTest extends AbstractTransactionalTestNGSpringContextT
         private Map<Long, Set<Long>> experimentDataSetsMap = new HashMap<Long, Set<Long>>();
         private Map<Long, Set<Long>> sampleDataSetsMap = new HashMap<Long, Set<Long>>();
         private Map<Long, Set<Long>> componentDataSetsMap = new HashMap<Long, Set<Long>>();
+        private Map<Long, Set<Long>> parentsDataSetsMap = new HashMap<Long, Set<Long>>();
         
         public String renderNodeToDtoMapping()
         {
@@ -854,6 +883,11 @@ public abstract class BaseTest extends AbstractTransactionalTestNGSpringContextT
                 {
                     addToDataSetsMap(componentDataSetsMap, dataSet, containerDataSet);
                 }
+                Collection<AbstractExternalData> parents = dataSet.getParents();
+                for (AbstractExternalData parentDataSet : parents)
+                {
+                    addToDataSetsMap(parentsDataSetsMap, parentDataSet, dataSet);
+                }
             }
             if (showWhereIAm)
             {
@@ -1017,6 +1051,11 @@ public abstract class BaseTest extends AbstractTransactionalTestNGSpringContextT
             return getDataSetNodes(componentDataSetsMap, dataSetsNodeToDtoMap.get(containerDataSetNode.getId()));
         }
         
+        Set<DataSetNode> getParentDataSetNodes(DataSetNode childDataSetNode)
+        {
+            return getDataSetNodes(parentsDataSetsMap, dataSetsNodeToDtoMap.get(childDataSetNode.getId()));
+        }
+        
         private Set<DataSetNode> getDataSetNodes(Map<Long, Set<Long>> idHolderDataSetsMap, IIdHolder experiment)
         {
             Set<DataSetNode> result = new TreeSet<DataSetNode>();
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/base/builder/DataSetUpdateBuilder.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/base/builder/DataSetUpdateBuilder.java
index 7a8dcb1e589..594788bc804 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/base/builder/DataSetUpdateBuilder.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/base/builder/DataSetUpdateBuilder.java
@@ -72,7 +72,7 @@ public class DataSetUpdateBuilder extends UpdateBuilder<DataSetUpdatesDTO>
 
     public DataSetUpdateBuilder toSample(Sample sample)
     {
-//        toExperiment(sample.getExperiment());
+        toExperiment(sample.getExperiment());
         this.sampleIdentifier = id(sample);
         return this;
     }
@@ -105,12 +105,18 @@ public class DataSetUpdateBuilder extends UpdateBuilder<DataSetUpdatesDTO>
         return this;
     }
 
+    public DataSetUpdateBuilder removingExperiment()
+    {
+        this.experimentIdentifier = null;
+        return this;
+    }
+
     public DataSetUpdateBuilder removingSample()
     {
         this.sampleIdentifier = null;
         return this;
     }
-
+    
     public DataSetUpdateBuilder withContainer(AbstractExternalData dataSet)
     {
         this.containerCode = dataSet.getCode();
-- 
GitLab