// Path: src/main/java/com/danielflower/apprunner/mgmt/AppDescription.java
// public interface AppDescription {
//     String name();
// 
//     String gitUrl();
// 
//     void gitUrl(String url) throws URISyntaxException, GitAPIException;
// 
//     Availability currentAvailability();
// 
//     BuildStatus lastBuildStatus();
// 
//     BuildStatus lastSuccessfulBuild();
// 
//     String latestBuildLog();
// 
//     String latestConsoleLog();
// 
//     ArrayList<String> contributors();
// 
//     File dataDir();
// 
//     void stopApp() throws Exception;
// 
//     void update(AppRunnerFactoryProvider runnerProvider, InvocationOutputHandler outputHandler) throws Exception;
// 
//     void delete();
// }
// 
// Path: src/main/java/com/danielflower/apprunner/web/ProxyMap.java
// public class ProxyMap {
//     public static final Logger log = LoggerFactory.getLogger(ProxyMap.class);
//     private final ConcurrentHashMap<String, URL> mapping = new ConcurrentHashMap<>();
// 
//     public void add(String prefix, URL url) {
//         URL old = mapping.put(prefix, url);
//         if (old == null) {
//             log.info(prefix + " maps to " + url);
//         } else {
//             log.info(prefix + " maps to " + url + " (previously " + old + ")");
//         }
//     }
// 
//     public void remove(String prefix) {
//         URL remove = mapping.remove(prefix);
//         if (remove == null) {
//             log.info("Removed " + prefix + " mapping to " + remove);
//         }
//     }
// 
//     public URL get(String prefix) {
//         return mapping.getOrDefault(prefix, null);
//     }
// }
// 
// Path: src/test/java/scaffolding/MockAppDescription.java
// public class MockAppDescription implements AppDescription {
//     private volatile String gitUrl;
//     private final  String name;
//     public int updateCount = 0;
//     private ArrayList<String> contributors;
// 
//     public MockAppDescription(String name, String gitUrl) {
//         this.gitUrl = gitUrl;
//         this.name = name;
//         this.contributors = new ArrayList<>();
//     }
// 
//     public String name() {
//         return name;
//     }
// 
//     public String gitUrl() {
//         return gitUrl;
//     }
// 
//     @Override
//     public void gitUrl(String url) {
//         this.gitUrl = url;
//     }
// 
//     public Availability currentAvailability() {
//         return Availability.available();
//     }
// 
//     @Override
//     public BuildStatus lastBuildStatus() {
//         return BuildStatus.notStarted(null);
//     }
// 
//     @Override
//     public BuildStatus lastSuccessfulBuild() {
//         return null;
//     }
// 
//     public String latestBuildLog() {
//         return "";
//     }
// 
//     public String latestConsoleLog() {
//         return "";
//     }
// 
//     public ArrayList<String> contributors() {
//         return contributors;
//     }
// 
//     @Override
//     public File dataDir() {
//         throw new NotImplementedException("dataDir");
//     }
// 
//     public void stopApp() {
//     }
// 
//     public void update(AppRunnerFactoryProvider runnerProvider, InvocationOutputHandler outputHandler) throws Exception {
//         ++updateCount;
//     }
// 
//     @Override
//     public void delete() {
// 
//     }
// }
// 
// Path: src/test/java/com/danielflower/apprunner/web/WebServerTest.java
// public static FileSandbox fileSandbox() {
//     File root = new File("target/test-sandboxes/" + UUID.randomUUID());
//     try {
//         FileUtils.forceMkdir(root);
//     } catch (IOException e) {
//         throw new RuntimeException(e);
//     }
//     return new FileSandbox(root);
// }


import com.danielflower.apprunner.mgmt.AppDescription;
import com.danielflower.apprunner.web.ProxyMap;
import org.junit.Before;
import org.junit.Test;
import scaffolding.MockAppDescription;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.stream.Collectors;
import static com.danielflower.apprunner.web.WebServerTest.fileSandbox;
import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
package com.danielflower.apprunner;




public class AppEstateTest {
    private AppEstate estate;

    @Before
    public void populate() throws IOException {
        estate = new AppEstate(new ProxyMap(), fileSandbox(), null);
        estate.add(app("Y app"));
        estate.add(app("z app"));
        estate.add(app("c app"));
        estate.add(app("a app"));
        estate.add(app("B app"));
    }

    @Test
    public void startsAlphabetically() throws Exception {
        List<String> ordered = estate.appsByStartupOrder(null)
            .map(AppDescription::name)
            .collect(Collectors.toList());
        assertThat(ordered, equalTo(asList("a app", "B app", "c app", "Y app", "z app")));
    }

    @Test
    public void startsAlphabeticallyWithOptionalStartupAppFirst() throws Exception {
        List<String> ordered = estate.appsByStartupOrder("c app")
            .map(AppDescription::name)
// Path: src/main/java/com/danielflower/apprunner/mgmt/AppDescription.java
// public interface AppDescription {
//     String name();
// 
//     String gitUrl();
// 
//     void gitUrl(String url) throws URISyntaxException, GitAPIException;
// 
//     Availability currentAvailability();
// 
//     BuildStatus lastBuildStatus();
// 
//     BuildStatus lastSuccessfulBuild();
// 
//     String latestBuildLog();
// 
//     String latestConsoleLog();
// 
//     ArrayList<String> contributors();
// 
//     File dataDir();
// 
//     void stopApp() throws Exception;
// 
//     void update(AppRunnerFactoryProvider runnerProvider, InvocationOutputHandler outputHandler) throws Exception;
// 
//     void delete();
// }
// 
// Path: src/main/java/com/danielflower/apprunner/web/ProxyMap.java
// public class ProxyMap {
//     public static final Logger log = LoggerFactory.getLogger(ProxyMap.class);
//     private final ConcurrentHashMap<String, URL> mapping = new ConcurrentHashMap<>();
// 
//     public void add(String prefix, URL url) {
//         URL old = mapping.put(prefix, url);
//         if (old == null) {
//             log.info(prefix + " maps to " + url);
//         } else {
//             log.info(prefix + " maps to " + url + " (previously " + old + ")");
//         }
//     }
// 
//     public void remove(String prefix) {
//         URL remove = mapping.remove(prefix);
//         if (remove == null) {
//             log.info("Removed " + prefix + " mapping to " + remove);
//         }
//     }
// 
//     public URL get(String prefix) {
//         return mapping.getOrDefault(prefix, null);
//     }
// }
// 
// Path: src/test/java/scaffolding/MockAppDescription.java
// public class MockAppDescription implements AppDescription {
//     private volatile String gitUrl;
//     private final  String name;
//     public int updateCount = 0;
//     private ArrayList<String> contributors;
// 
//     public MockAppDescription(String name, String gitUrl) {
//         this.gitUrl = gitUrl;
//         this.name = name;
//         this.contributors = new ArrayList<>();
//     }
// 
//     public String name() {
//         return name;
//     }
// 
//     public String gitUrl() {
//         return gitUrl;
//     }
// 
//     @Override
//     public void gitUrl(String url) {
//         this.gitUrl = url;
//     }
// 
//     public Availability currentAvailability() {
//         return Availability.available();
//     }
// 
//     @Override
//     public BuildStatus lastBuildStatus() {
//         return BuildStatus.notStarted(null);
//     }
// 
//     @Override
//     public BuildStatus lastSuccessfulBuild() {
//         return null;
//     }
// 
//     public String latestBuildLog() {
//         return "";
//     }
// 
//     public String latestConsoleLog() {
//         return "";
//     }
// 
//     public ArrayList<String> contributors() {
//         return contributors;
//     }
// 
//     @Override
//     public File dataDir() {
//         throw new NotImplementedException("dataDir");
//     }
// 
//     public void stopApp() {
//     }
// 
//     public void update(AppRunnerFactoryProvider runnerProvider, InvocationOutputHandler outputHandler) throws Exception {
//         ++updateCount;
//     }
// 
//     @Override
//     public void delete() {
// 
//     }
// }
// 
// Path: src/test/java/com/danielflower/apprunner/web/WebServerTest.java
// public static FileSandbox fileSandbox() {
//     File root = new File("target/test-sandboxes/" + UUID.randomUUID());
//     try {
//         FileUtils.forceMkdir(root);
//     } catch (IOException e) {
//         throw new RuntimeException(e);
//     }
//     return new FileSandbox(root);
// }


// Path: src/test/java/com/danielflower/apprunner/AppEstateTest.java
import com.danielflower.apprunner.mgmt.AppDescription;
import com.danielflower.apprunner.web.ProxyMap;
import org.junit.Before;
import org.junit.Test;
import scaffolding.MockAppDescription;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.stream.Collectors;
import static com.danielflower.apprunner.web.WebServerTest.fileSandbox;
import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;

package com.danielflower.apprunner;




public class AppEstateTest {
    private AppEstate estate;

    @Before
    public void populate() throws IOException {
        estate = new AppEstate(new ProxyMap(), fileSandbox(), null);
        estate.add(app("Y app"));
        estate.add(app("z app"));
        estate.add(app("c app"));
        estate.add(app("a app"));
        estate.add(app("B app"));
    }

    @Test
    public void startsAlphabetically() throws Exception {
        List<String> ordered = estate.appsByStartupOrder(null)
            .map(AppDescription::name)
            .collect(Collectors.toList());
        assertThat(ordered, equalTo(asList("a app", "B app", "c app", "Y app", "z app")));
    }

    @Test
    public void startsAlphabeticallyWithOptionalStartupAppFirst() throws Exception {
        List<String> ordered = estate.appsByStartupOrder("c app")
            .map(AppDescription::name)
            .collect(Collectors.toList());