RUM-988 Implement the SR payloads update local_ci task#1598
Conversation
55213a6 to
7fe45a8
Compare
|
|
||
| Session Replay has a suite of functional tests which can be found in the `instrumentation:integration` module. | ||
| Those tests are assessing the recorded payload for a specific scenario against a given payload from `assets/session_replay_payloads` in the `androidTest` source set. | ||
| In case you need to update these payloads given a change in the SDK, you can run the following command: |
There was a problem hiding this comment.
| In case you need to update these payloads given a change in the SDK, you can run the following command: | |
| In case you need to update these payloads after a change in the SDK, you can run the following command: |
| register("srPayloadUpdate") { | ||
| id = "srPayloadUpdate" // the alias | ||
| implementationClass = "com.datadog.gradle.plugin.srpayloadupdate.SrPayloadUpdatePlugin" | ||
| } |
There was a problem hiding this comment.
minor: maybe for the clarity we shouldn't use sr and use sessionReplay instead in the names (for all classes and tasks). WDYT?
There was a problem hiding this comment.
yes, makes sense, was afraid they will be too long :)
| } | ||
|
|
||
| override fun exec() { | ||
| println("Executing command: ${commandLine.joinToString(" ")}") |
There was a problem hiding this comment.
should use Gradle logger here instead of println, this will allow to control the verbosity.
|
|
||
| import org.gradle.api.tasks.Exec | ||
|
|
||
| open class SrPayloadCreateTask : Exec() { |
There was a problem hiding this comment.
that's the request for a gradle task class
|
|
||
| init { | ||
| group = "datadog" | ||
| description = "Update the Session Replay integration tests payloads" |
There was a problem hiding this comment.
| description = "Update the Session Replay integration tests payloads" | |
| description = "Create the Session Replay integration tests payloads" |
| @@ -0,0 +1 @@ | |||
| [{"type":4,"data":{"width":411,"height":914}}, {"type":6,"data":{"has_focus":true}}, {"type":10,"data":{"wireframes":[{"width":411,"height":914,"shapeStyle":{"backgroundColor":"#303030ff","opacity":1.0},"type":"shape"},{"width":395,"height":19,"type":"text","text":"Default Text View","textStyle":{"family":"roboto, sans-serif","size":14,"color":"#a538afff"},"textPosition":{"padding":{"top":0,"bottom":0,"left":0,"right":0},"alignment":{"horizontal":"left","vertical":"top"}}},{"width":395,"height":19,"type":"text","text":"Material Text View","textStyle":{"family":"roboto, sans-serif","size":14,"color":"#cc0000ff"},"textPosition":{"padding":{"top":0,"bottom":0,"left":0,"right":0},"alignment":{"horizontal":"left","vertical":"top"}}},{"width":395,"height":19,"type":"text","text":"App Compat Text View","textStyle":{"family":"roboto, sans-serif","size":14,"color":"#ffbb33ff"},"textPosition":{"padding":{"top":0,"bottom":0,"left":0,"right":0},"alignment":{"horizontal":"left","vertical":"top"}}},{"width":395,"height":44,"type":"text","text":"***","textStyle":{"family":"roboto, sans-serif","size":17,"color":"#ffffffff"},"textPosition":{"padding":{"top":9,"bottom":11,"left":3,"right":3},"alignment":{"horizontal":"left","vertical":"center"}}},{"width":395,"height":1,"shapeStyle":{"backgroundColor":"#a538afff","opacity":1.0},"type":"shape"},{"width":395,"height":44,"type":"text","text":"***","textStyle":{"family":"roboto, sans-serif","size":17,"color":"#ffffffff"},"textPosition":{"padding":{"top":9,"bottom":11,"left":3,"right":3},"alignment":{"horizontal":"left","vertical":"center"}}},{"width":395,"height":1,"shapeStyle":{"backgroundColor":"#ffbb33ff","opacity":1.0},"type":"shape"},{"width":395,"height":44,"type":"text","text":"***","textStyle":{"family":"roboto, sans-serif","size":17,"color":"#ffffffff"},"textPosition":{"padding":{"top":9,"bottom":11,"left":3,"right":3},"alignment":{"horizontal":"left","vertical":"center"}}},{"width":395,"height":1,"shapeStyle":{"backgroundColor":"#ffbb33ff","opacity":1.0},"type":"shape"},{"width":395,"height":44,"type":"text","text":"***","textStyle":{"family":"roboto, sans-serif","size":17,"color":"#ffffffff"},"textPosition":{"padding":{"top":9,"bottom":11,"left":3,"right":3},"alignment":{"horizontal":"left","vertical":"center"}}},{"width":395,"height":1,"shapeStyle":{"backgroundColor":"#a538afff","opacity":1.0},"type":"shape"},{"width":395,"height":44,"type":"text","text":"***","textStyle":{"family":"roboto, sans-serif","size":17,"color":"#ffffffff"},"textPosition":{"padding":{"top":9,"bottom":11,"left":3,"right":3},"alignment":{"horizontal":"left","vertical":"center"}}},{"width":395,"height":1,"shapeStyle":{"backgroundColor":"#a538afff","opacity":1.0},"type":"shape"},{"width":395,"height":32,"type":"text","text":"Checked Text View","textStyle":{"family":"roboto, sans-serif","size":14,"color":"#ffffffff"},"textPosition":{"padding":{"top":0,"bottom":12,"left":0,"right":32},"alignment":{"horizontal":"left","vertical":"center"}}},{"width":19,"height":19,"border":{"color":"#ffffffff","width":1},"type":"shape"},{"width":395,"height":32,"type":"text","text":"App Compat Checked Text View","textStyle":{"family":"roboto, sans-serif","size":14,"color":"#ffffffff"},"textPosition":{"padding":{"top":0,"bottom":12,"left":0,"right":32},"alignment":{"horizontal":"left","vertical":"center"}}},{"width":19,"height":19,"border":{"color":"#ffffffff","width":1},"type":"shape"},{"width":411,"height":56,"type":"placeholder","label":"Toolbar"}]}}] No newline at end of file | |||
There was a problem hiding this comment.
when comparison fails, do we have a only the difference highlighted in the output or we have a full context as expected vs actual?
There was a problem hiding this comment.
it is using Json comparator from assertj , It will show you where it fails.
| payloadUpdateFile.writeText(payloadUpdateData) | ||
| } | ||
|
|
||
| private fun wasPayloadUpdateRequest(): Boolean { |
There was a problem hiding this comment.
| private fun wasPayloadUpdateRequest(): Boolean { | |
| private fun isPayloadUpdateRequest(): Boolean { |
| val records = handledRequests | ||
| .mapNotNull { it.extractSrSegmentAsJson()?.asJsonObject } | ||
| .flatMap { it.getAsJsonArray("records") } | ||
| .filter { it.asJsonObject.get("type").asString != "11" } |
There was a problem hiding this comment.
would be nice to add a comment explaining this line
| .flatMap { it.getAsJsonArray("records") } | ||
| .filter { it.asJsonObject.get("type").asString != "11" } | ||
| .map { it.dropInconsistentProperties() } | ||
| assertThat(records.size).isGreaterThan(2) |
There was a problem hiding this comment.
because I am taking 3 bellow so want to make sure I have where to take from...I could actually just take 3 and have the exception in case it doesn't have data yet but I rather like it better this way, more readable
| if (!payloadUpdateFile.exists()) { | ||
| payloadUpdateFile.createNewFile() | ||
| } | ||
| val payloadUpdateData = records.take(3).toString() |
Codecov Report
@@ Coverage Diff @@
## develop #1598 +/- ##
===========================================
- Coverage 83.67% 83.59% -0.08%
===========================================
Files 451 451
Lines 15563 15563
Branches 2318 2318
===========================================
- Hits 13021 13009 -12
- Misses 1928 1932 +4
- Partials 614 622 +8 |
jonathanmos
left a comment
There was a problem hiding this comment.
Nice pr! I've added only one minor suggestion
| protected fun runInstrumentationScenario() { | ||
| val instrumentation = InstrumentationRegistry.getInstrumentation() | ||
| instrumentation.waitForIdleSync() | ||
| // we need this to avoid the Bitrise flakiness and to force and to wait for |
There was a problem hiding this comment.
| // we need this to avoid the Bitrise flakiness and to force and to wait for | |
| // we need this to avoid Bitrise flakiness by requiring waiting for |
| register("srPayloadUpdate") { | ||
| id = "srPayloadUpdate" // the alias | ||
| implementationClass = "com.datadog.gradle.plugin.srpayloadupdate.SrPayloadUpdatePlugin" | ||
| } |
| init { | ||
| group = "datadog" | ||
| description = "Update the Session Replay integration tests payloads" | ||
| setCommandLine( |
There was a problem hiding this comment.
Is the plugin really just a proxy to a command line call? If so, maybe we can add an option in the local_ci.sh file instead and call the adb tool directly.
There was a problem hiding this comment.
hmmm not quite, I still need the dependency on the assemble, install gradle tasks and is much more readable this way. Maybe later I will also leverage the up - to - date property of the gradle task, for now I wanted to force it to always execute to see how it behaves but probably I will get back to it later and remove that force flag.
| import org.gradle.api.tasks.Input | ||
| import org.gradle.api.tasks.OutputDirectory | ||
|
|
||
| open class SrPayloadOverrideTask : Exec() { |
There was a problem hiding this comment.
Same here, this is just a command line proxy, maybe not necessary to create a plugin
There was a problem hiding this comment.
same answer as above, also I like that I can add the input path relative to the project. What would be the drawback for using the plugin ?
There was a problem hiding this comment.
Basically it's the overhead of using the command line to start gradle to launch a command line.
Right now everything you do in those task is using constants, which can still be done in the local_ci.sh file. You can still ensure that the assemble / install tasks are ran before calling adb.
I like that I can add the input path relative to the project
The input path is hardcoded, did you mean that you want to set it to use the module's package name instead? Is this comming in this PR or another one?
for now I wanted to force it to always execute
If the adb command is ran from local_ci, it would always execute as there would not be any cache for it.
There was a problem hiding this comment.
let me think about it and give it a try in shell
9dbdf79 to
372e8c0
Compare
372e8c0 to
dfb4d49
Compare
| TEST=1 | ||
| shift | ||
| ;; | ||
| -u | --updateSessionReplayPayload) |
There was a problem hiding this comment.
I wouldn't use -u for that and keep only long version of argument. -u is not quite self-descriptive and this task anyway is specific for the single module.
1d28667 to
ffe2e3d
Compare
ffe2e3d to
c70ce82
Compare
| companion object { | ||
| internal val INITIAL_WAIT_MS = TimeUnit.SECONDS.toMillis(60) | ||
| private const val UI_THREAD_DELAY_IN_MS = 1000L | ||
| private const val PAYLOAD_UPDATE_REQUEST = "updateSrPayloads" |
There was a problem hiding this comment.
can also name it updateSessionReplayPayloads. IMO having SessionReplay not shortened will simplify text search, because searching only for sr may give too much noise.
What does this PR do?
Session Replay has a suite of functional tests which can be found in the
instrumentation:integrationmodule.Those tests are assessing the recorded payload for a specific scenario against a given payload from
assets/session_replay_payloadsin theandroidTestsource set.In case you need to update these payloads given a change in the SDK we created this new gradle task to ease this process.
Motivation
What inspired you to submit this pull request?
Additional Notes
Anything else we should know when reviewing?
Review checklist (to be filled by reviewers)