code: /*
   * Copyright (c) 2019 the Eclipse Milo Authors
   *
   * This program and the accompanying materials are made
   * available under the terms of the Eclipse Public License 2.0
   * which is available at https://www.eclipse.org/legal/epl-2.0/
   *
   * SPDX-License-Identifier: EPL-2.0
   */
  
  package org.eclipse.milo.opcua.sdk.client.subscriptions;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.concurrent.CompletableFuture;
  import java.util.concurrent.ExecutionException;
  
  import org.eclipse.milo.opcua.sdk.client.subscriptions.BatchModifyMonitoredItems.ModifyMonitoredItemResult;
  import org.eclipse.milo.opcua.stack.core.Identifiers;
  import org.eclipse.milo.opcua.stack.core.UaException;
  import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
  import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
  import org.junit.jupiter.api.Test;
  import org.junit.jupiter.api.TestInstance;
  
  import static org.junit.jupiter.api.Assertions.assertEquals;
  import static org.junit.jupiter.api.Assertions.assertFalse;
  import static org.junit.jupiter.api.Assertions.assertTrue;
  
  
  @TestInstance(TestInstance.Lifecycle.PER_CLASS)
  public class BatchModifyMonitoredItemsTest extends AbstractSubscriptionTest {
  
      @Test
      public void mixedOperationResults() throws UaException, ExecutionException, InterruptedException {
          List<OpcUaMonitoredItem> items = new ArrayList<>();
  
          for (int i = 0; i < 10; i++) {
              OpcUaMonitoredItem monitoredItem;
              if (i % 2 == 0) {
                  monitoredItem = subscription
                      .createDataItem(Identifiers.Server_ServerStatus_CurrentTime)
                      .getMonitoredItem();
              } else {
                  monitoredItem = subscription
                      .createDataItem(new NodeId(99, "DoesNotExist"))
                      .getMonitoredItem();
              }
              items.add(monitoredItem);
          }
  
          BatchModifyMonitoredItems batch = new BatchModifyMonitoredItems(
              client,
              subscription.getSubscription()
          );
  
          List<CompletableFuture<ModifyMonitoredItemResult>> futures = new ArrayList<>();
  
          items.forEach(item -> {
              CompletableFuture<ModifyMonitoredItemResult> future =
                  batch.add(item, b -> b.setSamplingInterval(5000.0));
  
              futures.add(future);
          });
  
          List<ModifyMonitoredItemResult> batchResults = batch.execute();
  
          for (int i = 0; i < 10; i++) {
              ModifyMonitoredItemResult result = batchResults.get(i);
              CompletableFuture<ModifyMonitoredItemResult> future = futures.get(i);
  
              assertTrue(future.isDone());
  
              if (i % 2 == 0) {
                  assertTrue(result.isOperationResultGood());
                  assertTrue(future.get().isOperationResultGood());
                  assertEquals(5000.0, items.get(i).getRevisedSamplingInterval());
              } else {
                  assertFalse(result.isOperationResultGood());
                  assertFalse(future.get().isOperationResultGood());
              }
          }
  
          assertEquals(1, batch.getServiceInvocationCount());
      }
  
      @Test
      public void multipleTimestampsToReturn() throws UaException, InterruptedException {
          ManagedDataItem item1 = subscription.createDataItem(Identifiers.Server_ServerStatus_CurrentTime);
          ManagedDataItem item2 = subscription.createDataItem(Identifiers.Server_ServerStatus_CurrentTime);
          ManagedDataItem item3 = subscription.createDataItem(Identifiers.Server_ServerStatus_CurrentTime);
          ManagedDataItem item4 = subscription.createDataItem(Identifiers.Server_ServerStatus_CurrentTime);
  
          item1.setTimestampsToReturn(TimestampsToReturn.Source);
          item2.setTimestampsToReturn(TimestampsToReturn.Server);
          item3.setTimestampsToReturn(TimestampsToReturn.Both);
          item4.setTimestampsToReturn(TimestampsToReturn.Neither);
  
          BatchModifyMonitoredItems batch = new BatchModifyMonitoredItems(
              client,
              subscription.getSubscription()
          );
  
          batch.add(item1.getMonitoredItem(), b -> b.setTimestamps(TimestampsToReturn.Server));
          batch.add(item2.getMonitoredItem(), b -> b.setTimestamps(TimestampsToReturn.Both));
          batch.add(item3.getMonitoredItem(), b -> b.setTimestamps(TimestampsToReturn.Neither));
          batch.add(item4.getMonitoredItem(), b -> b.setTimestamps(TimestampsToReturn.Source));
  
          List<ModifyMonitoredItemResult> results = batch.execute();
  
          for (ModifyMonitoredItemResult result : results) {
              assertTrue(result.isServiceResultGood());
              assertTrue(result.isOperationResultGood());
          }
  
          assertEquals(TimestampsToReturn.Server, item1.getTimestampsToReturn());
          assertEquals(TimestampsToReturn.Both, item2.getTimestampsToReturn());
          assertEquals(TimestampsToReturn.Neither, item3.getTimestampsToReturn());
          assertEquals(TimestampsToReturn.Source, item4.getTimestampsToReturn());
  
          assertEquals(4, batch.getServiceInvocationCount());
      }
  
      @Test
      public void operationResultCount() throws Exception {
          OpcUaMonitoredItem monitoredItem = subscription
              .createDataItem(Identifiers.Server_ServerStatus_CurrentTime)
              .getMonitoredItem();
  
          BatchModifyMonitoredItems batch = new BatchModifyMonitoredItems(
              client,
              subscription.getSubscription()
          );
  
          batch.add(monitoredItem, b -> b.setDiscardOldest(false));
          batch.add(monitoredItem, b -> b.setSamplingInterval(5000.0));
          batch.add(monitoredItem, b -> b.setTimestamps(TimestampsToReturn.Neither));
  
          // The number of operation results should match the number of add()
          // calls, not the number of *underlying* operation results. In this
          // test case there are 3 operations to the same item, which only
          // results in underlying modify operation but the batch should return
          // an operation result for each.
          assertEquals(3, batch.execute().size());
          assertEquals(1, batch.getServiceInvocationCount());
      }
  
  }
  