Skip to content

Commit 5bc91ac

Browse files
authored
Replace test-app with new demo app with simplified flow. (#69)
1 parent 5beb343 commit 5bc91ac

32 files changed

+1076
-462
lines changed

test-app/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Optimizely X Android SDK Demo App
2+
3+
This module houses the demo app used to demonstrate how to get started with the Android SDK. The app
4+
is also used to run integration tests on using the Android Espresso framework.
5+
6+
## Experiments Run
7+
8+
The experiments run in this demo app are part of the [email protected] account.
9+
10+
We run the following experiment:
11+
- Background change in second activity, which is loaded after the splash screen.
12+
13+
## How it works
14+
15+
The SDK is implemented in the following way:
16+
- The splash screen initializes the Optimizely manager asynchronously. This starts the datafile
17+
fetch.
18+
- Once the datafile is fetched and the Optimizely manager is started, we use grab the `optimizelyClient`
19+
from the manager and use it to activate the `background_experiment`. This buckets the user and sends
20+
an impression event.
21+
- We then use the bucketed variation to determine which activity to show. `VariationAActivity` for
22+
`variation_a` and `VariationBActivity` for `variation_b`.
23+
- Each of those activities include a `Test Conversion` button.
24+
- Clicking on that button will call `optimizelyClient.track()` and send a conversion event for the
25+
event named `sample_conversion`.
26+
- Then the application will navigate to the conversion page to confirm that a conversion event has
27+
been sent.
28+
29+
## Running the test app
30+
31+
Run `./gradlew test-app:connectedAndroidTest` to run the Espresso tests.
32+

test-app/src/androidTest/java/com/optimizely/ab/android/test_app/MainActivityEspressoTest.java

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
/*
2-
* Copyright 2016, Optimizely
3-
* <p/>
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
* <p/>
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
* <p/>
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
1+
/****************************************************************************
2+
* Copyright 2017, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
1616
package com.optimizely.ab.android.test_app;
1717

1818
import android.app.AlarmManager;
@@ -47,6 +47,7 @@
4747
import static android.support.test.espresso.Espresso.onView;
4848
import static android.support.test.espresso.action.ViewActions.click;
4949
import static android.support.test.espresso.assertion.ViewAssertions.matches;
50+
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
5051
import static android.support.test.espresso.matcher.ViewMatchers.withId;
5152
import static android.support.test.espresso.matcher.ViewMatchers.withText;
5253
import static junit.framework.Assert.assertFalse;
@@ -62,7 +63,7 @@ public class MainActivityEspressoTest {
6263
private ServiceScheduler serviceScheduler;
6364
private Intent dataFileServiceIntent, eventIntentService;
6465

65-
private ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class);
66+
private ActivityTestRule<SplashScreenActivity> activityTestRule = new ActivityTestRule<>(SplashScreenActivity.class);
6667
@Rule public TestRule chain = RuleChain
6768
.outerRule(new ExternalResource() {
6869
@Override
@@ -148,46 +149,32 @@ protected void after() {
148149
public void experimentActivationForWhitelistUser() throws InterruptedException {
149150
// Check that the text was changed.
150151
// These tests are pointed at a real project.
151-
// The user 'test_user` is in the whitelist for variation 1 for experiment 0 and experiment 1.
152-
onView(withId(R.id.button_1))
153-
.check(matches(withText(context.getString(R.string.main_act_button_1_text_var_1))));
152+
// The user 'test_user` is in the whitelist for variation_a for experiment background_experiment
153+
onView(withId(R.id.tv_variation_a_text_1))
154+
.check(matches(isDisplayed()));
154155

155156
// Espresso will wait for Optimizely to start due to the registered idling resources
156-
onView(withId(R.id.text_view_1))
157-
.check(matches(withText(context.getString(R.string.main_act_text_view_1_var_1))));
158-
159157
assertTrue(serviceScheduler.isScheduled(dataFileServiceIntent));
160158

161-
onView(withId(R.id.button_1)) // withId(R.id.my_view) is a ViewMatcher
162-
.perform(click()); // click() is a ViewAction
163-
164-
onView(withId(R.id.text_view_1))
165-
.check(matches(withText(context.getString(R.string.secondary_frag_text_view_1_var_1))));
166-
167-
onView(withId(R.id.button_1)) // withId(R.id.my_view) is a ViewMatcher
168-
.perform(click()); // click() is a ViewAction
159+
onView(withId(R.id.btn_variation_conversion)) // withId(R.id.my_view) is a ViewMatcher
160+
.perform(click()); // click() is a ViewAction
169161

170162
List<Pair<String, String>> events = CountingIdlingResourceManager.getEvents();
171-
assertTrue(events.size() == 6);
163+
assertTrue(events.size() == 2);
172164
Iterator<Pair<String, String>> iterator = events.iterator();
173165
while (iterator.hasNext()) {
174166
Pair<String, String> event = iterator.next();
175167
final String url = event.first;
176168
final String payload = event.second;
177-
if (url.equals("https://logx.optimizely.com/log/decision") && payload.contains("7676481120") && payload.contains("7661891902")
178-
|| url.equals("https://logx.optimizely.com/log/decision") && payload.contains("7651112186") && payload.contains("7674261140")
179-
|| url.equals("https://logx.optimizely.com/log/event") && payload.contains("experiment_0")
180-
|| url.equals("https://logx.optimizely.com/log/event") && payload.contains("experiment_1")
181-
|| url.equals("https://logx.optimizely.com/log/decision") && payload.contains("7680080715") && payload.contains("7685562539")
182-
|| url.equals("https://logx.optimizely.com/log/event") && payload.contains("experiment_2")) {
169+
if (url.equals("https://logx.optimizely.com/log/decision") && payload.contains("8126664113") && payload.contains("8146590584")
170+
|| url.equals("https://logx.optimizely.com/log/event") && payload.contains("sample_conversion")) {
183171
iterator.remove();
184172
}
185173
}
186174
assertTrue(events.isEmpty());
187175
MyApplication myApplication = (MyApplication) activityTestRule.getActivity().getApplication();
188176
UserProfile userProfile = myApplication.getOptimizelyManager().getUserProfile();
189177
// Being in the white list should override user profile
190-
assertNull(userProfile.lookup("test_user", "experiment_0"));
191-
assertNull(userProfile.lookup("test_user", "experiment_1"));
178+
assertNull(userProfile.lookup("test_user", "background_experiment"));
192179
}
193180
}

test-app/src/main/AndroidManifest.xml

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest package="com.optimizely.ab.android.test_app"
3-
xmlns:android="http://schemas.android.com/apk/res/android">
2+
<!--
3+
/****************************************************************************
4+
* Copyright 2017, Optimizely, Inc. and contributors *
5+
* *
6+
* Licensed under the Apache License, Version 2.0 (the "License"); *
7+
* you may not use this file except in compliance with the License. *
8+
* You may obtain a copy of the License at *
9+
* *
10+
* http://www.apache.org/licenses/LICENSE-2.0 *
11+
* *
12+
* Unless required by applicable law or agreed to in writing, software *
13+
* distributed under the License is distributed on an "AS IS" BASIS, *
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15+
* See the License for the specific language governing permissions and *
16+
* limitations under the License. *
17+
***************************************************************************/
18+
-->
19+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
20+
package="com.optimizely.ab.android.test_app">
421

5-
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
6-
<uses-permission android:name="android.permission.WAKE_LOCK"/>
22+
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
23+
<uses-permission android:name="android.permission.WAKE_LOCK" />
724

825
<application
926
android:name=".MyApplication"
@@ -12,22 +29,23 @@
1229
android:label="@string/app_name"
1330
android:supportsRtl="true"
1431
android:theme="@style/AppTheme">
15-
<activity android:name=".MainActivity">
32+
<service
33+
android:name=".NotificationService"
34+
android:exported="false" />
35+
36+
<activity
37+
android:name=".SplashScreenActivity"
38+
android:theme="@style/SplashTheme">
1639
<intent-filter>
17-
<action android:name="android.intent.action.MAIN"/>
40+
<action android:name="android.intent.action.MAIN" />
1841

19-
<category android:name="android.intent.category.LAUNCHER"/>
42+
<category android:name="android.intent.category.LAUNCHER" />
2043
</intent-filter>
2144
</activity>
22-
<activity
23-
android:name=".SecondaryActivity"
24-
android:parentActivityName=".MainActivity">
25-
</activity>
26-
27-
<service
28-
android:name=".NotificationService"
29-
android:exported="false">
30-
</service>
45+
<activity android:name=".VariationAActivity" />
46+
<activity android:name=".EventConfirmationActivity" />
47+
<activity android:name=".ActivationErrorActivity" />
48+
<activity android:name=".VariationBActivity"></activity>
3149
</application>
3250

3351
</manifest>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/****************************************************************************
2+
* Copyright 2017, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
package com.optimizely.ab.android.test_app;
17+
18+
import android.support.v7.app.AppCompatActivity;
19+
import android.os.Bundle;
20+
import android.view.View;
21+
import android.widget.Button;
22+
23+
public class ActivationErrorActivity extends AppCompatActivity {
24+
25+
@Override
26+
protected void onCreate(Bundle savedInstanceState) {
27+
super.onCreate(savedInstanceState);
28+
setContentView(R.layout.activity_activation_error);
29+
Button btnConversion = (Button)findViewById(R.id.btn_conversion_error_back);
30+
31+
btnConversion.setOnClickListener(new View.OnClickListener() {
32+
@Override
33+
public void onClick(View view) {
34+
onBackPressed();
35+
}
36+
});
37+
}
38+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/****************************************************************************
2+
* Copyright 2017, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package com.optimizely.ab.android.test_app;
18+
19+
import android.app.Fragment;
20+
import android.content.Intent;
21+
import android.os.Bundle;
22+
import android.support.annotation.Nullable;
23+
import android.view.LayoutInflater;
24+
import android.view.View;
25+
import android.view.ViewGroup;
26+
import android.widget.Button;
27+
28+
import com.optimizely.ab.android.sdk.OptimizelyClient;
29+
import com.optimizely.ab.android.sdk.OptimizelyManager;
30+
import com.optimizely.ab.android.shared.CountingIdlingResourceManager;
31+
32+
public class ConversionFragment extends Fragment {
33+
34+
Button conversionButton;
35+
36+
@Nullable
37+
@Override
38+
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
39+
return inflater.inflate(R.layout.fragment_conversion, container, false);
40+
}
41+
42+
@Override
43+
public void onViewCreated(View view, Bundle savedInstanceState) {
44+
conversionButton = (Button) view.findViewById(R.id.btn_variation_conversion);
45+
46+
final MyApplication myApplication = (MyApplication) getActivity().getApplication();
47+
final OptimizelyManager optimizelyManager = myApplication.getOptimizelyManager();
48+
49+
conversionButton.setOnClickListener(new View.OnClickListener() {
50+
@Override
51+
public void onClick(View view) {
52+
String userId = myApplication.getAnonUserId();
53+
54+
// This tracks a conversion event for the event named `sample_conversion`
55+
OptimizelyClient optimizely = optimizelyManager.getOptimizely();
56+
optimizely.track("sample_conversion", userId);
57+
58+
// Utility method for verifying event dispatches in our automated tests
59+
CountingIdlingResourceManager.increment(); // increment for conversion event
60+
61+
Intent intent = new Intent(myApplication.getBaseContext(), EventConfirmationActivity.class);
62+
startActivity(intent);
63+
}
64+
});
65+
}
66+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/****************************************************************************
2+
* Copyright 2017, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
package com.optimizely.ab.android.test_app;
17+
18+
import android.support.v7.app.AppCompatActivity;
19+
import android.os.Bundle;
20+
21+
public class EventConfirmationActivity extends AppCompatActivity {
22+
23+
@Override
24+
protected void onCreate(Bundle savedInstanceState) {
25+
super.onCreate(savedInstanceState);
26+
setContentView(R.layout.activity_event_confirmation);
27+
}
28+
}

0 commit comments

Comments
 (0)