Skip to content

Commit 09d7817

Browse files
authored
Merge pull request #378 from Countly/staging
24.7.2
2 parents e6944d3 + 9669272 commit 09d7817

File tree

8 files changed

+181
-6
lines changed

8 files changed

+181
-6
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 24.7.2
2+
* Mitigated an issue in the upload plugin that prevented the upload of a symbol file
3+
14
## 24.7.1
25
* ! Minor breaking change ! Unsupported types for user properties will now be omitted, they won't be converted to strings.
36

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ org.gradle.configureondemand=true
2222
android.useAndroidX=true
2323
android.enableJetifier=true
2424
# RELEASE FIELD SECTION
25-
VERSION_NAME=24.7.1
25+
VERSION_NAME=24.7.2
2626
GROUP=ly.count.android
2727
POM_URL=https://github.com/Countly/countly-sdk-android
2828
POM_SCM_URL=https://github.com/Countly/countly-sdk-android
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package ly.count.android.sdk;
2+
3+
import androidx.test.ext.junit.runners.AndroidJUnit4;
4+
import java.util.concurrent.ExecutorService;
5+
import org.junit.After;
6+
import org.junit.Assert;
7+
import org.junit.Before;
8+
import org.junit.Test;
9+
import org.junit.runner.RunWith;
10+
import org.mockito.Mockito;
11+
12+
@RunWith(AndroidJUnit4.class)
13+
public class CountlyTimerTests {
14+
15+
private CountlyTimer countlyTimer;
16+
private ModuleLog mockLog;
17+
18+
@Before
19+
public void setUp() {
20+
countlyTimer = new CountlyTimer();
21+
mockLog = Mockito.mock(ModuleLog.class);
22+
CountlyTimer.TIMER_DELAY_MS = 0;
23+
}
24+
25+
@After
26+
public void tearDown() {
27+
countlyTimer.stopTimer(mockLog);
28+
Assert.assertNull(countlyTimer.timerService);
29+
}
30+
31+
@Test
32+
public void validateInitialValues() {
33+
Assert.assertNull(countlyTimer.timerService);
34+
Assert.assertEquals(0, CountlyTimer.TIMER_DELAY_MS);
35+
}
36+
37+
@Test
38+
public void startTimer_validDelay() {
39+
Runnable mockRunnable = Mockito.mock(Runnable.class);
40+
41+
countlyTimer.startTimer(1, mockRunnable, mockLog);
42+
Mockito.verify(mockLog).i("[CountlyTimer] startTimer, Starting timer timerDelay: [1000 ms]");
43+
}
44+
45+
@Test
46+
public void startTimer_invalidDelay() {
47+
Runnable mockRunnable = Mockito.mock(Runnable.class);
48+
49+
countlyTimer.startTimer(-1, mockRunnable, mockLog);
50+
Mockito.verify(mockLog).i("[CountlyTimer] startTimer, Starting timer timerDelay: [1000 ms]");
51+
}
52+
53+
@Test
54+
public void startTimer() {
55+
Runnable mockRunnable = Mockito.mock(Runnable.class);
56+
57+
countlyTimer.startTimer(99, mockRunnable, mockLog);
58+
Mockito.verify(mockLog).i("[CountlyTimer] startTimer, Starting timer timerDelay: [99000 ms]");
59+
}
60+
61+
@Test
62+
public void startTimer_withTimerDelayMS() {
63+
CountlyTimer.TIMER_DELAY_MS = 500;
64+
Runnable mockRunnable = Mockito.mock(Runnable.class);
65+
66+
countlyTimer.startTimer(1, mockRunnable, mockLog);
67+
Mockito.verify(mockLog).i("[CountlyTimer] startTimer, Starting timer timerDelay: [500 ms]");
68+
}
69+
70+
/**
71+
* Test that the timer is stopped when a new timer is started
72+
* This is to prevent multiple timers from running at the same time
73+
* And it is not reusing the previous timer
74+
*/
75+
@Test
76+
public void startTimer_reuseTimer() {
77+
countlyTimer.stopTimer(mockLog);
78+
79+
Assert.assertNull(countlyTimer.timerService);
80+
81+
Runnable mockRunnable = Mockito.mock(Runnable.class);
82+
countlyTimer.startTimer(1, mockRunnable, mockLog);
83+
84+
Assert.assertNotNull(countlyTimer.timerService);
85+
ExecutorService timerService = countlyTimer.timerService;
86+
87+
countlyTimer.startTimer(2, mockRunnable, mockLog);
88+
Assert.assertNotEquals(timerService, countlyTimer.timerService);
89+
}
90+
91+
@Test
92+
public void stopTimer() {
93+
countlyTimer.startTimer(1, Mockito.mock(Runnable.class), mockLog);
94+
countlyTimer.stopTimer(mockLog);
95+
Mockito.verify(mockLog).i("[CountlyTimer] stopTimer, Stopping timer");
96+
}
97+
98+
@Test
99+
public void stopTimer_nullTimer() {
100+
countlyTimer.stopTimer(mockLog);
101+
Mockito.verify(mockLog, Mockito.never()).i("[CountlyTimer] stopTimer, Stopping timer");
102+
Mockito.verify(mockLog).d("[CountlyTimer] stopTimer, Timer already stopped");
103+
}
104+
}

sdk/src/androidTest/java/ly/count/android/sdk/TestUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class TestUtils {
4242
public final static String commonAppKey = "appkey";
4343
public final static String commonDeviceId = "1234";
4444
public final static String SDK_NAME = "java-native-android";
45-
public final static String SDK_VERSION = "24.7.1";
45+
public final static String SDK_VERSION = "24.7.2";
4646
public static final int MAX_THREAD_COUNT_PER_STACK_TRACE = 50;
4747

4848
public static class Activity2 extends Activity {

sdk/src/main/java/ly/count/android/sdk/Countly.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ of this software and associated documentation files (the "Software"), to deal
4747
*/
4848
public class Countly {
4949

50-
private final String DEFAULT_COUNTLY_SDK_VERSION_STRING = "24.7.1";
50+
private final String DEFAULT_COUNTLY_SDK_VERSION_STRING = "24.7.2";
5151

5252
/**
5353
* Used as request meta data on every request
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package ly.count.android.sdk;
2+
3+
import androidx.annotation.NonNull;
4+
import java.util.concurrent.Executors;
5+
import java.util.concurrent.ScheduledExecutorService;
6+
import java.util.concurrent.TimeUnit;
7+
8+
class CountlyTimer {
9+
10+
ScheduledExecutorService timerService;
11+
protected static int TIMER_DELAY_MS = 0; // for testing purposes
12+
13+
protected void stopTimer(@NonNull ModuleLog L) {
14+
if (timerService != null) {
15+
L.i("[CountlyTimer] stopTimer, Stopping timer");
16+
try {
17+
timerService.shutdown();
18+
if (!timerService.awaitTermination(1, TimeUnit.SECONDS)) {
19+
timerService.shutdownNow();
20+
if (!timerService.awaitTermination(1, TimeUnit.SECONDS)) {
21+
L.e("[CountlyTimer] stopTimer, Global timer must be locked");
22+
}
23+
}
24+
} catch (Exception e) {
25+
L.e("[CountlyTimer] stopTimer, Error while stopping global timer " + e);
26+
}
27+
timerService = null;
28+
} else {
29+
L.d("[CountlyTimer] stopTimer, Timer already stopped");
30+
}
31+
}
32+
33+
protected void startTimer(long timerDelay, @NonNull Runnable runnable, @NonNull ModuleLog L) {
34+
long timerDelayInternal = timerDelay * 1000;
35+
36+
if (timerDelayInternal < UtilsTime.ONE_SECOND_IN_MS) {
37+
timerDelayInternal = UtilsTime.ONE_SECOND_IN_MS;
38+
}
39+
40+
if (TIMER_DELAY_MS > 0) {
41+
timerDelayInternal = TIMER_DELAY_MS;
42+
}
43+
44+
L.i("[CountlyTimer] startTimer, Starting timer timerDelay: [" + timerDelayInternal + " ms]");
45+
46+
if (timerService != null) {
47+
L.d("[CountlyTimer] startTimer, timer was running, stopping it");
48+
stopTimer(L);
49+
}
50+
51+
timerService = Executors.newSingleThreadScheduledExecutor();
52+
timerService.scheduleWithFixedDelay(runnable, 0, timerDelayInternal, TimeUnit.MILLISECONDS);
53+
}
54+
}

sdk/src/main/java/ly/count/android/sdk/UtilsTime.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.List;
77

88
public class UtilsTime {
9+
protected static int ONE_SECOND_IN_MS = 1000;
910

1011
public static class Instant {
1112
public final long timestampMs;

upload-plugin/src/main/groovy/ly/count/android/plugins/uploadSymbols.groovy

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ class UploadSymbolsPlugin implements Plugin<Project> {
3636
throw new StopExecutionException("Please specify your server in countly block.")
3737
}
3838
String buildVersion = project.android.defaultConfig.versionName
39-
String url = "${ext.server}/i/crash_symbols/upload_symbol"
39+
String url = ext.server;
40+
String path = "i/crash_symbols/upload_symbol";
41+
// Ensure there is exactly one "/" between the base URL and the path
42+
url = url.endsWith("/") ? url + path : url + "/" + path;
4043
def filePath = "$project.buildDir/$ext.mappingFile"
4144
logger.debug("uploadJavaSymbols, Version name:[ {} ], Upload symbol url:[ {} ], Mapping file path:[ {} ]", buildVersion, url, filePath)
4245
File file = new File(filePath)
@@ -55,17 +58,27 @@ class UploadSymbolsPlugin implements Plugin<Project> {
5558
.build()
5659
request = new Request.Builder().url(url).post(formBody).build()
5760
}
58-
logger.debug("uploadJavaSymbols, Generated request: {}", request.body().toString())
5961
doLast {
6062
if (request == null) {
6163
logger.error("Request not constructed")
6264
throw new StopActionException("Something happened while constructing the request. Please try again.")
6365
}
66+
67+
if (request.body() != null) {
68+
logger.debug("uploadJavaSymbols, Generated request: {}", request.body().toString())
69+
} else {
70+
logger.error("uploadJavaSymbols, Request body is null which should not be the case")
71+
}
72+
6473
client = new OkHttpClient()
6574
Response response = client.newCall(request).execute()
6675

6776
if (response.code() != 200) {
68-
logger.error("An error occurred while uploading the mapping file: {}", response.body().string())
77+
if (response.body() != null) {
78+
logger.error("An error occurred while uploading the mapping file: {}", response.body().string())
79+
} else {
80+
logger.error("An error occurred while uploading the mapping file, response body null")
81+
}
6982
} else {
7083
logger.debug("File upload successful")
7184
}

0 commit comments

Comments
 (0)