Skip to content

Conversation

@wzieba
Copy link
Member

@wzieba wzieba commented Nov 5, 2025

Closes: AINFRA-843: Address tech debt of Encrypted Logging library (v2)
Related: AINFRA-1365: Fix or remove file-based cache in Encrypted Logging

Motivation

Some clients experience "ApplicationNotResponding in EncryptedLogging" ANRs, and one of the ideas is that Volley initialization (especially its cache) might be a contributing factor.

In this PR, I change the heavy and legacy Volley HTTP library for a straightforward, Android-native HttpURLConnection.

Testing

Please see detailed instruction on: woocommerce/woocommerce-android#14917

Summary

Replace the legacy Volley library with Android native HttpURLConnection to eliminate external HTTP dependencies and avoid version conflicts with consuming applications.

Changes

Removed

  • Volley dependency (com.android.volley:volley:1.2.1)
  • EncryptedLogUploadRequest.kt (Volley-specific request class)
  • RequestQueue initialization from AutomatticEncryptedLogging

Benefits

Zero external HTTP dependencies - No version conflicts with consuming apps
Reduced library size - Removed ~1MB Volley dependency
Same API preserved - Coroutine-based interface unchanged
All error handling maintained - InvalidRequest, TooManyRequests, NoConnection, Unknown errors
Fully tested - 100% test coverage of HTTP client behavior

🤖 Generated with Claude Code

wzieba and others added 2 commits November 5, 2025 17:16
Replace the legacy Volley library with Android native HttpURLConnection
to eliminate external HTTP dependencies and avoid version conflicts with
consuming applications.

Changes:
- Created EncryptedLogHttpClient using HttpURLConnection
- Updated EncryptedLogRestClient to use new HTTP client with Dispatchers.IO
- Removed Volley dependency from build files
- Deleted EncryptedLogUploadRequest (Volley-specific)
- Removed RequestQueue initialization from AutomatticEncryptedLogging

Benefits:
- Zero external HTTP dependencies
- No version conflicts with consuming apps
- Reduced library size
- Same coroutine-based API maintained
- All error handling preserved

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive unit tests to verify EncryptedLogRestClient behavior
with the new HttpURLConnection implementation.

Changes:
- Added MockWebServer test dependency (okhttp3:mockwebserver:3.2.0)
- Created EncryptedLogRestClientTest with 7 test cases
- Made EncryptedLogHttpClient URL configurable for testing
- Tests verify correct request formatting, headers, and error handling

Test coverage:
- Request headers and body validation
- Success response (200)
- InvalidRequest error (400)
- TooManyRequests error (429)
- Unknown error responses (500)
- Non-JSON error responses
- Network connection failures (IOException)

All tests passing with Robolectric test runner.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Comment on lines 35 to 39
val json = try {
JSONObject(responseBody)
} catch (jsonException: JSONException) {
Log.e(TAG, "Received response not in JSON format: " + jsonException.message)
return UploadEncryptedLogError.Unknown(message = responseBody)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the response is some HTTP error that doesn't contain a JSON body? e.g. HTTP 500 or the like?
Don't we want to still report the actual statusCode that was the cause of the error in the returned UploadEncryptedLogError object, like you do in the return UploadEncryptedLogError.Unknown(statusCode, errorMessage) fallback from line R49?

Suggested change
val json = try {
JSONObject(responseBody)
} catch (jsonException: JSONException) {
Log.e(TAG, "Received response not in JSON format: " + jsonException.message)
return UploadEncryptedLogError.Unknown(message = responseBody)
val json = try {
JSONObject(responseBody)
} catch (jsonException: JSONException) {
Log.e(TAG, "Received response not in JSON format: " + jsonException.message)
return UploadEncryptedLogError.Unknown(statusCode, responseBody)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, good point - we should pass the statusCode 👍

When the server returns a non-JSON response (e.g., HTTP 500 with HTML),
the status code is now included in the UploadEncryptedLogError.Unknown
object for consistent error reporting and better debugging.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@wzieba
Copy link
Member Author

wzieba commented Nov 7, 2025

Just FYI @AliSoftware , I'll go ahead and merge this PR to release the fix sooner than later. I tested this change on Woo app and it all worked well 👍

@wzieba wzieba merged commit 1f4c593 into trunk Nov 7, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants