@Override
  public Image apply(VAppTemplate from) {
    checkNotNull(from, "VAppTemplate");
    Envelope ovf = templateToEnvelope.apply(from);

    ImageBuilder builder = new ImageBuilder();
    builder.ids(from.getHref().toASCIIString());
    builder.uri(from.getHref());
    builder.name(from.getName());
    if (from.getVDC() != null) {
      builder.location(findLocationForResource.apply(from.getVDC()));
    } else {
      // otherwise, it could be in a public catalog, which is not assigned to a VDC
    }
    builder.description(from.getDescription() != null ? from.getDescription() : from.getName());
    builder.operatingSystem(CIMOperatingSystem.toComputeOs(ovf));
    builder.status(toPortableImageStatus.get(from.getStatus()));
    return builder.build();
  }
  @Override
  public Image apply(DiskImage from) {
    checkNotNull(from, "disk image");

    ImageBuilder builder = new ImageBuilder();

    builder.ids(from.getId());
    builder.name(from.getName());
    builder.description(from.getDescription());
    builder.location(Iterables.getOnlyElement(regionSupplier.get()));
    // in fgcp, if the image is listed it is available
    builder.status(Status.AVAILABLE);

    OperatingSystem os = diskImageToOperatingSystem.apply(from);
    builder.operatingSystem(os);
    String user = os.getFamily() == OsFamily.WINDOWS ? "Administrator" : "root";
    builder.defaultCredentials(LoginCredentials.builder().identity(user).noPassword().build());

    return builder.build();
  }
 @Override
 public Set<? extends Image> get() {
   final Set<Image> images = Sets.newHashSet();
   logger.debug(">> providing images");
   for (org.jclouds.rimuhosting.miro.domain.Image from : sync.getImageList()) {
     ImageBuilder builder = new ImageBuilder();
     builder.ids(from.getId() + "");
     builder.name(from.getDescription());
     builder.description(from.getDescription());
     builder.operatingSystem(parseOs(from));
     builder.status(Status.AVAILABLE);
     images.add(builder.build());
   }
   logger.debug("<< images(%d)", images.size());
   return images;
 }
/** @author Adrian Cole */
@Test(groups = "unit", singleThreaded = true, testName = "TemplateBuilderImplTest")
public class TemplateBuilderImplTest {

  public void testMultiMax() {
    Iterable<String> values = ImmutableList.of("1", "2", "2", "3", "3");
    assertEquals(
        TemplateBuilderImpl.multiMax(Ordering.natural(), values), ImmutableList.of("3", "3"));
  }

  public void testMultiMax1() {
    Iterable<String> values = ImmutableList.of("1", "2", "2", "3");
    assertEquals(TemplateBuilderImpl.multiMax(Ordering.natural(), values), ImmutableList.of("3"));
  }

  public void testMultiMax2() {
    // check with max buried in the middle
    Iterable<String> values = ImmutableList.of("1", "3", "2", "2");
    assertEquals(TemplateBuilderImpl.multiMax(Ordering.natural(), values), ImmutableList.of("3"));
  }

  public void testMultiMaxNull() {
    // we rely on checking nulls in some Orderings, so assert it also does what we expect
    // (unfortunately can't use ImmutableList here as that doesn't allow nulls)
    Iterable<String> values = Arrays.asList("1", "3", null, "2", "2");
    assertEquals(
        TemplateBuilderImpl.multiMax(Ordering.natural().nullsLast(), values),
        Arrays.asList((Object) null));
  }

  public void testMultiMaxNulls() {
    Iterable<String> values = Arrays.asList("1", "3", null, "2", "2", null);
    assertEquals(
        TemplateBuilderImpl.multiMax(Ordering.natural().nullsLast(), values),
        Arrays.asList((Object) null, null));
  }

  protected Location provider =
      new LocationBuilder()
          .scope(LocationScope.PROVIDER)
          .id("aws-ec2")
          .description("aws-ec2")
          .build();

  protected Location region =
      new LocationBuilder()
          .scope(LocationScope.REGION)
          .id("us-east-1")
          .description("us-east-1")
          .parent(provider)
          .build();

  protected Location region2 =
      new LocationBuilder()
          .scope(LocationScope.REGION)
          .id("us-east-2")
          .description("us-east-2")
          .parent(provider)
          .build();

  protected OperatingSystem os =
      OperatingSystem.builder()
          .name("osName")
          .version("osVersion")
          .description("osDescription")
          .arch("X86_32")
          .build();

  protected String getProviderFormatId(String uniqueLabel) {
    return uniqueLabel;
  }

  protected Image image =
      new ImageBuilder()
          .id(getProviderFormatId("imageId"))
          .providerId("imageId")
          .name("imageName")
          .description("imageDescription")
          .version("imageVersion")
          .operatingSystem(os)
          .status(Image.Status.AVAILABLE)
          .location(region)
          .build();

  protected Image image64bit =
      ImageBuilder.fromImage(image)
          .id(getProviderFormatId("image64bId"))
          .providerId("image64bId")
          .operatingSystem(os.toBuilder().arch("X86_64").build())
          .build();

  protected Image imageArchNull =
      ImageBuilder.fromImage(image)
          .id(getProviderFormatId("imageArchNullId"))
          .providerId("imageArchNullId")
          .operatingSystem(os.toBuilder().arch(null).build())
          .build();

  protected Image imageNameAlt =
      ImageBuilder.fromImage(image)
          .id(getProviderFormatId("imageNameAltId"))
          .providerId("imageNameAltId")
          .name("alternateImageName")
          .build();

  @SuppressWarnings("unchecked")
  public void testLocationPredicateWhenComputeMetadataIsNotLocationBound() {

    Hardware hardware = new HardwareBuilder().id("hardwareId").build();

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of(hardware));
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);

    replay(defaultTemplate, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);
    assert template.locationPredicate.apply(hardware);

    verify(defaultTemplate, optionsProvider, templateBuilderProvider);
  }

  /**
   * Resolves images using a default TemplateBuilder, optionally applying a customizer to that
   * TemplateBuilder where the customizer may e.g. apply an imageChooser
   */
  @SuppressWarnings("unchecked")
  protected void doTestResolveImagesWithTemplateBuilderCustomizer(
      Supplier<Set<? extends Image>> inputImages,
      Function<TemplateBuilderImpl, TemplateBuilderImpl> templateBuilderPerTestCustomizer,
      Image expectedBest) {

    Hardware hardware = new HardwareBuilder().id("hardwareId").build();

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of(hardware));
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);

    replay(defaultTemplate, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null,
            locations,
            inputImages,
            hardwares,
            region,
            optionsProvider,
            templateBuilderProvider);
    template = templateBuilderPerTestCustomizer.apply(template);

    assertEquals(template.resolveImage(hardware, inputImages.get()), expectedBest);

    verify(defaultTemplate, optionsProvider, templateBuilderProvider);
  }

  protected void doTestResolveImages(
      Supplier<Set<? extends Image>> inputImages, Image expectedBest) {
    doTestResolveImagesWithTemplateBuilderCustomizer(
        inputImages, Functions.<TemplateBuilderImpl>identity(), expectedBest);
  }

  public void testResolveImagesSimple() {
    doTestResolveImages(
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image, image64bit)),
        image64bit);
  }

  public void testResolveImagesPrefersNull() {
    // preferring null has been the default behaviour; not sure if this is ideal
    // (would make more sense to prefer nonNull) but don't change behaviour by default
    doTestResolveImages(
        Suppliers.<Set<? extends Image>>ofInstance(
            ImmutableSet.<Image>of(image, imageArchNull, image64bit)),
        imageArchNull);
  }

  public void testResolveImagesCustomSorterPreferringNonNull() {
    // preferring null has been the default behaviour;
    // see comments in TemplateBuilderImpl.DEFAULT_IMAGE_ORDERING

    final Ordering<Image> sorterPreferringNonNullArch =
        new Ordering<Image>() {
          @Override
          public int compare(Image left, Image right) {
            return ComparisonChain.start()
                .compare(
                    left.getOperatingSystem().getArch(),
                    right.getOperatingSystem().getArch(),
                    Ordering.<String>natural().nullsFirst())
                .compare(left, right, TemplateBuilderImpl.DEFAULT_IMAGE_ORDERING)
                .result();
          }
        };
    assertTrue(
        TemplateBuilderImpl.DEFAULT_IMAGE_ORDERING.compare(image64bit, imageArchNull) < 0,
        "wrong default image ordering");
    assertTrue(
        sorterPreferringNonNullArch.compare(image64bit, imageArchNull) > 0,
        "wrong custom image ordering");

    Function<TemplateBuilderImpl, TemplateBuilderImpl> tbCustomiser =
        new Function<TemplateBuilderImpl, TemplateBuilderImpl>() {
          @Override
          public TemplateBuilderImpl apply(TemplateBuilderImpl input) {
            return input.imageChooser(input.imageChooserFromOrdering(sorterPreferringNonNullArch));
          }
        };

    doTestResolveImagesWithTemplateBuilderCustomizer(
        Suppliers.<Set<? extends Image>>ofInstance(
            ImmutableSet.<Image>of(image, imageArchNull, image64bit)),
        tbCustomiser,
        image64bit);
  }

  public void testResolveImagesPrefersImageBecauseNameIsLastAlphabetically() {
    // preferring that which comes later alphabetically is the default behaviour;
    // see comments in TemplateBuilderImpl.DEFAULT_IMAGE_ORDERING
    doTestResolveImages(
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(imageNameAlt, image)),
        image);
  }

  public void testResolveImagesCustomSorterPreferringAltImage() {
    Function<TemplateBuilderImpl, TemplateBuilderImpl> tbSortWithAlternate =
        new Function<TemplateBuilderImpl, TemplateBuilderImpl>() {
          @Override
          public TemplateBuilderImpl apply(TemplateBuilderImpl input) {
            return input.imageChooser(
                input.imageChooserFromOrdering(
                    new Ordering<Image>() {
                      private int score(Image img) {
                        if (img.getName().contains("alternate")) return 10;
                        return 0;
                      }

                      @Override
                      public int compare(Image left, Image right) {
                        return score(left) - score(right);
                      }
                    }));
          }
        };
    doTestResolveImagesWithTemplateBuilderCustomizer(
        Suppliers.<Set<? extends Image>>ofInstance(
            ImmutableSet.<Image>of(imageNameAlt, image, imageArchNull, image64bit)),
        tbSortWithAlternate,
        imageNameAlt);
  }

  public void testResolveImagesCustomChooserPreferringAltImage() {
    Function<TemplateBuilderImpl, TemplateBuilderImpl> tbChooseAlternate =
        new Function<TemplateBuilderImpl, TemplateBuilderImpl>() {
          @Override
          public TemplateBuilderImpl apply(TemplateBuilderImpl input) {
            return input.imageChooser(
                new Function<Iterable<? extends Image>, Image>() {
                  @Override
                  public Image apply(Iterable<? extends Image> input) {
                    return Iterables.find(
                        input,
                        new Predicate<Image>() {
                          @Override
                          public boolean apply(Image input) {
                            return input.getName() != null && input.getName().contains("alternate");
                          }
                        });
                  }
                });
          }
        };
    doTestResolveImagesWithTemplateBuilderCustomizer(
        Suppliers.<Set<? extends Image>>ofInstance(
            ImmutableSet.<Image>of(imageNameAlt, image, imageArchNull, image64bit)),
        tbChooseAlternate,
        imageNameAlt);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testArchWins() {

    Hardware hardware = new HardwareBuilder().id("hardwareId").build();

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image, image64bit));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of(hardware));
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);

    expect(optionsProvider.get()).andReturn(new TemplateOptions());

    replay(defaultTemplate, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    assertEquals(template.smallest().osArchMatches("X86_32").build().getImage(), image);

    verify(defaultTemplate, optionsProvider, templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testHardwareWithImageIdPredicateOnlyAcceptsImage() {

    Hardware hardware =
        new HardwareBuilder()
            .id("hardwareId")
            .supportsImage(ImagePredicates.idEquals(getProviderFormatId("imageId")))
            .build();

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of(hardware));
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);

    expect(optionsProvider.get()).andReturn(new TemplateOptions());

    replay(defaultTemplate);
    replay(optionsProvider);
    replay(templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    template.imageId(getProviderFormatId("imageId")).build();

    verify(defaultTemplate);
    verify(optionsProvider);
    verify(templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testHardwareWithImageIdPredicateOnlyAcceptsImageWhenLocationNull() {

    Hardware hardware =
        new HardwareBuilder()
            .id("hardwareId")
            .supportsImage(ImagePredicates.idEquals(getProviderFormatId("imageId")))
            .build();

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of(hardware));
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);

    expect(optionsProvider.get()).andReturn(new TemplateOptions());

    replay(defaultTemplate, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    template.imageId(getProviderFormatId("imageId")).build();

    verify(defaultTemplate, optionsProvider, templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testHardwareWithImageIdPredicateOnlyDoesntImage() {

    Hardware hardware =
        new HardwareBuilder()
            .id("hardwareId")
            .supportsImage(ImagePredicates.idEquals("differentImageId"))
            .build();

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of(hardware));
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);

    expect(optionsProvider.get()).andReturn(new TemplateOptions());

    replay(defaultTemplate, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            image, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);
    try {
      template.imageId(getProviderFormatId("imageId")).build();
      fail("Expected NoSuchElementException");
    } catch (NoSuchElementException e) {
      // make sure message is succinct
      assertEquals(
          e.getMessage(),
          "no hardware profiles support images matching params: idEquals(differentImageId)");
      verify(defaultTemplate, optionsProvider, templateBuilderProvider);
    }
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testOptionsUsesDefaultTemplateBuilder() {
    TemplateOptions options = provideTemplateOptions();
    TemplateOptions from = provideTemplateOptions();

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of());
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of());
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of());
    Location defaultLocation = createMock(Location.class);
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);

    expect(templateBuilderProvider.get()).andReturn(defaultTemplate);
    expect(defaultTemplate.options(from)).andReturn(defaultTemplate);
    expect(defaultTemplate.build()).andReturn(null);
    expect(optionsProvider.get()).andReturn(from).atLeastOnce();

    replay(defaultTemplate);
    replay(defaultLocation);
    replay(optionsProvider);
    replay(templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null,
            locations,
            images,
            hardwares,
            defaultLocation,
            optionsProvider,
            templateBuilderProvider);

    template.options(options).build();

    verify(defaultTemplate);
    verify(defaultLocation);
    verify(optionsProvider);
    verify(templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testNothingUsesDefaultTemplateBuilder() {

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of());
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of());
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of());

    Location defaultLocation = createMock(Location.class);
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class);

    expect(templateBuilderProvider.get()).andReturn(defaultTemplate);
    expect(defaultTemplate.build()).andReturn(null);

    replay(defaultTemplate);
    replay(defaultLocation);
    replay(optionsProvider);
    replay(templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null,
            locations,
            images,
            hardwares,
            defaultLocation,
            optionsProvider,
            templateBuilderProvider);

    template.build();

    verify(defaultTemplate);
    verify(defaultLocation);
    verify(optionsProvider);
    verify(templateBuilderProvider);
  }

  protected TemplateBuilderImpl createTemplateBuilder(
      Image knownImage,
      Supplier<Set<? extends Location>> locations,
      Supplier<Set<? extends Image>> images,
      Supplier<Set<? extends Hardware>> hardwares,
      Location defaultLocation,
      Provider<TemplateOptions> optionsProvider,
      Provider<TemplateBuilder> templateBuilderProvider) {
    TemplateBuilderImpl template =
        new TemplateBuilderImpl(
            locations,
            images,
            hardwares,
            Suppliers.ofInstance(defaultLocation),
            optionsProvider,
            templateBuilderProvider);
    return template;
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testSuppliedImageLocationWiderThanDefault() {
    TemplateOptions from = provideTemplateOptions();

    Hardware hardware =
        new HardwareBuilder()
            .id("hardwareId")
            .supportsImage(ImagePredicates.idEquals(image.getId()))
            .build();

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(provider, region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of(hardware));

    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateOptions defaultOptions = createMock(TemplateOptions.class);
    expect(optionsProvider.get()).andReturn(from).atLeastOnce();

    replay(defaultOptions, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    assertEquals(
        template.imageId(image.getId()).locationId(provider.getId()).build().getLocation(), region);

    verify(defaultOptions, optionsProvider, templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testSuppliedLocationWithNoOptions() {
    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of());
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of());
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateOptions defaultOptions = createMock(TemplateOptions.class);

    replay(defaultOptions);
    replay(optionsProvider);
    replay(templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    try {
      template.imageId("foo").locationId("location").build();
      fail("Expected NoSuchElementException");
    } catch (NoSuchElementException e) {

    }

    verify(defaultOptions);
    verify(optionsProvider);
    verify(templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testSuppliedLocationAndOptions() {
    TemplateOptions from = provideTemplateOptions();

    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of());
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of());
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);

    expect(optionsProvider.get()).andReturn(from).atLeastOnce();

    replay(optionsProvider);
    replay(templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    try {
      template.imageId("foo").options(provideTemplateOptions()).locationId("location").build();
      fail("Expected NoSuchElementException");
    } catch (NoSuchElementException e) {

    }

    verify(optionsProvider);
    verify(templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  public void testImagesMustBePresentWhenQuerying() {
    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of());
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(
            ImmutableSet.<Hardware>of(createMock(Hardware.class)));
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateOptions defaultOptions = createMock(TemplateOptions.class);

    expect(optionsProvider.get()).andReturn(defaultOptions);

    replay(defaultOptions, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    try {
      template.os64Bit(true).build();
      fail("Expected IllegalStateException");
    } catch (IllegalStateException e) {
      assertEquals(e.getMessage(), "no images present!");
    }

    verify(defaultOptions, optionsProvider, templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  public void testHardwareProfilesMustBePresentWhenQuerying() {
    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of());
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateOptions defaultOptions = createMock(TemplateOptions.class);

    expect(optionsProvider.get()).andReturn(defaultOptions);

    replay(defaultOptions, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    try {
      template.os64Bit(true).build();
      fail("Expected IllegalStateException");
    } catch (IllegalStateException e) {
      assertEquals(e.getMessage(), "no hardware profiles present!");
    }

    verify(defaultOptions, optionsProvider, templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testDefaultLocationWithNoOptionsNoSuchElement() {
    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(
            ImmutableSet.<Hardware>of(createMock(Hardware.class)));
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateOptions defaultOptions = createMock(TemplateOptions.class);

    expect(optionsProvider.get()).andReturn(defaultOptions);

    replay(defaultOptions, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    try {
      template.imageId("region/imageId2").build();
      fail("Expected NoSuchElementException");
    } catch (NoSuchElementException e) {
      // make sure big data is not in the exception message
      assertEquals(e.getMessage(), "imageId(region/imageId2) not found");
    }

    verify(defaultOptions, optionsProvider, templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testDefaultLocationWithUnmatchedPredicateExceptionMessageAndLocationNotCalled() {
    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(
            ImmutableSet.<Hardware>of(createMock(Hardware.class)));
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
    TemplateOptions defaultOptions = createMock(TemplateOptions.class);

    expect(optionsProvider.get()).andReturn(defaultOptions);

    replay(defaultOptions, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null, locations, images, hardwares, region, optionsProvider, templateBuilderProvider);

    try {
      template.imageDescriptionMatches("notDescription").build();
      fail("Expected NoSuchElementException");
    } catch (NoSuchElementException e) {
      // make sure big data is not in the exception message
      assertEquals(
          e.getMessage(),
          "no image matched predicate: And(nullEqualToIsParentOrIsGrandparentOfCurrentLocation(),imageDescription(notDescription))");
    }

    verify(defaultOptions, optionsProvider, templateBuilderProvider);
  }

  protected TemplateOptions provideTemplateOptions() {
    return new TemplateOptions();
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testDefaultLocationWithOptions() {
    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of());
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of(image));
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(
            ImmutableSet.<Hardware>of(createMock(Hardware.class)));
    Location defaultLocation = createMock(Location.class);
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    TemplateOptions from = provideTemplateOptions();
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);

    expect(optionsProvider.get()).andReturn(from);

    replay(defaultLocation, optionsProvider, templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null,
            locations,
            images,
            hardwares,
            defaultLocation,
            optionsProvider,
            templateBuilderProvider);

    try {
      template.imageId("region/ami").options(provideTemplateOptions()).build();
      fail("Expected NoSuchElementException");
    } catch (NoSuchElementException e) {

    }

    verify(defaultLocation, optionsProvider, templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testImageIdNullsEverythingElse() {
    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of());
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of());
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of());
    Location defaultLocation = createMock(Location.class);
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);

    replay(defaultLocation);
    replay(optionsProvider);
    replay(templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null,
            locations,
            images,
            hardwares,
            defaultLocation,
            optionsProvider,
            templateBuilderProvider);

    template.imageDescriptionMatches("imageDescriptionMatches");
    template.imageNameMatches("imageNameMatches");
    template.imageVersionMatches("imageVersionMatches");
    template.osDescriptionMatches("osDescriptionMatches");
    template.osFamily(OsFamily.CENTOS);
    template.osArchMatches("osArchMatches");

    assertEquals(template.osArch, "osArchMatches");
    assertEquals(template.imageDescription, "imageDescriptionMatches");
    assertEquals(template.imageName, "imageNameMatches");
    assertEquals(template.imageVersion, "imageVersionMatches");
    assertEquals(template.osDescription, "osDescriptionMatches");
    assertEquals(template.osFamily, OsFamily.CENTOS);
    assertEquals(template.imageId, null);

    template.imageId("myid");
    assertEquals(template.osArch, null);
    assertEquals(template.imageDescription, null);
    assertEquals(template.imageName, null);
    assertEquals(template.imageVersion, null);
    assertEquals(template.osDescription, null);
    assertEquals(template.osFamily, null);
    assertEquals(template.imageId, "myid");

    verify(defaultLocation);
    verify(optionsProvider);
    verify(templateBuilderProvider);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testHardwareIdNullsHypervisor() {
    Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of());
    Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(ImmutableSet.<Image>of());
    Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(ImmutableSet.<Hardware>of());
    Location defaultLocation = createMock(Location.class);
    Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
    Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);

    replay(defaultLocation);
    replay(optionsProvider);
    replay(templateBuilderProvider);

    TemplateBuilderImpl template =
        createTemplateBuilder(
            null,
            locations,
            images,
            hardwares,
            defaultLocation,
            optionsProvider,
            templateBuilderProvider);

    template.hypervisorMatches("OpenVZ");

    assertEquals(template.hardwareId, null);
    assertEquals(template.hypervisor, "OpenVZ");

    template.hardwareId("myid");
    assertEquals(template.hardwareId, "myid");
    assertEquals(template.hypervisor, null);

    verify(defaultLocation);
    verify(optionsProvider);
    verify(templateBuilderProvider);
  }

  @Test
  public void testMatchesHardwareWithIdPredicate() {

    final Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    final Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(
            ImmutableSet.<Image>of(
                new ImageBuilder()
                    .ids("Ubuntu 11.04 x64")
                    .name("Ubuntu 11.04 x64")
                    .description("Ubuntu 11.04 x64")
                    .location(region)
                    .status(Status.AVAILABLE)
                    .operatingSystem(
                        OperatingSystem.builder()
                            .name("Ubuntu 11.04 x64")
                            .description("Ubuntu 11.04 x64")
                            .is64Bit(true)
                            .version("11.04")
                            .family(OsFamily.UBUNTU)
                            .build())
                    .build(),
                new ImageBuilder()
                    .ids("Ubuntu 11.04 64-bit")
                    .name("Ubuntu 11.04 64-bit")
                    .description("Ubuntu 11.04 64-bit")
                    .location(region)
                    .status(Status.AVAILABLE)
                    .operatingSystem(
                        OperatingSystem.builder()
                            .name("Ubuntu 11.04 64-bit")
                            .description("Ubuntu 11.04 64-bit")
                            .is64Bit(true)
                            .version("11.04")
                            .family(OsFamily.UBUNTU)
                            .build())
                    .build()));

    final Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(
            ImmutableSet.<Hardware>of(
                new HardwareBuilder()
                    .ids(
                        String.format(
                            "datacenter(%s)platform(%s)cpuCores(%d)memorySizeMB(%d)diskSizeGB(%d)",
                            "Falkenberg", "Xen", 1, 512, 5))
                    .ram(512)
                    .processors(ImmutableList.of(new Processor(1, 1.0)))
                    .volumes(ImmutableList.<Volume>of(new VolumeImpl((float) 5, true, true)))
                    .hypervisor("Xen")
                    .location(region)
                    .supportsImage(ImagePredicates.idIn(ImmutableSet.of("Ubuntu 11.04 x64")))
                    .build(),
                new HardwareBuilder()
                    .ids(
                        String.format(
                            "datacenter(%s)platform(%s)cpuCores(%d)memorySizeMB(%d)diskSizeGB(%d)",
                            "Falkenberg", "OpenVZ", 1, 512, 5))
                    .ram(512)
                    .processors(ImmutableList.of(new Processor(1, 1.0)))
                    .volumes(ImmutableList.<Volume>of(new VolumeImpl((float) 5, true, true)))
                    .hypervisor("OpenVZ")
                    .location(region)
                    .supportsImage(ImagePredicates.idIn(ImmutableSet.of("Ubuntu 11.04 64-bit")))
                    .build()));

    final Provider<TemplateOptions> optionsProvider =
        new Provider<TemplateOptions>() {

          @Override
          public TemplateOptions get() {
            return new TemplateOptions();
          }
        };
    Provider<TemplateBuilder> templateBuilderProvider =
        new Provider<TemplateBuilder>() {

          @Override
          public TemplateBuilder get() {
            return createTemplateBuilder(
                null, locations, images, hardwares, region, optionsProvider, this);
          }
        };

    TemplateBuilder templateBuilder =
        templateBuilderProvider
            .get()
            .minRam(512)
            .osFamily(OsFamily.UBUNTU)
            .hypervisorMatches("OpenVZ")
            .osVersionMatches("1[10].[10][04]")
            .os64Bit(true);

    assertEquals(
        templateBuilder.toString(),
        "{minRam=512, minRam=512, osFamily=ubuntu, osVersion=1[10].[10][04], os64Bit=true, hypervisor=OpenVZ}");

    Template template = templateBuilder.build();
    assertEquals(template.getHardware().getHypervisor(), "OpenVZ");
    assertEquals(template.getImage().getId(), "Ubuntu 11.04 64-bit");
  }

  @Test
  public void testImageLocationNonDefault() {

    final Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    final Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(
            ImmutableSet.<Image>of(
                new ImageBuilder()
                    .id("us-east-2/ami-ffff")
                    .providerId("ami-ffff")
                    .name("Ubuntu 11.04 x64")
                    .description("Ubuntu 11.04 x64")
                    .location(region2)
                    .status(Status.AVAILABLE)
                    .operatingSystem(
                        OperatingSystem.builder()
                            .name("Ubuntu 11.04 x64")
                            .description("Ubuntu 11.04 x64")
                            .is64Bit(true)
                            .version("11.04")
                            .family(OsFamily.UBUNTU)
                            .build())
                    .build()));

    final Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(
            ImmutableSet.<Hardware>of(
                new HardwareBuilder()
                    .ids("m1.small")
                    .ram(512)
                    .processors(ImmutableList.of(new Processor(1, 1.0)))
                    .volumes(ImmutableList.<Volume>of(new VolumeImpl((float) 5, true, true)))
                    .build()));

    final Provider<TemplateOptions> optionsProvider =
        new Provider<TemplateOptions>() {

          @Override
          public TemplateOptions get() {
            return new TemplateOptions();
          }
        };
    Provider<TemplateBuilder> templateBuilderProvider =
        new Provider<TemplateBuilder>() {

          @Override
          public TemplateBuilder get() {
            return createTemplateBuilder(
                null, locations, images, hardwares, region, optionsProvider, this);
          }
        };

    TemplateBuilder templateBuilder =
        templateBuilderProvider.get().hardwareId("m1.small").imageId("us-east-2/ami-ffff");

    assertEquals(templateBuilder.toString(), "{imageId=us-east-2/ami-ffff, hardwareId=m1.small}");

    Template template = templateBuilder.build();
    assertEquals(template.getLocation().getId(), "us-east-2");
  }

  @Test
  public void testFromSpecWithLoginUser() {

    final Supplier<Set<? extends Location>> locations =
        Suppliers.<Set<? extends Location>>ofInstance(ImmutableSet.<Location>of(region));
    final Supplier<Set<? extends Image>> images =
        Suppliers.<Set<? extends Image>>ofInstance(
            ImmutableSet.<Image>of(
                new ImageBuilder()
                    .id("us-east-2/ami-ffff")
                    .providerId("ami-ffff")
                    .name("Ubuntu 11.04 x64")
                    .description("Ubuntu 11.04 x64")
                    .location(region2)
                    .status(Status.AVAILABLE)
                    .operatingSystem(
                        OperatingSystem.builder()
                            .name("Ubuntu 11.04 x64")
                            .description("Ubuntu 11.04 x64")
                            .is64Bit(true)
                            .version("11.04")
                            .family(OsFamily.UBUNTU)
                            .build())
                    .build()));

    final Supplier<Set<? extends Hardware>> hardwares =
        Suppliers.<Set<? extends Hardware>>ofInstance(
            ImmutableSet.<Hardware>of(
                new HardwareBuilder()
                    .ids("m1.small")
                    .ram(512)
                    .processors(ImmutableList.of(new Processor(1, 1.0)))
                    .volumes(ImmutableList.<Volume>of(new VolumeImpl((float) 5, true, true)))
                    .build()));

    final Provider<TemplateOptions> optionsProvider =
        new Provider<TemplateOptions>() {

          @Override
          public TemplateOptions get() {
            return new TemplateOptions();
          }
        };
    Provider<TemplateBuilder> templateBuilderProvider =
        new Provider<TemplateBuilder>() {

          @Override
          public TemplateBuilder get() {
            return createTemplateBuilder(
                null, locations, images, hardwares, region, optionsProvider, this);
          }
        };

    TemplateBuilder templateBuilder =
        templateBuilderProvider
            .get()
            .from(
                "hardwareId=m1.small,imageId=us-east-2/ami-ffff,loginUser=user:Password01,authenticateSudo=true");

    assertEquals(templateBuilder.toString(), "{imageId=us-east-2/ami-ffff, hardwareId=m1.small}");

    Template template = templateBuilder.build();
    assertEquals(template.getLocation().getId(), "us-east-2");
    assertEquals(template.getOptions().getLoginUser(), "user");
    assertEquals(template.getOptions().getLoginPassword(), "Password01");
    assertEquals(template.getOptions().getLoginPrivateKey(), null);
    assertEquals(template.getOptions().shouldAuthenticateSudo(), Boolean.TRUE);
  }
}