Merge branch 'master' of git.bubblev.org:bubblev/bubble into kris/fix_backup_restore_test update lib Update lib Merge branch 'master' into kris/fix_backup_restore_test # Conflicts: # utils/cobbzilla-wizard Set sendMetrics where needed in test Move comment to be the first line in script parts Add payment method for when needed in the test Remove not needed duplicated check in the test Update lib Use proper conditions in test for existing contact Use proper method to get domain for test bubble Allow different then default root password in live tests Use single backups EP constant Co-authored-by: Jonathan Cobb <jonathan@kyuss.org> Co-authored-by: Kristijan Mitrovic <kmitrovic@itekako.com> Reviewed-on: #12tags/v0.10.5
@@ -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"; | |||
@@ -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 { | |||
@@ -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"); } | |||
} |
@@ -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<String> sageFqdn = new AtomicReference<>(); | |||
private static final AtomicReference<AbstractMap.SimpleEntry<String, String>> sageFqdnAndRootPass = | |||
new AtomicReference<>(); | |||
private static final AtomicReference<LiveTestBase> 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 { | |||
@@ -31,7 +31,7 @@ | |||
{ | |||
"comment": "add <<contactType>> contact for user <<username>>", | |||
"unless": "existingContact.getInfo() == '<<contactInfo>>'", | |||
"unless": "existingContact.getUuid() != null", | |||
"request": { | |||
"session": "<<userSession>>", | |||
"uri": "users/<<username>>/policy/contacts", | |||
@@ -47,7 +47,7 @@ | |||
{ | |||
"comment": "resend verification message for <<contactType>>/<<contactInfo>> for user <<username>>", | |||
"onlyIf": "existingContact.getInfo() == '<<contactInfo>>'", | |||
"onlyIf": "existingContact.getUuid() != null", | |||
"request": { | |||
"session": "<<userSession>>", | |||
"uri": "users/<<username>>/policy/contacts/verify", | |||
@@ -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": "<<username>>", | |||
"userSession": "<<userSessionVar>>", | |||
"userConnection": "<<sageConnectionVar>>", | |||
"rootSession": "rootSession", | |||
"rootConnection": "<<sageConnectionVar>>", | |||
"contactInfo": "<<email>>", | |||
"contactLookup": "<<email>>", | |||
"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": "<<locale>>", | |||
"timezone": "<<timezone>>", | |||
"plan": "<<plan>>", | |||
"footprint": "<<footprint>>" | |||
"footprint": "<<footprint>>", | |||
"sendMetrics": <<sendMetrics>>, | |||
"paymentMethodObject": { "uuid": "{{ paymentMethods.[0].uuid }}" } | |||
} | |||
}, | |||
"response": { | |||
"store": "plan" | |||
} | |||
"response": { "store": "plan" } | |||
}, | |||
{ | |||
@@ -125,8 +165,8 @@ | |||
}, | |||
{ | |||
"before": "await_url me/networks/<<network>>/dns/find?type=A&name=.<<network>>.<<domain>> 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/<<network>>/dns/find?type=A&name=.<<network>>.<<domain>> 40m 10s await_json.length > 0", | |||
"request": { | |||
"uri": "me/networks/<<network>>/dns/find?type=A&name=.<<network>>.<<domain>>" | |||
}, | |||
@@ -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": "<<bubbleConnectionVar>>", | |||
"baseUri": "https://{{<<networkVar>>.host}}.<<network>>.<<domain>>:{{serverConfig.nginxPort}}/api" | |||
@@ -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", | |||
@@ -23,7 +23,7 @@ | |||
"uri": "auth/login", | |||
"entity": { | |||
"name": "root", | |||
"password": "password1!" | |||
"password": "{{sageRootPass}}" | |||
} | |||
}, | |||
"response": { | |||