@Test
@Transactional
public void copyTest_WithManyToManyRelationships() {

    final String originalViewName = "My Original View";
    final String partitions = "1,2,4";
    final String topic = "MyTopic";
    final String expectedCopyName = "My Copied View";
    final Cluster cluster = clusterTestTools.createCluster("Test Cluster");
    final MessageFormat keyMessageFormat = messageFormatTestTools.createMessageFormat("Key Message Format");
    final MessageFormat valueMessageFormat = messageFormatTestTools.createMessageFormat("Value Message Format");
    final Filter filterA = filterTestTools.createFilter("Filter A");
    final Filter filterB = filterTestTools.createFilter("Filter B");
    final Filter filterC = filterTestTools.createFilter("Filter C");
    final Filter filterD = filterTestTools.createFilter("Filter D");
    // Create source view
    final View sourceView = viewTestTools.createView(originalViewName, cluster, keyMessageFormat);
    sourceView.setKeyMessageFormat(keyMessageFormat);
    sourceView.setValueMessageFormat(valueMessageFormat);
    sourceView.setTopic(topic);
    sourceView.setPartitions(partitions);
    viewRepository.save(sourceView);
    final ViewToFilterEnforced enforcedFilterA = addEnforcedFilterToView(sourceView, filterA, 1L);
    final ViewToFilterEnforced enforcedFilterB = addEnforcedFilterToView(sourceView, filterB, 2L);
    final ViewToFilterOptional enforcedFilterC = addOptionalFilterToView(sourceView, filterC,3L);
    final ViewToFilterOptional enforcedFilterD = addOptionalFilterToView(sourceView, filterD,4L);
    viewRepository.save(sourceView);
    // Attempt to copy
    final ViewCopyManager copyManager = new ViewCopyManager(viewRepository);
    View copiedView = copyManager.copy(sourceView.getId(),expectedCopyName);
    assertNotNull("Should be non-null", copiedView);
    assertNotNull("Should have an id", copiedView.getId());
    assertNotEquals("Should have a new id", copiedView.getId(), sourceView.getId());
    // Re-pull entity from database?
    copiedView = viewRepository.findById(copiedView.getId()).get();
    // Validate properties
    assertNotNull("Should have an id", copiedView.getId());
    assertEquals("Has new name", expectedCopyName, copiedView.getName());
    assertEquals("Has topic", topic, copiedView.getTopic());
    assertEquals("Has partitions", partitions, copiedView.getPartitions());
    assertEquals("Has cluster", cluster.getId(), copiedView.getCluster().getId());
    assertEquals("Has key format", keyMessageFormat.getId(), copiedView.getKeyMessageFormat().getId());
    assertEquals("Has value format", valueMessageFormat.getId(), copiedView.getValueMessageFormat().getId());
    // Validate enforced filters
    assertEquals("Should have 2 enforced filters", 2, copiedView.getEnforcedFilters().size());
    for (final ViewToFilterEnforced copiedFilter: copiedView.getEnforcedFilters()) {
        assertNotNull(copiedFilter.getId());
        assertNotEquals("Should have a new id", enforcedFilterA.getId(), copiedFilter.getId());
        assertNotEquals("Should have a new id", enforcedFilterB.getId(), copiedFilter.getId());
        assertNotEquals("Should have a new id", enforcedFilterC.getId(), copiedFilter.getId());
        assertNotEquals("Should have a new id", enforcedFilterD.getId(), copiedFilter.getId());
        final String expectedFilterName;
        final String expectedParameterOptions;
        if (copiedFilter.getSortOrder().equals(1L)) {
            expectedFilterName = "Filter A";
            expectedParameterOptions = "my parameters 1";
        } else if (copiedFilter.getSortOrder().equals(2L)) {
            expectedFilterName = "Filter B";
            expectedParameterOptions = "my parameters 2";
        } else {
            throw new RuntimeException("Invalid sort order found? " + copiedFilter.getSortOrder());
        }
        assertEquals(expectedParameterOptions, copiedFilter.getOptionParameters());
        assertEquals(expectedFilterName, copiedFilter.getFilter().getName());
    }
    assertEquals("Should have 2 optional filters", 2, copiedView.getOptionalFilters().size());
    for (final ViewToFilterOptional copiedFilter: copiedView.getOptionalFilters()) {
        assertNotNull(copiedFilter.getId());
        assertNotEquals("Should have a new id", enforcedFilterA.getId(), copiedFilter.getId());
        assertNotEquals("Should have a new id", enforcedFilterB.getId(), copiedFilter.getId());
        assertNotEquals("Should have a new id", enforcedFilterC.getId(), copiedFilter.getId());
        assertNotEquals("Should have a new id", enforcedFilterD.getId(), copiedFilter.getId());
        final String expectedFilterName;
        if (copiedFilter.getSortOrder().equals(3L)) {
            expectedFilterName = "Filter C";
        } else if (copiedFilter.getSortOrder().equals(4L)) {
            expectedFilterName = "Filter D";
        } else {
            throw new RuntimeException("Invalid sort order found? " + copiedFilter.getSortOrder());
        }
        assertEquals(expectedFilterName, copiedFilter.getFilter().getName());
    }
}