diff options
7 files changed, 474 insertions, 20 deletions
diff --git a/profiling/org.eclipse.linuxtools.profiling.provider.tests/META-INF/MANIFEST.MF b/profiling/org.eclipse.linuxtools.profiling.provider.tests/META-INF/MANIFEST.MF index 88349a51a7..d1747786fa 100644 --- a/profiling/org.eclipse.linuxtools.profiling.provider.tests/META-INF/MANIFEST.MF +++ b/profiling/org.eclipse.linuxtools.profiling.provider.tests/META-INF/MANIFEST.MF @@ -6,7 +6,11 @@ Bundle-Version: 1.2.0.qualifier Bundle-RequiredExecutionEnvironment: J2SE-1.5 Fragment-Host: org.eclipse.linuxtools.profiling.launch Require-Bundle: org.junit;bundle-version="4.0.0", - org.eclipse.linuxtools.profiling.tests -Import-Package: org.eclipse.cdt.debug.core + org.eclipse.linuxtools.profiling.tests, + org.eclipse.swtbot.eclipse.finder;bundle-version="2.0.5", + org.eclipse.swtbot.forms.finder;bundle-version="2.0.5", + org.apache.log4j, + org.eclipse.cdt.managedbuilder.gnu.ui;bundle-version="8.0.0" Bundle-Localization: fragment Bundle-Vendor: %Bundle-Vendor +Import-Package: org.eclipse.swtbot.swt.finder.junit diff --git a/profiling/org.eclipse.linuxtools.profiling.provider.tests/fragment.xml b/profiling/org.eclipse.linuxtools.profiling.provider.tests/fragment.xml index 6663ead717..6675d9086a 100644 --- a/profiling/org.eclipse.linuxtools.profiling.provider.tests/fragment.xml +++ b/profiling/org.eclipse.linuxtools.profiling.provider.tests/fragment.xml @@ -7,7 +7,7 @@ <shortcut id="org.eclipse.linuxtools.profiling.stub" label="Profile As Stub" - modes="profile"> + modes="linuxtools"> <class class="org.eclipse.linuxtools.internal.profiling.launch.provider.launch.ProviderLaunchShortcut"> <parameter name="type" @@ -59,7 +59,7 @@ class="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchShortcut" id="org.eclipse.linuxtools.profiling.stubby" label="Profile As Stubby" - modes="profile"> + modes="linuxtools"> <contextualLaunch> <enablement> <with @@ -124,7 +124,7 @@ <launchConfigurationType delegate="org.eclipse.linuxtools.internal.profiling.launch.provider.launch.ProviderLaunchConfigurationDelegate" id="org.eclipse.linuxtools.profiling.stub.launchConfigurationType" - modes="profile" + modes="linuxtools" name="Profile As Stub" public="true" sourceLocatorId="org.eclipse.cdt.launch.DefaultSourceLocator"> @@ -132,26 +132,13 @@ <launchConfigurationType delegate="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchConfigurationDelegate" id="org.eclipse.linuxtools.profiling.stubby.launchConfigurationType" - modes="profile" + modes="linuxtools" name="Profile As Stubby" public="true" sourceLocatorId="org.eclipse.cdt.launch.DefaultSourceLocator"> </launchConfigurationType> </extension> <extension - point="org.eclipse.ui.preferencePages"> - <page - category="org.eclipse.linuxtools.profiling.provider.MainPreferencePage" - id="org.eclipse.linuxtools.profiling.snapshot.preferences" - name="Snapshot"> - <class class="org.eclipse.linuxtools.internal.profiling.launch.provider.AbstractProviderPreferencesPage"> - <parameter - name="type" - value="timing"/> - </class> - </page> - </extension> - <extension point="org.eclipse.linuxtools.profiling.launch.launchProvider"> <provider delegate="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchConfigurationDelegate" @@ -180,6 +167,39 @@ tabgroup="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchConfigurationTabGroup" type="stub"> </provider> + <provider + delegate="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyTimingLaunchConfigurationDelegate" + description="description test" + id="org.eclipse.linuxtools.profiling.provider.stubby.timing" + information="tooltip test" + name="Test Tool" + priority="1" + shortcut="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchShortcut" + tabgroup="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchConfigurationTabGroup" + type="timing"> + </provider> + <provider + delegate="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchConfigurationDelegate" + description="description test" + id="org.eclipse.linuxtools.profiling.provider.stubby.timing" + information="tooltip test" + name="Test Tool" + priority="1" + shortcut="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchShortcut" + tabgroup="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchConfigurationTabGroup" + type="memory"> + </provider> + <provider + delegate="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchConfigurationDelegate" + description="description test" + id="org.eclipse.linuxtools.profiling.provider.stubby.timing" + information="tooltip test" + name="Test Tool" + priority="1" + shortcut="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchShortcut" + tabgroup="org.eclipse.linuxtools.profiling.provider.tests.stubby.StubbyLaunchConfigurationTabGroup" + type="coverage"> + </provider> </extension> </fragment> diff --git a/profiling/org.eclipse.linuxtools.profiling.provider.tests/pom.xml b/profiling/org.eclipse.linuxtools.profiling.provider.tests/pom.xml index acc4a4efdb..04a78f5e58 100644 --- a/profiling/org.eclipse.linuxtools.profiling.provider.tests/pom.xml +++ b/profiling/org.eclipse.linuxtools.profiling.provider.tests/pom.xml @@ -23,4 +23,19 @@ <name>Linux Tools Profiling Provider Tests Plug-in</name> + <build> + <plugins> + <plugin> + <groupId>org.eclipse.tycho</groupId> + <artifactId>tycho-surefire-plugin</artifactId> + <version>${tycho-version}</version> + <configuration> + <useUIHarness>true</useUIHarness> + <useUIThread>false</useUIThread> + <product>org.eclipse.sdk.ide</product> + </configuration> + </plugin> + </plugins> +</build> + </project> diff --git a/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/AllTests.java b/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/AllTests.java index 8fdd2dfc2f..9793db8c68 100644 --- a/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/AllTests.java +++ b/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/AllTests.java @@ -15,7 +15,7 @@ import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses({LaunchTest.class, ExtensionPointTest.class}) +@SuiteClasses({LaunchTest.class, ExtensionPointTest.class, PreferencesTest.class}) public class AllTests { } diff --git a/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/ContextMenuHelper.java b/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/ContextMenuHelper.java new file mode 100644 index 0000000000..3bd68dbe2a --- /dev/null +++ b/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/ContextMenuHelper.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2012 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat initial API and implementation + * Adapted from http://www.eclipse.org/forums/index.php?t=msg&th=11863&start=2 + *******************************************************************************/ +package org.eclipse.linuxtools.profiling.provider.tests; + +import static org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory.withMnemonic; +import static org.hamcrest.core.AllOf.allOf; +import static org.hamcrest.core.IsInstanceOf.instanceOf; + +import java.util.Arrays; +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException; +import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; +import org.eclipse.swtbot.swt.finder.results.VoidResult; +import org.eclipse.swtbot.swt.finder.results.WidgetResult; +import org.eclipse.swtbot.swt.finder.widgets.AbstractSWTBot; +import org.hamcrest.Matcher; + +/** + * Adapted from http://www.eclipse.org/forums/index.php?t=msg&th=11863&start=2 + */ +public class ContextMenuHelper { + + /** + * Clicks the context menu matching the text. + * + * @param bot + * + * @param texts + * the text on the context menu. + * @throws WidgetNotFoundException + * if the widget is not found. + * @throws SWTException + * if the menu item is disabled (the root cause being an + * {@link IllegalStateException}) + */ + public static void clickContextMenu(final AbstractSWTBot<?> bot, + final String... texts) { + + // show + final MenuItem menuItem = UIThreadRunnable + .syncExec(new WidgetResult<MenuItem>() { + public MenuItem run() { + MenuItem theItem = getMenuItem(bot, texts); + if (theItem != null && !theItem.isEnabled()) + throw new IllegalStateException( + "Menu item is diabled"); + + return theItem; + } + }); + if (menuItem == null) { + throw new WidgetNotFoundException("Could not find menu: " + + Arrays.asList(texts)); + } + + // click + click(menuItem); + + // hide + UIThreadRunnable.syncExec(new VoidResult() { + public void run() { + if (menuItem.isDisposed()) + return; // menu already gone + hide(menuItem.getParent()); + } + }); + } + + @SuppressWarnings("unchecked") + private static MenuItem getMenuItem(final AbstractSWTBot<?> bot, + final String... texts) { + MenuItem theItem = null; + Control control = (Control) bot.widget; + // for dynamic menus, we need to issue this event + control.notifyListeners(SWT.MenuDetect, new Event()); + Menu menu = control.getMenu(); + for (String text : texts) { + // Use regex to ensure tests pass if items are reordered. + Matcher<?> matcher = allOf(instanceOf(MenuItem.class), + withMnemonic(text)); + theItem = show(menu, matcher); + if (theItem != null) { + menu = theItem.getMenu(); + } else { + hide(menu); + break; + } + } + return theItem; + } + + private static MenuItem show(final Menu menu, final Matcher<?> matcher) { + if (menu != null) { + menu.notifyListeners(SWT.Show, new Event()); + MenuItem[] items = menu.getItems(); + for (final MenuItem menuItem : items) { + if (matcher.matches(menuItem)) { + return menuItem; + } + } + menu.notifyListeners(SWT.Hide, new Event()); + } + return null; + } + + private static void click(final MenuItem menuItem) { + final Event event = new Event(); + event.time = (int) System.currentTimeMillis(); + event.widget = menuItem; + event.display = menuItem.getDisplay(); + event.type = SWT.Selection; + + UIThreadRunnable.asyncExec(menuItem.getDisplay(), new VoidResult() { + public void run() { + menuItem.notifyListeners(SWT.Selection, event); + } + }); + } + + private static void hide(final Menu menu) { + menu.notifyListeners(SWT.Hide, new Event()); + if (menu.getParentMenu() != null) { + hide(menu.getParentMenu()); + } + } +} diff --git a/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/PreferencesTest.java b/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/PreferencesTest.java new file mode 100644 index 0000000000..03fc51c3f0 --- /dev/null +++ b/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/PreferencesTest.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright (c) 2012 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat initial API and implementation. + *******************************************************************************/ +package org.eclipse.linuxtools.profiling.provider.tests; + +import static org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory.allOf; +import static org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory.widgetOfType; +import static org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory.withRegex; +import static org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory.withStyle; +import static org.eclipse.swtbot.swt.finder.waits.Conditions.shellCloses; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.linuxtools.internal.profiling.launch.provider.launch.ProviderFramework; +import org.eclipse.linuxtools.profiling.tests.AbstractTest; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Widget; +import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; +import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException; +import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; +import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; +import org.eclipse.swtbot.swt.finder.results.VoidResult; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotCheckBox; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotRadio; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; +import org.hamcrest.Matcher; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.osgi.framework.FrameworkUtil; + +@RunWith(SWTBotJunit4ClassRunner.class) +public class PreferencesTest extends AbstractTest{ + private static final String PROJ_NAME = "fibTest"; + private static final String STUB_TOOLTIP = "tooltip test"; + private static final String STUB_LABEL = "Test Tool [description test]"; + private static final String PROFILING_PREFS_CATEGORY = "Timing"; + private static final String PROFILING_PREFS_TYPE = "timing"; + private static final String[][] PROFILING_PREFS_INFO = { + { "Coverage", "coverage" }, { "Memory", "memory" },{ "Timing", "timing" } }; + + @BeforeClass + public static void setUpWorkbench() throws Exception { + // Set up is based from from GcovTest{c,CPP}. + + SWTWorkbenchBot bot = new SWTWorkbenchBot(); + try { + bot.viewByTitle("Welcome").close(); + // hide Subclipse Usage stats popup if present/installed + bot.shell("Subclipse Usage").activate(); + bot.button("Cancel").click(); + } catch (WidgetNotFoundException e) { + // ignore + } + + // Set C/C++ perspective. + bot.perspectiveByLabel("C/C++").activate(); + bot.sleep(500); + for (SWTBotShell sh : bot.shells()) { + if (sh.getText().startsWith("C/C++")) { + sh.activate(); + bot.sleep(500); + break; + } + } + + // Turn off automatic building by default to avoid timing issues + SWTBotMenu windowsMenu = bot.menu("Window"); + windowsMenu.menu("Preferences").click(); + SWTBotShell shell = bot.shell("Preferences"); + shell.activate(); + bot.tree().expandNode("General").select("Workspace"); + SWTBotCheckBox buildAuto = bot.checkBox("Build automatically"); + if (buildAuto != null && buildAuto.isChecked()) { + buildAuto.click(); + } + bot.sleep(1000); + bot.button("Apply").click(); + bot.button("OK").click(); + bot.waitUntil(shellCloses(shell)); + } + + @Test + public void testDefaultPreferences() throws Exception { + for (String[] preferenceInfo : PROFILING_PREFS_INFO) { + checkDefaultPreference(preferenceInfo[0], preferenceInfo[1]); + } + } + + @Test + public void testPreferencesPage() throws Exception { + SWTWorkbenchBot bot = new SWTWorkbenchBot(); + + // Set default tool for "timing" profiling. + checkDefaultPreference(PROFILING_PREFS_CATEGORY, PROFILING_PREFS_TYPE); + + // Open preferences shell. + SWTBotMenu windowsMenu = bot.menu("Window"); + windowsMenu.menu("Preferences").click(); + SWTBotShell shell = bot.shell("Preferences"); + shell.activate(); + + // Go to "Profiling Categories" preferences page. + SWTBotTreeItem treeItem = bot.tree().expandNode("C/C++").expandNode("Profiling Categories"); + assertNotNull(treeItem); + + // Select "Timing" category page. + treeItem.select(PROFILING_PREFS_CATEGORY); + + // Get name of default tool to deselect. + String defaultToolId = ProviderFramework.getProviderIdToRun(null, PROFILING_PREFS_TYPE); + String defaultToolName = ProviderFramework.getToolInformationFromId(defaultToolId , "name"); + + // Workaround for BZ #344484. + deselectSelectionByName(defaultToolName, bot); + + // Assert specified tool to select is what we expect and select it. + SWTBotRadio stubRadio = bot.radio(STUB_LABEL); + assertNotNull(stubRadio); + assertTrue(STUB_TOOLTIP.equals(stubRadio.getToolTipText())); + stubRadio.click(); + + bot.button("Apply").click(); + bot.button("OK").click(); + } + + @Test + public void testProfileProject() throws Exception { + SWTWorkbenchBot bot = new SWTWorkbenchBot(); + proj = createProjectAndBuild(FrameworkUtil.getBundle(this.getClass()), PROJ_NAME); + testPreferencesPage(); + + // Focus on project explorer view. + bot.viewByTitle("Project Explorer").bot(); + bot.activeShell(); + SWTBotTree treeBot = bot.tree(); + treeBot.setFocus(); + + // Select project binary. + // AbstractTest#createProjectAndBuild builds one executable binary under Binaries. + treeBot.expandNode(PROJ_NAME).expandNode("Binaries").getNode(0).select(); + + String menuItem = "Profiling Tools"; + String subMenuItem = "3 Profile Timing"; + + // Click on "Profiling Tools -> 3 Profiling Timing" context menu to execute shortcut. + ContextMenuHelper.clickContextMenu(treeBot, menuItem, subMenuItem); + + // Assert that the expected tool is running. + SWTBotShell profileShell = bot.shell("Successful profile launch").activate(); + assertNotNull(profileShell); + + bot.button("OK").click(); + bot.waitUntil(shellCloses(profileShell)); + + deleteProject(proj); + } + + private static void checkDefaultPreference(String preferenceCategory, String profilingType){ + SWTWorkbenchBot bot = new SWTWorkbenchBot(); + + // Open preferences shell. + SWTBotMenu windowsMenu = bot.menu("Window"); + windowsMenu.menu("Preferences").click(); + SWTBotShell shell = bot.shell("Preferences"); + shell.activate(); + + // Go to specified tree item in "Profiling Categories" preferences page. + SWTBotTreeItem treeItem = bot.tree().expandNode("C/C++").expandNode("Profiling Categories"); + assertNotNull(treeItem); + + treeItem.select(preferenceCategory); + + // Restore defaults. + bot.button("Restore Defaults").click(); + bot.button("Apply").click(); + + // Get information for default tool. + String defaultToolId = ProviderFramework.getProviderIdToRun(null, profilingType); + String defaultToolName = ProviderFramework.getToolInformationFromId(defaultToolId , "name"); + String defaultToolInfo = ProviderFramework.getToolInformationFromId(defaultToolId , "information"); + String defaultToolDescription = ProviderFramework.getToolInformationFromId(defaultToolId , "description"); + String defaultToolLabel = defaultToolName + " [" + defaultToolDescription + "]"; + + // Assert default radio is as expected. + SWTBotRadio defaultRadio = bot.radio(defaultToolLabel); + assertNotNull(defaultRadio); + assertTrue(defaultToolInfo.equals(defaultRadio.getToolTipText())); + + bot.button("Apply").click(); + bot.button("OK").click(); + } + + @Override + protected ILaunchConfigurationType getLaunchConfigType() { + return null; + } + + @Override + protected void setProfileAttributes(ILaunchConfigurationWorkingCopy wc) + throws CoreException { + } + + /** + * Deselect radio button with partial label name. + * + * Adapted workaround for BZ #344484: + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=344484#c1 + * + * @param name partial label of radio button to deselect. + */ + public static void deselectSelectionByName(final String name, final SWTWorkbenchBot bot) { + UIThreadRunnable.syncExec(new VoidResult() { + public void run() { + @SuppressWarnings("unchecked") + Matcher<Widget> matcher = allOf(widgetOfType(Button.class), + withStyle(SWT.RADIO, "SWT.RADIO"), + withRegex(name + ".*")); + + Button b = (Button) bot.widget(matcher); // the current selection + b.setSelection(false); + } + }); + } +}
\ No newline at end of file diff --git a/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/stubby/StubbyTimingLaunchConfigurationDelegate.java b/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/stubby/StubbyTimingLaunchConfigurationDelegate.java new file mode 100644 index 0000000000..a270f87c0b --- /dev/null +++ b/profiling/org.eclipse.linuxtools.profiling.provider.tests/src/org/eclipse/linuxtools/profiling/provider/tests/stubby/StubbyTimingLaunchConfigurationDelegate.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.profiling.provider.tests.stubby; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +public class StubbyTimingLaunchConfigurationDelegate extends + StubbyLaunchConfigurationDelegate { + + @Override + public void launch(ILaunchConfiguration configuration, String mode, + ILaunch launch, IProgressMonitor monitor) throws CoreException { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + IWorkbenchWindow window = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow(); + MessageDialog.openConfirm(window.getShell(), + "Successful profile launch", + "Successful profile launch"); + } + }); + } +} |