package be.iminds.ilabt.jfed.test;

import be.iminds.ilabt.jfed.*;
import be.iminds.ilabt.jfed.log.Logger;
import be.iminds.ilabt.jfed.lowlevel.*;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.AggregateManagerWrapper;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.UserAndSliceApiWrapper;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.impl.AutomaticAggregateManagerWrapper;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.impl.AutomaticUserAndSliceApiWrapper;

import be.iminds.ilabt.jfed.lowlevel.authority.JFedTestbedInfoSource;
import be.iminds.ilabt.jfed.fedmon.webapi.service.json.*;
import be.iminds.ilabt.jfed.lowlevel.connection.JFedConnectionProvider;
import be.iminds.ilabt.jfed.lowlevel.userloginmodel.InvalidLoginException;
import be.iminds.ilabt.jfed.preferences.JFedPreferences;
import be.iminds.ilabt.jfed.util.*;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * JFedTesterBuilder
 */
public class JFedTesterBuilder {
    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(JFedTesterBuilder.class);

    public static final String dummyAuthServerPrivateKeyPem = "-----BEGIN RSA PRIVATE KEY-----\n" +
            "MIIEowIBAAKCAQEAn5LU9Zpc135UBCL+3HXGwwkqI1F0biB8DuR4Ai8rNmWFna0Z\n" +
            "10Fvc3P1BqURplrQDr+R8s6Fc003G0oBAUYTeeVEjRQ+s395qWaM0zLILXKNhdUf\n" +
            "PUGuILHsKIYhopWaE5fSOMj6CnlaTI02DOc8fejibphXvuxEW79EbEXLcWbArShb\n" +
            "Uum05zte5uIm7PJOJPPAGkVFsiXP/ZgRcZ61tWp+hIEXQZnYnW92gET7P8v747pv\n" +
            "4aXaVS39/d5sRvatgEX64RDAeORSIxHswaUx1vSk+dsHaDAeZNjFnj7r7zp78hAY\n" +
            "7w2lAFF/poWTDVnFmMv4JRvJ/mGbpxa22zx3TQIDAQABAoIBAHYCrdGwxeZsO5AP\n" +
            "nXHG/CZy2aHi9HsZNQYCeqoK3idNb0JLqOejMdwtLlEqtGHVmTa/AB2UE+dQfGeH\n" +
            "FDUv8Old35OCHFi89mmMOKtcS+QoandGROMVdsQhMOhLQgauIpNI3SQ3pYsncdtZ\n" +
            "N1bVj8wB9asaqRG+Q1OioOR9vVXwH6FFbf1tsDp/IipZ6Tk3hozT3aFg3SJAz5Ji\n" +
            "UOOrSQtiJZhNfkdKZAvvLqwhvq0ydC7aB4QLM4G0ImnCZ9McG9lNiduQf5HI2Dhj\n" +
            "9xA2ep5WPUpEaiVHiycP1/4rU7B+5ILnAcwjE9NE9qtm4RcVO6tCyoHz1dpYGXrb\n" +
            "HbjW6uECgYEAzbv8J4OV6/GinTwmkTSj2jya4HJbhcJfEpikmXHIYirBANzzKUPd\n" +
            "ZQqxchJZv/3XdYYdMGzF6O69cFm7Uys9l0CTkarxfE3ubgIFCixyCpuivj74pTRa\n" +
            "xoYoNZSoGidq0UCrNNfWnDrQQwUTRIVCld6e9OKzhDTHQ3wO0TSHaekCgYEAxo+k\n" +
            "KMQdi+jgORbRGFzmAOhBUwczuH5mUaA0WcgMY3ftDr3q7ln5+qLXJUVV4rC3hDLO\n" +
            "6Xy7A5TDoz1V6ETKW+0RxTY3H8YSvF2JxjZplwEAstp2Gf/6FQjEBAi/ZAyO01li\n" +
            "NDz3N8+H9K7wYP9a7GPyFq1cDnamdPMblcnW38UCgYEAyz0X3lkpc8pjYH0ZhHzC\n" +
            "GUehoHSYYU0g6pgMkuFKmV+vBpE/TdaTEcw8e3oRW48CmEEC+OGbqX6feivK2GBx\n" +
            "Gchbf52lray3C8nG/MPnbP9PCC3hKCLOQiwp8LSIVD34UftWpn9KrU+UiYCsBha3\n" +
            "LqKb2UNTIBmbd9lIMfd4hnECgYAlZjjNVOMbzyksl5eatyS7VwO218xuG6C6DyrN\n" +
            "Hlj3A0erVypA6sGi67kKVBzxLcfjJo7Ce7Pd4M9Yl9zuesaCugx20NdhLLWqtROW\n" +
            "Ofl5b77p8Sv9ibFY9OW2vM8P0S21sUhF/pWx9WzuMWUlX/OIQur+SnjkYITJ0mCH\n" +
            "vhSy4QKBgCzuWhzSHdAKa5eQpAx0Uq0MHW7cS4Wdcm78dBbUR08vCSjs9ueM3Fkq\n" +
            "1iz7BtX9TduI6dy8u6xf8N5YzaOLrxSg6bDF0QAn838xdq+3ASd/V6JgnUip2O1g\n" +
            "Z+3STnk73/TgEVgEqA726kqbC6V5LcJ8ILlI9rMN8Foazu28bSZT\n" +
            "-----END RSA PRIVATE KEY-----\n";
    public final String dummyAuthServerCertPem = "-----BEGIN CERTIFICATE-----\n" +
            "MIIC5DCCAcygAwIBAgIEbOdraTANBgkqhkiG9w0BAQsFADAQMQ4wDAYDVQQDEwVk\n" +
            "dW1teTAeFw0xNTA2MDExMjM5MDJaFw0yNTA1MzAxMjM5MDJaMBAxDjAMBgNVBAMT\n" +
            "BWR1bW15MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn5LU9Zpc135U\n" +
            "BCL+3HXGwwkqI1F0biB8DuR4Ai8rNmWFna0Z10Fvc3P1BqURplrQDr+R8s6Fc003\n" +
            "G0oBAUYTeeVEjRQ+s395qWaM0zLILXKNhdUfPUGuILHsKIYhopWaE5fSOMj6Cnla\n" +
            "TI02DOc8fejibphXvuxEW79EbEXLcWbArShbUum05zte5uIm7PJOJPPAGkVFsiXP\n" +
            "/ZgRcZ61tWp+hIEXQZnYnW92gET7P8v747pv4aXaVS39/d5sRvatgEX64RDAeORS\n" +
            "IxHswaUx1vSk+dsHaDAeZNjFnj7r7zp78hAY7w2lAFF/poWTDVnFmMv4JRvJ/mGb\n" +
            "pxa22zx3TQIDAQABo0YwRDASBgNVHRMBAf8ECDAGAQH/AgEBMC4GA1UdEQQnMCWG\n" +
            "I3VybjpwdWJsaWNpZDpJRE4rZHVtbXkrYXV0aG9yaXR5K3NhMA0GCSqGSIb3DQEB\n" +
            "CwUAA4IBAQBdAHEr09cXhqgmquOUCW9BUSQosqIDy5CreBXcz5E+ww2jDIxO8wHd\n" +
            "JbWQwdLjVgkr+1V1cr8NZhcm/cGqHqWDF5fin9Z0GoDkPq2J4MJjkdkYe7FJ+vPo\n" +
            "5aE3tY9hTR5DyXUxMOUMSVuyoXTB6k504i+yqt9+3A8R6c1wq5ckf/+Egvi02yj5\n" +
            "u21K2emL1UQrDmtldI4DOr2BMyHvIrllQe6SITdgPIJDbfFuWjZOEQe2iBIEvmPV\n" +
            "sX3DJoVlen6DA1QDJRHalj7fqGhMSVDSSqFRn6es6nH83u2RYTEOZIzE/OeqtDA0\n" +
            "XKP8XUvBCug/wolMOTIbLkDVl+DAQJ7V\n" +
            "-----END CERTIFICATE-----";

    public static final String dummyAuthServerHostname = "dummy";
    public static final String dummyAuthServerUrn = "urn:publicid:IDN+"+dummyAuthServerHostname+"+authority+sa";
    public static final String dummyUserName = "dummy";
    public static final String dummyUserUuid = UUID.randomUUID().toString();
    public static final String dummyUserEmail = dummyUserName + "@" + dummyAuthServerHostname;
    public static final String dummyUserUuidUrn = "urn:uuid:" + dummyUserUuid;
    public static final String dummyUserUrnString = "urn:publicid:IDN+" + dummyAuthServerHostname + "+user+" + dummyUserName;
    public static final GeniUrn dummyUserUrn = GeniUrn.parse(dummyUserUrnString);

    public final SSHKeyHelper dummyAuthKeys;
    public final SSHKeyHelper dummyUserKeys;
    public final X509Certificate dummyAuthServerCert;
    public final String dummyUserPrivateKeyPem;
    public final X509Certificate dummyUserCert;
    public final String dummyUserCertPem;

    private final SfaCredential dummyUserCredential;

    private final String dummySliceName = "ds";
    private final String dummySliceUrn = "urn:publicid:IDN+" + dummyAuthServerHostname + "+slice+" + dummySliceName;
    private final SfaCredential dummySliceCredential;


    private boolean useDummyUserAndSlice = false;

    private boolean needSlice = true;
    private String sliceSubAuthName = null;

    private String userPemFilename = null;
    private GeniUrn forcedUserAuthorityUrn = null;
    private GeniUrn forcedUserUrn = null;
    private GeniUrn authUrn;

    private int fakeTestbedId = -1;
    private int fakeServerId = -1;
    private int fakeServiceId = -1;
    private final List<Testbed> testbedsToRegister = new ArrayList<>();
    private final List<String> jFedAuthoritiesToRegister = new ArrayList<>();

    private final Date in2Hour;

    private static final Random random = new Random(System.currentTimeMillis());

    public JFedTesterBuilder() {
        in2Hour = new Date(System.currentTimeMillis()+(2 * 60 * 60 * 1000L));
        try {
            dummyAuthKeys = new SSHKeyHelper(KeyUtil.pemToRsaPrivateKey(dummyAuthServerPrivateKeyPem, null));

            //we have to use a fixed cert and register that with the tested server, or the tested server might not trust the credentials we generate
//            dummyAuthServerCert = TestCertHelper.makeAuthCert(dummyAuthKeys, dummyAuthServerHostname, dummyAuthServerUrn, 2*365 /*2 years*/);
//            dummyAuthServerCertPem = KeyUtil.x509certificateToPem(dummyAuthServerCert);

            dummyAuthServerCert = KeyUtil.pemToX509Certificate(dummyAuthServerCertPem);

            System.out.println("The dummy authority certificate is: "+dummyAuthServerCertPem);

            //random keys for user
            dummyUserKeys = new SSHKeyHelper();
            dummyUserPrivateKeyPem = new String(KeyUtil.privateKeyToPem(dummyUserKeys.getSshPrivateKey()));
            dummyUserCert = TestCertHelper.makeUserCert(dummyAuthKeys, dummyAuthServerHostname, dummyAuthServerUrn,
                    dummyUserKeys, dummyUserEmail, dummyUserUrnString, dummyUserUuid, dummyUserUuidUrn);
            dummyUserCertPem = KeyUtil.x509certificateToPem(dummyUserCert);

            //TODO: these credentials probably don't work? Needs testing!
            //generate user credential
            dummyUserCredential = SfaCredential.create("privilege",
                    dummyUserUrnString/*owner*/, dummyAuthServerUrn/*target*/,
                    dummyUserCert/*ownerCert*/, dummyAuthServerCert/*targetCert*/,
                    dummyAuthServerCert/*signerCert*/, dummyAuthKeys.getSshPrivateKey()/*signerPrivateKey*/,
                    in2Hour, "*"/*privilegeName*/, false/*canDelegate*/, "Dummy Credential");

            dummySliceCredential = SfaCredential.create("privilege",
                    dummyUserUrnString/*owner*/, dummySliceUrn/*target*/,
                    dummyUserCert/*ownerCert*/, dummyAuthServerCert/*targetCert (not sure if I need to make a "slice cert")*/,
                    dummyAuthServerCert/*signerCert*/, dummyAuthKeys.getSshPrivateKey()/*signerPrivateKey*/,
                    new Date(System.currentTimeMillis()+(3* 3600000L)), "*"/*privilegeName*/, false/*canDelegate*/, "Dummy Credential");
        } catch (Exception e) {
            throw new RuntimeException("Error initialising JFedTesterBuilder", e);
        }
    }

    /**
     * Use a dummy user and dummy credentials.
     *
     * This is useful to test servers that require credentials.
     *
     * Note that you need to "federate" the test server (never a real one!) with this fake user authority.
     * You can do that by using trusting the PEM file in this class.
     * */
    public void setDummyUser() {
        useDummyUserAndSlice = true;
    }
    public void setPemFileUser(String pemFilename) {
        this.userPemFilename = pemFilename;
    }
    public void setNeedSlice(boolean needSlice) {
        this.needSlice = needSlice;
        this.sliceSubAuthName = null;
    }
    public void setNeedSliceFromSubAuthority(String sliceSubAuthName) {
        this.needSlice = true;
        this.sliceSubAuthName = sliceSubAuthName;
    }
    /**
     * @param pemFilename
     * @param forcedUserUrn forces the user's URN to be this URN, even if the user certificate has another user URN.
     * @param forcedUserAuthorityUrn forces the user's authority to be the authority identified by this URN, even if the user certificate or URN point to another authority.
     */
    public void setPemFileUser(String pemFilename, String forcedUserUrn, String forcedUserAuthorityUrn) throws GeniUrn.GeniUrnParseException {
        this.userPemFilename = pemFilename;
        this.forcedUserUrn = new GeniUrn(forcedUserUrn);
        this.forcedUserAuthorityUrn = new GeniUrn(forcedUserAuthorityUrn);
    }



    public Testbed registerAuthority(TestbedBuilder testbedBuilder) throws JFedException {
        Testbed testbed = testbedBuilder.create();
        testbedsToRegister.add(testbed);
        return testbed;
    }

    public void registerAuthorityFromJFedAuthorities(String authUrn) throws JFedException {
        jFedAuthoritiesToRegister.add(authUrn);
    }

    /**
     * Trust all certificates for testing
     * */
    public Testbed registerAuthority(String urnString, String hrn, Location location, Map<ApiInfo.Api, URL> urls, List<Proxy> proxies, Gid gid, String type) throws JFedException {
        TestbedBuilder testbedBuilder = new TestbedBuilder();
        ServerBuilder serverBuilder = new ServerBuilder();
        testbedBuilder.addServerBuilder(serverBuilder);
        if (proxies != null) {
            for (Proxy proxy : proxies) {
                testbedBuilder.addProxyBuilder(new ProxyBuilder(proxy));
            }
        } else
            testbedBuilder.setProxies(null);
        testbedBuilder.setLongName(hrn);
        serverBuilder.setName(hrn);
        testbedBuilder.setId("fake" + (fakeTestbedId--));
        serverBuilder.setId(fakeServerId--);
        testbedBuilder.setDefaultComponentManagerUrn(urnString);
        serverBuilder.setDefaultComponentManagerUrn(urnString);
        serverBuilder.setServerType(type);
        serverBuilder.setLocation(location);
        serverBuilder.setUrnTld(GeniUrn.parse(urnString).getEncodedTopLevelAuthority());
        serverBuilder.setBaseUrl("http://localhost");
        if (gid != null)
            serverBuilder.setCertificateChain(gid.getFullPemCertificate());

        for (Map.Entry<ApiInfo.Api, URL> e: urls.entrySet()) {
            ApiInfo.Api api = e.getKey();
            URL url = e.getValue();

            ServiceBuilder serviceBuilder = new ServiceBuilder();
            serviceBuilder.setId(fakeServiceId--);
            serviceBuilder.setApi(api.getId());
            serviceBuilder.setApiVersion(api.getVersion());
            serviceBuilder.setUrl(url.toExternalForm());
            serverBuilder.setBaseUrl(url.toExternalForm());
            serviceBuilder.setUrn(urnString);
            serverBuilder.addServiceBuilder(serviceBuilder);
        }

        return registerAuthority(testbedBuilder);
    }
    /**
     * Trust all certificates for testing
     * */
    public Testbed registerAuthority(String urnString, int amVersion, String serverUrlString) throws MalformedURLException, JFedException, GeniUrn.GeniUrnParseException {
        TestbedBuilder testbedBuilder = new TestbedBuilder();
        ServerBuilder serverBuilder = new ServerBuilder();
        testbedBuilder.setId("fake"+(fakeTestbedId--));
        serverBuilder.setId(fakeServerId--);
        testbedBuilder.addServerBuilder(serverBuilder);
        testbedBuilder.setLongName(urnString);
        serverBuilder.setName(urnString);
        serverBuilder.setServerType("test-unknown");
        testbedBuilder.setDefaultComponentManagerUrn(urnString);
        serverBuilder.setDefaultComponentManagerUrn(urnString);
        serverBuilder.setUrnTld(GeniUrn.parse(urnString).getEncodedTopLevelAuthority());
        serverBuilder.setBaseUrl(serverUrlString);

        LOG.info("Checking target server certificate info. (In order to trust all untrusted)");
        SSLCertificateDownloader.SSLCertificateJFedInfo certInfo = SSLCertificateDownloader.getCertificateInfo(new URL(serverUrlString));
        if (certInfo != null && !certInfo.isTrusted()) {
            LOG.info("Server not trusted. Will try to trust it.");
            if (certInfo.getSubjectMatchesHostname() == Boolean.FALSE) {
                LOG.info("   Allowing host name alias \"" + certInfo.getSubject()+"\"");
                serverBuilder.setAllowedCertificateAlias(certInfo.getSubject());
            }
            serverBuilder.setCertificateChain(KeyUtil.x509certificateToPem(certInfo.getCert()));
        }


        ServiceBuilder serviceBuilder = new ServiceBuilder();
        serviceBuilder.setId(fakeServiceId--);
        serviceBuilder.setApi(ApiInfo.ApiName.GENI_AM.getId());
        serviceBuilder.setApiVersion(amVersion+"");
        serviceBuilder.setUrl(serverUrlString);
        serviceBuilder.setUrn(urnString);
        serverBuilder.addServiceBuilder(serviceBuilder);


        Testbed testbed = registerAuthority(testbedBuilder);
        this.authUrn = testbed.getDefaultComponentManagerAsGeniUrn();
        return testbed;
    }
    public void useAuthority(String urn) throws GeniUrn.GeniUrnParseException {
        this.authUrn = new GeniUrn(urn);
    }


    public JFedTest build() throws JFedException, IOException {
//        System.out.println("Initial authority list has size: "+testbedInfoSource.getServers().size());
//        if (!testbedInfoSource.getServers().isEmpty())
//            System.out.println("   first auth: " + testbedInfoSource.getServers().get(0).getDefaultComponentManagerUrn());

        List<Testbed> neededTestbeds = new ArrayList<>();

        neededTestbeds.addAll(testbedsToRegister);

        if (!jFedAuthoritiesToRegister.isEmpty()) {
            Injector tmpInjector = Guice.createInjector(new BasicTestbedInfoModule(), new JFedWebApiClientModule(), new PreLoginCoreModule(), new CorePreferencesModule());
            TestbedInfoSource jFedTestbedInfoSource = tmpInjector.getInstance(JFedTestbedInfoSource.class).get();
            for (String jFedAuthUrnString : jFedAuthoritiesToRegister) {
                GeniUrn jFedAuthUrn = null;
                try {
                    jFedAuthUrn = new GeniUrn(jFedAuthUrnString);
                    Testbed existingTestbed = null;
                    for (Testbed t : neededTestbeds)
                        if (Objects.equals(t.getDefaultComponentManagerUrn(), jFedAuthUrnString))
                            existingTestbed = t;

                    if (existingTestbed == null) {
                        Testbed jFedTestbed = jFedTestbedInfoSource.getTestbedByUrn(
                                jFedAuthUrn,
                                TestbedInfoSource.SubAuthMatchAllowed.ALLOW_ONLY_EXACT_SUBAUTHORITY,
                                TestbedInfoSource.SubAuthMatchPreference.PREFER_EXACT_SUBAUTHORITY,
                                false/*ignoreUrnTypeAndName*/);
                        if (jFedTestbed == null)
                            throw new RuntimeException("Could not find Authority in jFed authorities: " + jFedAuthUrn);
                        else
                            neededTestbeds.add(jFedTestbed);
                    } else {
                        LOG.debug("Not adding "+jFedAuthUrn+" because it is already known");
                    }
                } catch (GeniUrn.GeniUrnParseException e) {
                    LOG.debug("Not adding " + jFedAuthUrn + " because it is an invalid URN.");
                }
            }
        }

        Injector injector;

        Module userModule;
        if (useDummyUserAndSlice) {
            TestbedBuilder testbedBuilder = new TestbedBuilder();
            ServerBuilder serverBuilder = new ServerBuilder();
            testbedBuilder.setId("fake"+(fakeTestbedId--));
            serverBuilder.setId(fakeServerId--);
            testbedBuilder.addServerBuilder(serverBuilder);
            testbedBuilder.setLongName("Dummy User Auth");
            serverBuilder.setName("Dummy User Auth");
            testbedBuilder.setDefaultComponentManagerUrn(dummyAuthServerUrn);
            serverBuilder.setDefaultComponentManagerUrn(dummyAuthServerUrn);
            Testbed userAuthTestbed = registerAuthority(testbedBuilder);   //NOTE: this adds to neededTestbeds which is why we need to create the injector only later
            Server userAuthServer = userAuthTestbed.getServers().get(0);
            serverBuilder.setUrnTld(GeniUrn.parse(dummyAuthServerUrn).getEncodedTopLevelAuthority());
            serverBuilder.setBaseUrl("http://localhost");

            List<X509Certificate> userCertChain = new ArrayList<>();
//            userCertChain.add(dummyAuthServerCert);
            userCertChain.add(dummyUserCert);
            SimpleGeniUser user = new SimpleGeniUser(userAuthServer, dummyUserUrn, userCertChain, dummyUserKeys.getSshPrivateKey(), null, null);
            userModule = new DirectUserModule(user);

            System.out.println("Dummy user PEM file:\n" + KeyUtil.x509certificateChainToPem(userCertChain)+"\n"+new String(KeyUtil.privateKeyToAnyPem(dummyUserKeys.getSshPrivateKey()))+"\n");

            injector = Guice.createInjector(new ManualTestbedInfoSourceModule(neededTestbeds), new PreLoginCoreModule(), new CorePreferencesModule());
        } else {
            injector = Guice.createInjector(new ManualTestbedInfoSourceModule(neededTestbeds), new PreLoginCoreModule(), new CorePreferencesModule());
            TestbedInfoSource testbedInfoSource = injector.getInstance(TestbedInfoSource.class);

            File userPemFile = new File(userPemFilename);
            String pemContent = IOUtils.fileToString(userPemFile);
            if (forcedUserAuthorityUrn != null) {
                Server userAuthServer = testbedInfoSource.getByUrnExact(forcedUserAuthorityUrn);
                if (userAuthServer == null)
                    throw new RuntimeException("Could not create user. forcedUserAuthorityUrn set, but no matching authority found: \""+forcedUserAuthorityUrn+"\"");
                SimpleGeniUser user;
                try {
                    user = new SimpleGeniUser(userAuthServer, forcedUserUrn, pemContent,
                            null,
                            userPemFile, userPemFile);
                } catch (InvalidLoginException e) {
                    throw new RuntimeException(e);
                }
                userModule = new DirectUserModule(user);
            } else {
                userModule = new KeyCertFileUserModule(pemContent, null, userPemFile, userPemFile);
            }
        }

        TestbedInfoSource testbedInfoSource = injector.getInstance(TestbedInfoSource.class);
        assert neededTestbeds.size() <= testbedInfoSource.getTestbeds().size() : neededTestbeds.size()+" > "+testbedInfoSource.getTestbeds().size();
        assert neededTestbeds.size() <= testbedInfoSource.getServers().size() : neededTestbeds.size()+" > "+testbedInfoSource.getServers().size();

        injector = injector.createChildInjector(userModule, new PostLoginCoreModule());

        //should be the same
        TestbedInfoSource newTestbedInfoSource = injector.getInstance(TestbedInfoSource.class);
        assert newTestbedInfoSource.getServers().size() == testbedInfoSource.getServers().size();
        assert newTestbedInfoSource == testbedInfoSource;

        Logger logger = injector.getInstance(Logger.class);
        GeniUser user = injector.getInstance(GeniUser.class);

        UserAndSliceApiWrapper sa;

        List<AnyCredential> userCreds;
        List<AnyCredential> sliceCreds;
        GeniUrn sliceUrn;
        if (!useDummyUserAndSlice) {
            sa = injector.getInstance(AutomaticUserAndSliceApiWrapper.AutomaticUserAndSliceApiWrapperFactory.class).create();
            userCreds = sa.getUserCredentials(logger, user.getUserUrn());

            if (needSlice) {
                String sliceName = "t";
                String uniqueTextHelper = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
                for (int i = 0; i < 4; i++) {
                    int pos = random.nextInt(uniqueTextHelper.length());
                    sliceName += uniqueTextHelper.charAt(pos);
                }
                Date expire = in2Hour;
                UserAndSliceApiWrapper.SliceInfo sliceInfo = sa.createSlice(logger, sliceName, expire, sliceSubAuthName);
                sliceCreds = sliceInfo.getCredentials();
                sliceUrn = sliceInfo.getUrn();
            } else {
                sliceCreds = null;
                sliceUrn = null;
            }
        } else {
            sliceUrn = GeniUrn.parse(dummySliceUrn);
            userCreds = new ArrayList<>();
            userCreds.add(dummyUserCredential);
            sliceCreds = new ArrayList<>();
            sliceCreds.add(dummySliceCredential);
            sa = null;
        }

        assert neededTestbeds.size() <= testbedInfoSource.getTestbeds().size() : neededTestbeds.size()+" > "+testbedInfoSource.getTestbeds().size();
        assert neededTestbeds.size() <= testbedInfoSource.getServers().size() : neededTestbeds.size()+" > "+testbedInfoSource.getServers().size();

        Server amServer = testbedInfoSource.getByUrnExact(authUrn);
        if (amServer == null) {
            System.out.println("Debug: known auth count: "+testbedInfoSource.getServers().size());
            for (Server s : testbedInfoSource.getServers()) {
                System.out.println("Debug: known auth: "+s.getDefaultComponentManagerUrn());
            }
            System.out.flush();
            System.err.flush();
            throw new RuntimeException("Authority \"" + authUrn + "\" not found among "+testbedInfoSource.getServers().size()+" known servers. neededTestbeds.size()="+neededTestbeds.size());
        }

        AggregateManagerWrapper am = injector.getInstance(
                AutomaticAggregateManagerWrapper.AutomaticAggregateManagerWrapperFactory.class)
                .create(amServer);
        JFedConnectionProvider connectionProvider = injector.getInstance(JFedConnectionProvider.class);
        JFedPreferences prefs = injector.getInstance(JFedPreferences.class);
        JFedTrustStore trustStore = new JFedTrustStore(injector.getInstance(JFedTrustStore.class));

        assert am != null;

        if (amServer.hasCertificateChain()) {
            trustStore.addTrustedPemCertificateIfNotAdded(amServer.getCertificateChain());
            if (amServer.hasAllowedCertificateAlias())
                trustStore.addAllowedServerCertificateHostnameAlias(amServer.getAllowedCertificateAlias());
        }

        JFedTest res = new JFedTest(logger, prefs, user, connectionProvider, trustStore, am, sa, userCreds, sliceCreds, sliceUrn);
        assert res.am != null;
        return res;
    }
}
