-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RUM-988 Implement the SR payloads update local_ci task #1598
RUM-988 Implement the SR payloads update local_ci task #1598
Conversation
55213a6
to
7fe45a8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice appoach!
CONTRIBUTING.md
Outdated
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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: |
buildSrc/build.gradle.kts
Outdated
register("srPayloadUpdate") { | ||
id = "srPayloadUpdate" // the alias | ||
implementationClass = "com.datadog.gradle.plugin.srpayloadupdate.SrPayloadUpdatePlugin" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should use Gradle logger
here instead of println
, this will allow to control the verbosity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah...good point
|
||
import org.gradle.api.tasks.Exec | ||
|
||
open class SrPayloadCreateTask : Exec() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this class should be open
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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"}]}}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also here, why 2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and here explaining why 3.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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 |
buildSrc/build.gradle.kts
Outdated
register("srPayloadUpdate") { | ||
id = "srPayloadUpdate" // the alias | ||
implementationClass = "com.datadog.gradle.plugin.srpayloadupdate.SrPayloadUpdatePlugin" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed
init { | ||
group = "datadog" | ||
description = "Update the Session Replay integration tests payloads" | ||
setCommandLine( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, this is just a command line proxy, maybe not necessary to create a plugin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me think about it and give it a try in shell
9dbdf79
to
372e8c0
Compare
372e8c0
to
dfb4d49
Compare
local_ci.sh
Outdated
@@ -30,6 +32,10 @@ while [[ $# -gt 0 ]]; do | |||
TEST=1 | |||
shift | |||
;; | |||
-u | --updateSessionReplayPayload) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah makes more sense
1d28667
to
ffe2e3d
Compare
ffe2e3d
to
c70ce82
Compare
@@ -172,9 +254,12 @@ internal abstract class SrTest<R : Activity, T : MockServerActivityTestRule<R>> | |||
|
|||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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:integration
module.Those tests are assessing the recorded payload for a specific scenario against a given payload from
assets/session_replay_payloads
in theandroidTest
source 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)