private Volume.State waitForVolumeState(
     final IVolumeService volumeService,
     final ProviderTarget target,
     final String volumeId,
     final int seconds,
     final Volume.State... expectedStates)
     throws Exception {
   int tries = seconds;
   while (tries-- > 0) {
     Volume.State volumeState = volumeService.getVolumeState(volumeId, target);
     if (volumeState == Volume.State.ERROR) {
       throw new Exception("Volume state ERROR");
     }
     for (Volume.State expectedFinalState : expectedStates) {
       if (volumeState == expectedFinalState) {
         return volumeState;
       }
     }
     Thread.sleep(1000);
   }
   throw new Exception("Timeout waiting for Volume state transition");
 }
  @Test
  public void computeAndVolumeServiceTest() throws Exception {
    ProviderTarget target =
        new ProviderTarget().account(this.cloudProviderAccount).location(this.location);
    IComputeService computeService = this.connector.getComputeService();
    IVolumeService volumeService = this.connector.getVolumeService();
    INetworkService networkService = this.connector.getNetworkService();
    IImageService imageService = this.connector.getImageService();

    // get public network
    Network publicNetwork = null;
    Network privateNetwork = null;
    for (Network net : networkService.getNetworks(target)) {
      Assert.assertNotNull(net.getName());
      Assert.assertNotNull(net.getProviderAssignedId());
      Assert.assertNotNull(net.getState());
      Assert.assertNotNull(net.getNetworkType());
      if (net.getNetworkType() == Network.Type.PUBLIC) {
        publicNetwork = net;
      } else {
        privateNetwork = net;
      }
    }

    Assert.assertTrue("no network", publicNetwork != null || privateNetwork != null);

    // get MachineConfigs

    MachineConfiguration selectedMachineConfig = null;
    List<MachineConfiguration> machineConfigs = computeService.getMachineConfigs(target);
    for (MachineConfiguration machineConfig : machineConfigs) {
      Assert.assertNotNull(machineConfig.getName());
      Assert.assertTrue(machineConfig.getCpu() > 0);
      Assert.assertTrue(machineConfig.getMemory() > 0);
      Assert.assertNotNull(machineConfig.getDisks());
      Assert.assertTrue(!machineConfig.getDisks().isEmpty());
      Assert.assertNotNull(machineConfig.getProviderMappings());
      Assert.assertTrue(machineConfig.getProviderMappings().size() == 1);
      ProviderMapping mapping = machineConfig.getProviderMappings().get(0);
      Assert.assertNotNull(mapping.getProviderAssignedId());
      if (machineConfig.getName().equals(this.machineConfigName)) {
        selectedMachineConfig = machineConfig;
      }
    }

    Assert.assertNotNull(
        "cannot find machine config " + this.machineConfigName, selectedMachineConfig);

    // get images

    List<MachineImage> images = imageService.getMachineImages(false, null, target);
    for (MachineImage image : images) {
      Assert.assertNotNull(image.getName());
      Assert.assertTrue(image.getProviderMappings().size() == 1);
      ProviderMapping mapping = image.getProviderMappings().get(0);
      Assert.assertNotNull(mapping.getProviderAssignedId());
    }

    String imageId = images.get(0).getProviderMappings().get(0).getProviderAssignedId();

    MachineCreate machineCreate = new MachineCreate();
    MachineTemplate machineTemplate = new MachineTemplate();
    machineTemplate.setMachineConfig(selectedMachineConfig);

    MachineImage machineImage = new MachineImage();
    ProviderMapping providerMapping = new ProviderMapping();
    providerMapping.setProviderAssignedId(imageId);
    providerMapping.setProviderAccount(this.cloudProviderAccount);
    providerMapping.setProviderLocation(this.location);
    machineImage.setProviderMappings(Collections.singletonList(providerMapping));
    machineTemplate.setMachineImage(machineImage);

    List<MachineTemplateNetworkInterface> nics = new ArrayList<MachineTemplateNetworkInterface>();
    MachineTemplateNetworkInterface nic = new MachineTemplateNetworkInterface();
    nic.setNetwork(publicNetwork != null ? publicNetwork : privateNetwork);
    nics.add(nic);
    machineTemplate.setNetworkInterfaces(nics);
    if (this.key != null) {
      Credentials credentials = new Credentials();
      credentials.setPublicKey(this.key);
      machineTemplate.setCredential(credentials);
    }
    machineTemplate.setUserData("color=blue\nip=1.2.3.4\n");
    machineCreate.setMachineTemplate(machineTemplate);
    machineCreate.setName("test");

    System.out.println("Creating machine...");
    Machine machine = computeService.createMachine(machineCreate, target);
    String machineId = machine.getProviderAssignedId();
    this.waitForMachineState(
        computeService,
        target,
        machine.getProviderAssignedId(),
        CloudProviderConnectorTest.ASYNC_OPERATION_WAIT_TIME_IN_SECONDS,
        Machine.State.STARTED,
        Machine.State.STOPPED);

    machine = computeService.getMachine(machine.getProviderAssignedId(), target);
    System.out.println(
        "Machine id=" + machine.getProviderAssignedId() + " state=" + machine.getState());
    for (MachineNetworkInterface netInterface : machine.getNetworkInterfaces()) {
      System.out.print("\t Network " + netInterface.getNetworkType() + " addresses=");
      if (netInterface.getAddresses() != null) {
        for (MachineNetworkInterfaceAddress addr : netInterface.getAddresses()) {
          Address address = addr.getAddress();
          if (address != null) {
            System.out.print(address.getIp() + " ");
          }
        }
      }
      System.out.println();
    }
    if (this.testStopMachine) {
      if (machine.getState() == Machine.State.STOPPED) {
        System.out.println("Starting machine " + machineId);
        computeService.startMachine(machineId, target);
        this.waitForMachineState(
            computeService,
            target,
            machine.getProviderAssignedId(),
            CloudProviderConnectorTest.ASYNC_OPERATION_WAIT_TIME_IN_SECONDS,
            Machine.State.STARTED);
      } else {
        System.out.println("Stopping machine " + machineId);
        computeService.stopMachine(machineId, false, target);
        this.waitForMachineState(
            computeService,
            target,
            machine.getProviderAssignedId(),
            CloudProviderConnectorTest.ASYNC_OPERATION_WAIT_TIME_IN_SECONDS,
            Machine.State.STOPPED);
        System.out.println("Starting machine " + machineId);
        computeService.startMachine(machineId, target);
        this.waitForMachineState(
            computeService,
            target,
            machine.getProviderAssignedId(),
            CloudProviderConnectorTest.ASYNC_OPERATION_WAIT_TIME_IN_SECONDS,
            Machine.State.STARTED);
      }
    }

    if (this.testVolumeAttach) {
      VolumeCreate volumeCreate = new VolumeCreate();
      VolumeTemplate volumeTemplate = new VolumeTemplate();
      VolumeConfiguration volumeConfig = new VolumeConfiguration();
      volumeConfig.setCapacity(this.volumeConfigSizeGB * 1000 * 1000);
      volumeTemplate.setVolumeConfig(volumeConfig);
      volumeCreate.setVolumeTemplate(volumeTemplate);
      volumeCreate.setName("test");
      volumeCreate.setDescription("a test volume");

      System.out.println("Creating Volume size=" + this.volumeConfigSizeGB + "GB");
      Volume volume = volumeService.createVolume(volumeCreate, target);
      String volumeId = volume.getProviderAssignedId();
      this.waitForVolumeState(
          volumeService,
          target,
          volumeId,
          CloudProviderConnectorTest.ASYNC_OPERATION_WAIT_TIME_IN_SECONDS,
          Volume.State.AVAILABLE);
      volume = volumeService.getVolume(volumeId, target);
      System.out.println(
          "Volume id=" + volume.getProviderAssignedId() + " size=" + volume.getCapacity() + " KB");

      MachineVolume machineVolume = new MachineVolume();
      machineVolume.setVolume(volume);
      machineVolume.setInitialLocation(this.volumeDevice);
      System.out.println(
          "Attaching volume " + volume.getProviderAssignedId() + " to machine " + machineId);
      computeService.addVolumeToMachine(machineId, machineVolume, target);

      int seconds = CloudProviderConnectorTest.ASYNC_OPERATION_WAIT_TIME_IN_SECONDS;
      while (seconds-- > 0) {
        machine = computeService.getMachine(machineId, target);
        if (machine.getVolumes().get(0).getState() != MachineVolume.State.ATTACHING) {
          break;
        }
        try {
          Thread.sleep(1000);
        } catch (InterruptedException ex) {
        }
      }
      Assert.assertEquals(MachineVolume.State.ATTACHED, machine.getVolumes().get(0).getState());

      machineVolume = machine.getVolumes().get(0);

      System.out.println(
          "Detaching volume " + volume.getProviderAssignedId() + " from machine " + machineId);
      computeService.removeVolumeFromMachine(machineId, machineVolume, target);
      seconds = CloudProviderConnectorTest.ASYNC_OPERATION_WAIT_TIME_IN_SECONDS;
      while (seconds-- > 0) {
        machine = computeService.getMachine(machineId, target);
        if (machine.getVolumes().isEmpty()) {
          break;
        }
        try {
          Thread.sleep(1000);
        } catch (InterruptedException ex) {
        }
      }
      Assert.assertTrue(machine.getVolumes().isEmpty());

      System.out.println("Deleting volume " + volumeId);
      volumeService.deleteVolume(volumeId, target);
      try {
        this.waitForVolumeState(
            volumeService,
            target,
            volumeId,
            CloudProviderConnectorTest.ASYNC_OPERATION_WAIT_TIME_IN_SECONDS,
            Volume.State.DELETED);
      } catch (ConnectorException ex) {
        // OK
      }
      try {
        volume = volumeService.getVolume(volumeId, target);
        Assert.fail("Volume still exists after deletion");
      } catch (ConnectorException ex) {
        // OK
      }
    }

    System.out.println("Deleting machine " + machineId);
    computeService.deleteMachine(machineId, target);
    try {
      this.waitForMachineState(
          computeService,
          target,
          machine.getProviderAssignedId(),
          CloudProviderConnectorTest.ASYNC_OPERATION_WAIT_TIME_IN_SECONDS,
          Machine.State.DELETED);
    } catch (ConnectorException ex) {
      // OK
    }
  }