diff --git a/bubble-server/src/main/java/bubble/ApiConstants.java b/bubble-server/src/main/java/bubble/ApiConstants.java index 4bbb63f5..bc33f25e 100644 --- a/bubble-server/src/main/java/bubble/ApiConstants.java +++ b/bubble-server/src/main/java/bubble/ApiConstants.java @@ -122,7 +122,6 @@ public class ApiConstants { public static final String DOMAINS_ENDPOINT = "/domains"; public static final String PLANS_ENDPOINT = "/plans"; public static final String FOOTPRINTS_ENDPOINT = "/footprints"; - public static final String BACKUPS_ENDPOINT = "/backups"; public static final String EP_CLEAN_BACKUPS = "/clean"; public static final String PAYMENT_METHODS_ENDPOINT = "/paymentMethods"; diff --git a/bubble-server/src/main/java/bubble/model/cloud/BubbleBackup.java b/bubble-server/src/main/java/bubble/model/cloud/BubbleBackup.java index 3e185fb9..e9534f67 100644 --- a/bubble-server/src/main/java/bubble/model/cloud/BubbleBackup.java +++ b/bubble-server/src/main/java/bubble/model/cloud/BubbleBackup.java @@ -20,7 +20,7 @@ import javax.persistence.*; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; -import static bubble.ApiConstants.BACKUPS_ENDPOINT; +import static bubble.ApiConstants.EP_BACKUPS; import static bubble.ApiConstants.ERROR_MAXLEN; import static bubble.service.backup.BackupService.BR_STATE_LOCK_TIMEOUT; import static org.cobbzilla.util.daemon.ZillaRuntime.empty; @@ -29,7 +29,7 @@ import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENCRYPTED_STRING; import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENC_PAD; @ECType(root=true, name="backup") @ECTypeCreate(method="DISABLED") -@ECTypeURIs(baseURI=BACKUPS_ENDPOINT, listFields={"network", "label", "path"}) +@ECTypeURIs(baseURI=EP_BACKUPS, listFields={"network", "label", "path"}) @Entity @NoArgsConstructor @Accessors(chain=true) @ECIndexes({ @ECIndex(unique=true, of={"network", "path"}) }) public class BubbleBackup extends IdentifiableBase implements HasAccount { diff --git a/bubble-server/src/test/java/bubble/test/live/BackupRestoreTest.java b/bubble-server/src/test/java/bubble/test/live/BackupRestoreTest.java index 5f66029a..c0b19300 100644 --- a/bubble-server/src/test/java/bubble/test/live/BackupRestoreTest.java +++ b/bubble-server/src/test/java/bubble/test/live/BackupRestoreTest.java @@ -8,6 +8,7 @@ import org.junit.Test; import static org.cobbzilla.util.daemon.ZillaRuntime.die; import static org.cobbzilla.util.daemon.ZillaRuntime.empty; +import static org.cobbzilla.util.http.URIUtil.hostToDomain; public class BackupRestoreTest extends LiveTestBase { @@ -15,10 +16,14 @@ public class BackupRestoreTest extends LiveTestBase { final String fqdn = System.getenv("BUBBLE_BACKUP_RESTORE_SAGE"); return empty(fqdn) ? die("getTestSageFqdn: BUBBLE_BACKUP_RESTORE_SAGE env var not defined") : fqdn; } + // If not default, remember to set `TEST_SAGE_ROOT_PASS` properly also. + @Override protected boolean shouldStopSage() { return false; } @Override public boolean backupsEnabled() { return true; } + @Override public String getDefaultDomain() { return hostToDomain(getTestSageFqdn()); } + @Test public void testBackupAndRestore () throws Exception { modelTest("live/backup_and_restore"); } } diff --git a/bubble-server/src/test/java/bubble/test/live/LiveTestBase.java b/bubble-server/src/test/java/bubble/test/live/LiveTestBase.java index 9e0a84de..cc0b1bfc 100644 --- a/bubble-server/src/test/java/bubble/test/live/LiveTestBase.java +++ b/bubble-server/src/test/java/bubble/test/live/LiveTestBase.java @@ -11,8 +11,10 @@ import org.junit.After; import org.junit.AfterClass; import org.junit.Before; +import java.util.AbstractMap; import java.util.concurrent.atomic.AtomicReference; +import static org.cobbzilla.util.daemon.ZillaRuntime.empty; import static org.junit.Assert.fail; @Slf4j @@ -21,27 +23,34 @@ public class LiveTestBase extends NetworkTestBase { @Override protected boolean useMocks() { return false; } protected String getTestSageFqdn() { return System.getenv("TEST_SAGE_FQDN"); } + protected String getTestSageRootPass() { + final var envRootPass = System.getenv("TEST_SAGE_ROOT_PASS"); + return (!empty(envRootPass)) ? envRootPass : ROOT_PASSWORD; + } protected boolean shouldStopSage() { return true; } - private static final AtomicReference sageFqdn = new AtomicReference<>(); + private static final AtomicReference> sageFqdnAndRootPass = + new AtomicReference<>(); private static final AtomicReference testInstance = new AtomicReference<>(); @Before public void startSage () throws Exception { - synchronized (sageFqdn) { - if (sageFqdn.get() == null) { - final String envSage = getTestSageFqdn(); + synchronized (sageFqdnAndRootPass) { + if (sageFqdnAndRootPass.get() == null) { + final var envSage = getTestSageFqdn(); + final var rootPass = getTestSageRootPass(); if (envSage != null) { - sageFqdn.set(envSage); + sageFqdnAndRootPass.set(new AbstractMap.SimpleEntry<>(envSage, rootPass)); } else { modelTest("live/fork_sage"); - final NewNodeNotification newNetwork = (NewNodeNotification) getApiRunner().getContext().get("newNetwork"); + final var newNetwork = (NewNodeNotification) getApiRunner().getContext().get("newNetwork"); if (newNetwork == null) fail("newNetwork not found in context after fork"); if (newNetwork.getFqdn() == null) fail("newNetwork.fqdn was null after fork"); - sageFqdn.set(newNetwork.getFqdn()); + sageFqdnAndRootPass.set(new AbstractMap.SimpleEntry<>(newNetwork.getFqdn(), rootPass)); } } } - getApiRunner().getContext().put("sageFqdn", sageFqdn.get()); + getApiRunner().getContext().put("sageFqdn", sageFqdnAndRootPass.get().getKey()); + getApiRunner().getContext().put("sageRootPass", sageFqdnAndRootPass.get().getValue()); } @After public void saveTestInstance() throws Exception { testInstance.set(this); } @@ -49,10 +58,10 @@ public class LiveTestBase extends NetworkTestBase { @AfterClass public static void stopSage () throws Exception { final LiveTestBase liveTest = testInstance.get(); if (liveTest == null) { - log.warn("testInstance was never set, cannot stop sage: "+sageFqdn.get()); + log.warn("testInstance was never set, cannot stop sage: " + sageFqdnAndRootPass.get()); } else { if (liveTest.shouldStopSage()) { - final String fqdn = sageFqdn.get(); + final var fqdn = sageFqdnAndRootPass.get().getKey(); if (fqdn == null) { log.warn("stopSage: sage FQDN never got set"); } else { diff --git a/bubble-server/src/test/resources/models/include/add_approved_contact.json b/bubble-server/src/test/resources/models/include/add_approved_contact.json index 0a3952aa..c6d9b504 100644 --- a/bubble-server/src/test/resources/models/include/add_approved_contact.json +++ b/bubble-server/src/test/resources/models/include/add_approved_contact.json @@ -31,7 +31,7 @@ { "comment": "add <> contact for user <>", - "unless": "existingContact.getInfo() == '<>'", + "unless": "existingContact.getUuid() != null", "request": { "session": "<>", "uri": "users/<>/policy/contacts", @@ -47,7 +47,7 @@ { "comment": "resend verification message for <>/<> for user <>", - "onlyIf": "existingContact.getInfo() == '<>'", + "onlyIf": "existingContact.getUuid() != null", "request": { "session": "<>", "uri": "users/<>/policy/contacts/verify", diff --git a/bubble-server/src/test/resources/models/include/new_bubble.json b/bubble-server/src/test/resources/models/include/new_bubble.json index 2065b76a..2b121284 100644 --- a/bubble-server/src/test/resources/models/include/new_bubble.json +++ b/bubble-server/src/test/resources/models/include/new_bubble.json @@ -22,7 +22,8 @@ "region": "New Jersey", "bubbleConnectionVar": "bubbleConnection", "bubbleUserSessionVar": "bubbleUserSession", - "bubbleUserVar": "bubbleUserAccount" + "bubbleUserVar": "bubbleUserAccount", + "sendMetrics": null } }, @@ -94,8 +95,47 @@ }, { + "comment": "add email contact for the new user, if not already present", + "include": "add_approved_contact", + "params": { + "username": "<>", + "userSession": "<>", + "userConnection": "<>", + "rootSession": "rootSession", + "rootConnection": "<>", + "contactInfo": "<>", + "contactLookup": "<>", + "authFactor": "not_required" + } + }, + + { + "comment": "list all payment methods", + "request": { "uri": "me/paymentMethods?all=true" }, + "response": { "store": "paymentMethods" } + }, + + { + "comment": "add payment method for the user", + "onlyIf": "len(paymentMethods) == 0", + "before": "stripe_tokenize_card", + "request": { + "uri": "me/paymentMethods", + "method": "put", + "entity": { "paymentMethodType": "credit", "paymentInfo": "{{stripeToken}}" } + } + }, + + { + "comment": "list all payment methods again after creating one", + "onlyIf": "len(paymentMethods) == 0", + "request": { "uri": "me/paymentMethods?all=true" }, + "response": { "store": "paymentMethods", "check": [{ "condition": "len(json) == 1" }] } + }, + + { + "comment": "add plan, using the first found payment method for the new bubble", "before": "sleep 24s", - "comment": "add plan", "request": { "uri": "me/plans", "method": "put", @@ -105,12 +145,12 @@ "locale": "<>", "timezone": "<>", "plan": "<>", - "footprint": "<>" + "footprint": "<>", + "sendMetrics": <>, + "paymentMethodObject": { "uuid": "{{ paymentMethods.[0].uuid }}" } } }, - "response": { - "store": "plan" - } + "response": { "store": "plan" } }, { @@ -125,8 +165,8 @@ }, { - "before": "await_url me/networks/<>/dns/find?type=A&name=.<>.<> 40m 10s await_json.length > 0", "comment": "list DNS for the network, should now see a DNS A record for new instance", + "before": "await_url me/networks/<>/dns/find?type=A&name=.<>.<> 40m 10s await_json.length > 0", "request": { "uri": "me/networks/<>/dns/find?type=A&name=.<>.<>" }, @@ -139,8 +179,8 @@ }, { - "before": "await_url .bubble 40m 20s", "comment": "call API of deployed node, ensure it is running", + "before": "await_url .bubble 40m 20s", "connection": { "name": "<>", "baseUri": "https://{{<>.host}}.<>.<>:{{serverConfig.nginxPort}}/api" diff --git a/bubble-server/src/test/resources/models/tests/live/backup_and_restore.json b/bubble-server/src/test/resources/models/tests/live/backup_and_restore.json index 91e33d64..92cef50a 100644 --- a/bubble-server/src/test/resources/models/tests/live/backup_and_restore.json +++ b/bubble-server/src/test/resources/models/tests/live/backup_and_restore.json @@ -10,7 +10,7 @@ "uri": "auth/login", "entity": { "username": "root", - "password": "password1!" + "password": "{{sageRootPass}}" } }, "response": { @@ -20,19 +20,8 @@ } }, - { - "comment": "load root account policy", - "request": { - "uri": "users/root/policy" - }, - "response": { - "store": "rootPolicy" - } - }, - { "comment": "add root@example.com as email contact for root user, if not already present", - "onlyIf": "!rootPolicy.hasContact('root@example.com')", "include": "add_approved_contact", "params": { "username": "root", @@ -51,6 +40,7 @@ "include": "new_bubble", "params": { "sageFqdn": "{{sageFqdn}}", + "rootPassword": "{{sageRootPass}}", "username": "bubble-user", "password": "password1!", "userSessionVar": "userSession", @@ -58,13 +48,14 @@ "email": "bubble-user@example.com", "plan": "bubble", "networkVar": "bubbleNetwork", - "bubbleConnectionVar": "bubbleConnection" + "bubbleConnectionVar": "bubbleConnection", + "sendMetrics": true } }, { - "before": "await_url .bubble 40m 20s", "comment": "add file to storage", + "before": "await_url .bubble 40m 20s", "connection": { "name": "bubbleConnection" }, "request": { "session": "bubbleUserSession", diff --git a/bubble-server/src/test/resources/models/tests/live/fork_sage.json b/bubble-server/src/test/resources/models/tests/live/fork_sage.json index e748b723..0f597f36 100644 --- a/bubble-server/src/test/resources/models/tests/live/fork_sage.json +++ b/bubble-server/src/test/resources/models/tests/live/fork_sage.json @@ -23,7 +23,7 @@ "uri": "auth/login", "entity": { "name": "root", - "password": "password1!" + "password": "{{sageRootPass}}" } }, "response": {